Merge branch 'akpm' (Andrew's patch-bomb)
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Mar 2012 16:04:48 +0000 (09:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Mar 2012 16:04:48 +0000 (09:04 -0700)
Merge first batch of patches from Andrew Morton:
 "A few misc things and all the MM queue"

* emailed from Andrew Morton <akpm@linux-foundation.org>: (92 commits)
  memcg: avoid THP split in task migration
  thp: add HPAGE_PMD_* definitions for !CONFIG_TRANSPARENT_HUGEPAGE
  memcg: clean up existing move charge code
  mm/memcontrol.c: remove unnecessary 'break' in mem_cgroup_read()
  mm/memcontrol.c: remove redundant BUG_ON() in mem_cgroup_usage_unregister_event()
  mm/memcontrol.c: s/stealed/stolen/
  memcg: fix performance of mem_cgroup_begin_update_page_stat()
  memcg: remove PCG_FILE_MAPPED
  memcg: use new logic for page stat accounting
  memcg: remove PCG_MOVE_LOCK flag from page_cgroup
  memcg: simplify move_account() check
  memcg: remove EXPORT_SYMBOL(mem_cgroup_update_page_stat)
  memcg: kill dead prev_priority stubs
  memcg: remove PCG_CACHE page_cgroup flag
  memcg: let css_get_next() rely upon rcu_read_lock()
  cgroup: revert ss_id_lock to spinlock
  idr: make idr_get_next() good for rcu_read_lock()
  memcg: remove unnecessary thp check in page stat accounting
  memcg: remove redundant returns
  memcg: enum lru_list lru
  ...

703 files changed:
Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
Documentation/filesystems/debugfs.txt
Documentation/filesystems/porting
Documentation/filesystems/qnx6.txt [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt
Documentation/networking/dns_resolver.txt
Documentation/powerpc/firmware-assisted-dump.txt [new file with mode: 0644]
Documentation/powerpc/mpc52xx.txt
Documentation/powerpc/phyp-assisted-dump.txt [deleted file]
Documentation/security/00-INDEX
Documentation/security/Yama.txt [new file with mode: 0644]
Documentation/security/keys.txt
MAINTAINERS
arch/alpha/kernel/binfmt_loader.c
arch/arm/mach-tegra/fuse.c
arch/m68k/Kconfig
arch/m68k/include/asm/m5206sim.h
arch/m68k/include/asm/m520xsim.h
arch/m68k/include/asm/m523xsim.h
arch/m68k/include/asm/m5249sim.h
arch/m68k/include/asm/m5272sim.h
arch/m68k/include/asm/m527xsim.h
arch/m68k/include/asm/m528xsim.h
arch/m68k/include/asm/m5307sim.h
arch/m68k/include/asm/m532xsim.h
arch/m68k/include/asm/m5407sim.h
arch/m68k/include/asm/m54xxsim.h
arch/m68k/include/asm/machdep.h
arch/m68k/include/asm/mcfqspi.h
arch/m68k/include/asm/mcfuart.h
arch/m68k/kernel/process.c
arch/m68k/kernel/process_mm.c [deleted file]
arch/m68k/kernel/process_no.c [deleted file]
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/ptrace_mm.c [deleted file]
arch/m68k/kernel/ptrace_no.c [deleted file]
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/time.c
arch/m68k/kernel/time_mm.c [deleted file]
arch/m68k/kernel/time_no.c [deleted file]
arch/m68k/kernel/vmlinux-nommu.lds
arch/m68k/platform/5206/config.c
arch/m68k/platform/520x/config.c
arch/m68k/platform/523x/config.c
arch/m68k/platform/5249/config.c
arch/m68k/platform/5272/config.c
arch/m68k/platform/527x/config.c
arch/m68k/platform/528x/config.c
arch/m68k/platform/5307/config.c
arch/m68k/platform/532x/config.c
arch/m68k/platform/5407/config.c
arch/m68k/platform/54xx/config.c
arch/m68k/platform/68328/config.c
arch/m68k/platform/68328/ints.c
arch/m68k/platform/68328/timers.c
arch/m68k/platform/68360/config.c
arch/m68k/platform/68360/ints.c
arch/m68k/platform/68EZ328/config.c
arch/m68k/platform/68VZ328/config.c
arch/m68k/platform/coldfire/Makefile
arch/m68k/platform/coldfire/device.c [new file with mode: 0644]
arch/m68k/platform/coldfire/head.S
arch/m68k/platform/coldfire/pit.c
arch/m68k/platform/coldfire/reset.c [new file with mode: 0644]
arch/m68k/platform/coldfire/sltimers.c
arch/m68k/platform/coldfire/timers.c
arch/m68k/platform/coldfire/vectors.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/a4m072.dts [new file with mode: 0644]
arch/powerpc/boot/dts/bluestone.dts
arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
arch/powerpc/boot/dts/fsl/p3060si-post.dtsi
arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi
arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi
arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi
arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi
arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi
arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi
arch/powerpc/boot/dts/ge_imp3a.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc836x_mds.dts
arch/powerpc/boot/dts/mpc8536ds.dts
arch/powerpc/boot/dts/mpc8536ds.dtsi
arch/powerpc/boot/dts/mpc8536ds_36b.dts
arch/powerpc/boot/dts/mpc8548cds.dts [deleted file]
arch/powerpc/boot/dts/mpc8548cds.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8548cds_32b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8548cds_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8572ds.dtsi
arch/powerpc/boot/dts/p1010rdb.dtsi
arch/powerpc/boot/dts/p1020rdb-pc.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1020rdb-pc_32b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1020rdb-pc_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1021rdb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1021rdb.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1021rdb_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1022ds.dts [deleted file]
arch/powerpc/boot/dts/p1022ds.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1022ds_32b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1022ds_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1025rdb.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1025rdb_32b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1025rdb_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p2020rdb-pc.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p2020rdb-pc_32b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p2020rdb-pc_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p2020rdb.dts
arch/powerpc/boot/wrapper
arch/powerpc/configs/85xx/ge_imp3a_defconfig [new file with mode: 0644]
arch/powerpc/configs/86xx/gef_ppc9a_defconfig
arch/powerpc/configs/86xx/gef_sbc310_defconfig
arch/powerpc/configs/86xx/gef_sbc610_defconfig
arch/powerpc/configs/iseries_defconfig [deleted file]
arch/powerpc/configs/mpc5200_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/include/asm/abs_addr.h
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/dma.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/eeh_event.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/fadump.h [new file with mode: 0644]
arch/powerpc/include/asm/firmware.h
arch/powerpc/include/asm/fsl_guts.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/irqflags.h
arch/powerpc/include/asm/iseries/alpaca.h [deleted file]
arch/powerpc/include/asm/iseries/hv_call.h [deleted file]
arch/powerpc/include/asm/iseries/hv_call_event.h [deleted file]
arch/powerpc/include/asm/iseries/hv_call_sc.h [deleted file]
arch/powerpc/include/asm/iseries/hv_call_xm.h [deleted file]
arch/powerpc/include/asm/iseries/hv_lp_config.h [deleted file]
arch/powerpc/include/asm/iseries/hv_lp_event.h [deleted file]
arch/powerpc/include/asm/iseries/hv_types.h [deleted file]
arch/powerpc/include/asm/iseries/iommu.h [deleted file]
arch/powerpc/include/asm/iseries/it_lp_queue.h [deleted file]
arch/powerpc/include/asm/iseries/lpar_map.h [deleted file]
arch/powerpc/include/asm/iseries/mf.h [deleted file]
arch/powerpc/include/asm/iseries/vio.h [deleted file]
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/mpic_msgr.h [new file with mode: 0644]
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/phyp_dump.h [deleted file]
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/spinlock.h
arch/powerpc/include/asm/system.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/time.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dbell.c
arch/powerpc/kernel/e500-pmu.c [deleted file]
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fadump.c [new file with mode: 0644]
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_40x.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_8xx.S
arch/powerpc/kernel/head_booke.h
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/idle.c
arch/powerpc/kernel/idle_book3e.S
arch/powerpc/kernel/idle_power4.S
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/isa-bridge.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/misc.S
arch/powerpc/kernel/mpc7450-pmu.c [deleted file]
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/perf_callchain.c [deleted file]
arch/powerpc/kernel/perf_event.c [deleted file]
arch/powerpc/kernel/perf_event_fsl_emb.c [deleted file]
arch/powerpc/kernel/power4-pmu.c [deleted file]
arch/powerpc/kernel/power5+-pmu.c [deleted file]
arch/powerpc/kernel/power5-pmu.c [deleted file]
arch/powerpc/kernel/power6-pmu.c [deleted file]
arch/powerpc/kernel/power7-pmu.c [deleted file]
arch/powerpc/kernel/ppc970-pmu.c [deleted file]
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/signal.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/lib/locks.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/icswx.c
arch/powerpc/mm/icswx.h
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/slb_low.S
arch/powerpc/mm/stab.c
arch/powerpc/oprofile/common.c
arch/powerpc/perf/Makefile [new file with mode: 0644]
arch/powerpc/perf/callchain.c [new file with mode: 0644]
arch/powerpc/perf/core-book3s.c [new file with mode: 0644]
arch/powerpc/perf/core-fsl-emb.c [new file with mode: 0644]
arch/powerpc/perf/e500-pmu.c [new file with mode: 0644]
arch/powerpc/perf/mpc7450-pmu.c [new file with mode: 0644]
arch/powerpc/perf/power4-pmu.c [new file with mode: 0644]
arch/powerpc/perf/power5+-pmu.c [new file with mode: 0644]
arch/powerpc/perf/power5-pmu.c [new file with mode: 0644]
arch/powerpc/perf/power6-pmu.c [new file with mode: 0644]
arch/powerpc/perf/power7-pmu.c [new file with mode: 0644]
arch/powerpc/perf/ppc970-pmu.c [new file with mode: 0644]
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/currituck.c
arch/powerpc/platforms/44x/iss4xx.c
arch/powerpc/platforms/44x/ppc44x_simple.c
arch/powerpc/platforms/52xx/mpc5200_simple.c
arch/powerpc/platforms/52xx/mpc52xx_common.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/corenet_ds.c
arch/powerpc/platforms/85xx/ge_imp3a.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/ksi8560.c
arch/powerpc/platforms/85xx/mpc8536_ds.c
arch/powerpc/platforms/85xx/mpc85xx_ads.c
arch/powerpc/platforms/85xx/mpc85xx_cds.c
arch/powerpc/platforms/85xx/mpc85xx_ds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/mpc85xx_rdb.c
arch/powerpc/platforms/85xx/p1010rdb.c
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/85xx/p1023_rds.c
arch/powerpc/platforms/85xx/sbc8548.c
arch/powerpc/platforms/85xx/sbc8560.c
arch/powerpc/platforms/85xx/socrates.c
arch/powerpc/platforms/85xx/stx_gp3.c
arch/powerpc/platforms/85xx/tqm85xx.c
arch/powerpc/platforms/85xx/xes_mpc85xx.c
arch/powerpc/platforms/86xx/Kconfig
arch/powerpc/platforms/86xx/Makefile
arch/powerpc/platforms/86xx/gef_gpio.c [deleted file]
arch/powerpc/platforms/86xx/gef_pic.c [deleted file]
arch/powerpc/platforms/86xx/gef_pic.h [deleted file]
arch/powerpc/platforms/86xx/gef_ppc9a.c
arch/powerpc/platforms/86xx/gef_sbc310.c
arch/powerpc/platforms/86xx/gef_sbc610.c
arch/powerpc/platforms/86xx/pic.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Makefile
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/syscalls.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/embedded6xx/holly.c
arch/powerpc/platforms/embedded6xx/linkstation.c
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
arch/powerpc/platforms/embedded6xx/storcenter.c
arch/powerpc/platforms/iseries/Kconfig [deleted file]
arch/powerpc/platforms/iseries/Makefile [deleted file]
arch/powerpc/platforms/iseries/call_hpt.h [deleted file]
arch/powerpc/platforms/iseries/call_pci.h [deleted file]
arch/powerpc/platforms/iseries/call_sm.h [deleted file]
arch/powerpc/platforms/iseries/dt.c [deleted file]
arch/powerpc/platforms/iseries/exception.S [deleted file]
arch/powerpc/platforms/iseries/exception.h [deleted file]
arch/powerpc/platforms/iseries/htab.c [deleted file]
arch/powerpc/platforms/iseries/hvcall.S [deleted file]
arch/powerpc/platforms/iseries/hvlog.c [deleted file]
arch/powerpc/platforms/iseries/hvlpconfig.c [deleted file]
arch/powerpc/platforms/iseries/iommu.c [deleted file]
arch/powerpc/platforms/iseries/ipl_parms.h [deleted file]
arch/powerpc/platforms/iseries/irq.c [deleted file]
arch/powerpc/platforms/iseries/irq.h [deleted file]
arch/powerpc/platforms/iseries/it_exp_vpd_panel.h [deleted file]
arch/powerpc/platforms/iseries/it_lp_naca.h [deleted file]
arch/powerpc/platforms/iseries/ksyms.c [deleted file]
arch/powerpc/platforms/iseries/lpardata.c [deleted file]
arch/powerpc/platforms/iseries/lpevents.c [deleted file]
arch/powerpc/platforms/iseries/main_store.h [deleted file]
arch/powerpc/platforms/iseries/mf.c [deleted file]
arch/powerpc/platforms/iseries/misc.S [deleted file]
arch/powerpc/platforms/iseries/naca.h [deleted file]
arch/powerpc/platforms/iseries/pci.c [deleted file]
arch/powerpc/platforms/iseries/pci.h [deleted file]
arch/powerpc/platforms/iseries/proc.c [deleted file]
arch/powerpc/platforms/iseries/processor_vpd.h [deleted file]
arch/powerpc/platforms/iseries/release_data.h [deleted file]
arch/powerpc/platforms/iseries/setup.c [deleted file]
arch/powerpc/platforms/iseries/setup.h [deleted file]
arch/powerpc/platforms/iseries/smp.c [deleted file]
arch/powerpc/platforms/iseries/spcomm_area.h [deleted file]
arch/powerpc/platforms/iseries/vio.c [deleted file]
arch/powerpc/platforms/iseries/viopath.c [deleted file]
arch/powerpc/platforms/iseries/vpd_areas.h [deleted file]
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/nvram.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_cache.c
arch/powerpc/platforms/pseries/eeh_dev.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/eeh_event.c
arch/powerpc/platforms/pseries/eeh_pseries.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/eeh_sysfs.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/msi.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/phyp_dump.c [deleted file]
arch/powerpc/platforms/pseries/processor_idle.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/Kconfig
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/fsl_85xx_cache_sram.c
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/fsl_rmu.c
arch/powerpc/sysdev/ge/Makefile [new file with mode: 0644]
arch/powerpc/sysdev/ge/ge_pic.c [new file with mode: 0644]
arch/powerpc/sysdev/ge/ge_pic.h [new file with mode: 0644]
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic_msgr.c [new file with mode: 0644]
arch/powerpc/sysdev/mpic_msi.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/powerpc/xmon/xmon.c
arch/s390/hypfs/inode.c
arch/um/include/asm/mmu.h
arch/um/include/asm/mmu_context.h
arch/um/kernel/skas/mmu.c
arch/x86/crypto/Makefile
arch/x86/crypto/blowfish_glue.c
arch/x86/crypto/camellia-x86_64-asm_64.S [new file with mode: 0644]
arch/x86/crypto/camellia_glue.c [new file with mode: 0644]
arch/x86/crypto/serpent-sse2-i586-asm_32.S
arch/x86/crypto/serpent-sse2-x86_64-asm_64.S
arch/x86/crypto/serpent_sse2_glue.c
arch/x86/crypto/twofish_glue.c
arch/x86/crypto/twofish_glue_3way.c
arch/x86/ia32/ia32_aout.c
crypto/Kconfig
crypto/Makefile
crypto/algapi.c
crypto/camellia.c [deleted file]
crypto/camellia_generic.c [new file with mode: 0644]
crypto/crypto_user.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
drivers/base/driver.c
drivers/block/viodasd.c [deleted file]
drivers/cdrom/viocd.c [deleted file]
drivers/char/hw_random/tx4939-rng.c
drivers/char/tpm/Kconfig
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_tis.c
drivers/char/viotape.c [deleted file]
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/ctrl.c
drivers/crypto/geode-aes.c
drivers/crypto/hifn_795x.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/mv_cesa.c
drivers/crypto/n2_core.c
drivers/crypto/omap-aes.c
drivers/crypto/omap-sham.c
drivers/crypto/picoxcell_crypto.c
drivers/crypto/s5p-sss.c
drivers/crypto/talitos.c
drivers/crypto/tegra-aes.c [new file with mode: 0644]
drivers/crypto/tegra-aes.h [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-ge.c [new file with mode: 0644]
drivers/misc/carma/carma-fpga.c
drivers/misc/ibmasm/ibmasmfs.c
drivers/misc/ibmasm/module.c
drivers/mmc/card/block.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/fsl_ifc_nand.c [new file with mode: 0644]
drivers/net/ethernet/brocade/bna/bnad_debugfs.c
drivers/net/macvtap.c
drivers/oprofile/oprofilefs.c
drivers/scsi/Kconfig
drivers/scsi/ibmvscsi/Makefile
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/iseries_vscsi.c [deleted file]
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/tty/hvc/Kconfig
drivers/tty/hvc/Makefile
drivers/tty/hvc/hvc_iseries.c [deleted file]
drivers/tty/hvc/hvc_udbg.c
drivers/tty/hvc/hvc_vio.c
drivers/tty/serial/Kconfig
drivers/usb/core/inode.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/inode.c
drivers/watchdog/Kconfig
fs/9p/v9fs.c
fs/9p/vfs_super.c
fs/Kconfig
fs/Makefile
fs/adfs/super.c
fs/affs/super.c
fs/afs/super.c
fs/aio.c
fs/anon_inodes.c
fs/autofs4/init.c
fs/autofs4/inode.c
fs/befs/linuxvfs.c
fs/bfs/inode.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_em86.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/binfmt_script.c
fs/binfmt_som.c
fs/btrfs/super.c
fs/cachefiles/namei.c
fs/ceph/super.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/coda/inode.c
fs/configfs/configfs_internal.h
fs/configfs/dir.c
fs/configfs/inode.c
fs/configfs/mount.c
fs/configfs/symlink.c
fs/cramfs/inode.c
fs/dcache.c
fs/debugfs/file.c
fs/devpts/inode.c
fs/dlm/dir.c
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lowcomms.c
fs/ecryptfs/file.c
fs/ecryptfs/main.c
fs/ecryptfs/super.c
fs/efs/super.c
fs/exec.c
fs/exofs/namei.c
fs/exofs/super.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext3/super.c
fs/ext4/super.c
fs/fat/inode.c
fs/file_table.c
fs/freevxfs/vxfs_super.c
fs/fs_struct.c
fs/fuse/inode.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/lock_dlm.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/trace_gfs2.h
fs/gfs2/util.c
fs/gfs2/util.h
fs/gfs2/xattr.c
fs/hfs/super.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hfsplus/super.c
fs/hostfs/hostfs_kern.c
fs/hpfs/super.c
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/isofs/inode.c
fs/jffs2/fs.c
fs/jfs/namei.c
fs/jfs/super.c
fs/libfs.c
fs/logfs/dir.c
fs/logfs/super.c
fs/minix/inode.c
fs/minix/minix.h
fs/minix/namei.c
fs/namei.c
fs/ncpfs/inode.c
fs/nfs/client.c
fs/nfs/getroot.c
fs/nfs/idmap.c
fs/nfsd/fault_inject.c
fs/nfsd/vfs.c
fs/nilfs2/namei.c
fs/nilfs2/super.c
fs/ntfs/super.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/super.c
fs/omfs/inode.c
fs/openpromfs/inode.c
fs/proc/inode.c
fs/proc/proc_sysctl.c
fs/proc/vmcore.c
fs/pstore/inode.c
fs/qnx4/inode.c
fs/qnx4/namei.c
fs/qnx4/qnx4.h
fs/qnx6/Kconfig [new file with mode: 0644]
fs/qnx6/Makefile [new file with mode: 0644]
fs/qnx6/README [new file with mode: 0644]
fs/qnx6/dir.c [new file with mode: 0644]
fs/qnx6/inode.c [new file with mode: 0644]
fs/qnx6/namei.c [new file with mode: 0644]
fs/qnx6/qnx6.h [new file with mode: 0644]
fs/qnx6/super_mmi.c [new file with mode: 0644]
fs/quota/dquot.c
fs/ramfs/inode.c
fs/reiserfs/acl.h [new file with mode: 0644]
fs/reiserfs/bitmap.c
fs/reiserfs/dir.c
fs/reiserfs/do_balan.c
fs/reiserfs/file.c
fs/reiserfs/fix_node.c
fs/reiserfs/hashes.c
fs/reiserfs/ibalance.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/item_ops.c
fs/reiserfs/journal.c
fs/reiserfs/lbalance.c
fs/reiserfs/lock.c
fs/reiserfs/namei.c
fs/reiserfs/objectid.c
fs/reiserfs/prints.c
fs/reiserfs/procfs.c
fs/reiserfs/reiserfs.h [new file with mode: 0644]
fs/reiserfs/resize.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/reiserfs/tail_conversion.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr.h [new file with mode: 0644]
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/romfs/super.c
fs/squashfs/super.c
fs/stat.c
fs/super.c
fs/sysfs/mount.c
fs/sysv/namei.c
fs/sysv/super.c
fs/sysv/sysv.h
fs/ubifs/super.c
fs/udf/namei.c
fs/udf/super.c
fs/ufs/namei.c
fs/ufs/super.c
fs/xfs/xfs_rename.c
fs/xfs/xfs_super.c
fs/xfs/xfs_utils.c
fs/xfs/xfs_vnodeops.c
include/linux/atomic.h
include/linux/audit.h
include/linux/binfmts.h
include/linux/crypto.h
include/linux/dcache.h
include/linux/debugfs.h
include/linux/device.h
include/linux/file.h
include/linux/fs.h
include/linux/gfs2_ondisk.h
include/linux/key.h
include/linux/magic.h
include/linux/mm.h
include/linux/of.h
include/linux/padata.h
include/linux/pci.h
include/linux/prctl.h
include/linux/qnx6_fs.h [new file with mode: 0644]
include/linux/reiserfs_acl.h [deleted file]
include/linux/reiserfs_fs.h
include/linux/reiserfs_fs_i.h [deleted file]
include/linux/reiserfs_fs_sb.h [deleted file]
include/linux/reiserfs_xattr.h
include/linux/security.h
include/linux/trace_seq.h
include/net/af_unix.h
include/net/sock.h
init/do_mounts_rd.c
ipc/mqueue.c
ipc/msgutil.c
kernel/audit.c
kernel/cgroup.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/padata.c
kernel/sched/core.c
kernel/sysctl.c
kernel/trace/trace_output.c
mm/memory.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/shmem.c
mm/swapfile.c
net/dns_resolver/dns_key.c
net/sunrpc/rpc_pipe.c
net/unix/af_unix.c
net/unix/diag.c
security/Kconfig
security/Makefile
security/apparmor/Makefile
security/apparmor/apparmorfs.c
security/apparmor/audit.c
security/apparmor/domain.c
security/apparmor/file.c
security/apparmor/include/apparmor.h
security/apparmor/include/apparmorfs.h
security/apparmor/include/audit.h
security/apparmor/include/file.h
security/apparmor/include/match.h
security/apparmor/include/path.h
security/apparmor/include/policy.h
security/apparmor/include/resource.h
security/apparmor/match.c
security/apparmor/path.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c
security/apparmor/resource.c
security/capability.c
security/commoncap.c
security/integrity/ima/Kconfig
security/integrity/ima/ima_audit.c
security/integrity/ima/ima_policy.c
security/keys/keyctl.c
security/keys/process_keys.c
security/lsm_audit.c
security/security.c
security/selinux/hooks.c
security/smack/smack_lsm.c
security/tomoyo/audit.c
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/mount.c
security/tomoyo/securityfs_if.c
security/yama/Kconfig [new file with mode: 0644]
security/yama/Makefile [new file with mode: 0644]
security/yama/yama_lsm.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt
new file mode 100644 (file)
index 0000000..bc8ded6
--- /dev/null
@@ -0,0 +1,63 @@
+* FSL MPIC Message Registers
+
+This binding specifies what properties must be available in the device tree
+representation of the message register blocks found in some FSL MPIC
+implementations.
+
+Required properties:
+
+    - compatible: Specifies the compatibility list for the message register
+      block.  The type shall be <string-list> and the value shall be of the form
+      "fsl,mpic-v<version>-msgr", where <version> is the version number of
+      the MPIC containing the message registers.
+
+    - reg: Specifies the base physical address(s) and size(s) of the
+      message register block's addressable register space.  The type shall be
+      <prop-encoded-array>.
+
+    - interrupts: Specifies a list of interrupt-specifiers which are available
+      for receiving interrupts. Interrupt-specifier consists of two cells: first
+      cell is interrupt-number and second cell is level-sense. The type shall be
+      <prop-encoded-array>.
+
+Optional properties:
+
+    - mpic-msgr-receive-mask: Specifies what registers in the containing block
+      are allowed to receive interrupts. The value is a bit mask where a set
+      bit at bit 'n' indicates that message register 'n' can receive interrupts.
+      Note that "bit 'n'" is numbered from LSB for PPC hardware. The type shall
+      be <u32>. If not present, then all of the message registers in the block
+      are available.
+
+Aliases:
+
+    An alias should be created for every message register block.  They are not
+    required, though.  However, a particular implementation of this binding
+    may require aliases to be present.  Aliases are of the form
+    'mpic-msgr-block<n>', where <n> is an integer specifying the block's number.
+    Numbers shall start at 0.
+
+Example:
+
+       aliases {
+               mpic-msgr-block0 = &mpic_msgr_block0;
+               mpic-msgr-block1 = &mpic_msgr_block1;
+       };
+
+       mpic_msgr_block0: mpic-msgr-block@41400 {
+               compatible = "fsl,mpic-v3.1-msgr";
+               reg = <0x41400 0x200>;
+               // Message registers 0 and 2 in this block can receive interrupts on
+               // sources 0xb0 and 0xb2, respectively.
+               interrupts = <0xb0 2 0xb2 2>;
+               mpic-msgr-receive-mask = <0x5>;
+       };
+
+       mpic_msgr_block1: mpic-msgr-block@42400 {
+               compatible = "fsl,mpic-v3.1-msgr";
+               reg = <0x42400 0x200>;
+               // Message registers 0 and 2 in this block can receive interrupts on
+               // sources 0xb4 and 0xb6, respectively.
+               interrupts = <0xb4 2 0xb6 2>;
+               mpic-msgr-receive-mask = <0x5>;
+       };
index 2cf38bd..dc57446 100644 (file)
@@ -56,7 +56,27 @@ PROPERTIES
           to the client.  The presence of this property also mandates
           that any initialization related to interrupt sources shall
           be limited to sources explicitly referenced in the device tree.
-       
+
+  - big-endian
+      Usage: optional
+      Value type: <empty>
+          If present the MPIC will be assumed to be big-endian.  Some
+          device-trees omit this property on MPIC nodes even when the MPIC is
+          in fact big-endian, so certain boards override this property.
+
+  - single-cpu-affinity
+      Usage: optional
+      Value type: <empty>
+          If present the MPIC will be assumed to only be able to route
+          non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC).
+
+  - last-interrupt-source
+      Usage: optional
+      Value type: <u32>
+          Some MPICs do not correctly report the number of hardware sources
+          in the global feature registers.  If specified, this field will
+          override the value read from MPIC_GREG_FEATURE_LAST_SRC.
+
 INTERRUPT SPECIFIER DEFINITION
 
   Interrupt specifiers consists of 4 cells encoded as
index 5d586e1..5693877 100644 (file)
@@ -6,8 +6,10 @@ Required properties:
   etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
   the parent type.
 
-- reg : should contain the address and the length of the shared message
-  interrupt register set.
+- reg : It may contain one or two regions. The first region should contain
+  the address and the length of the shared message interrupt register set.
+  The second region should contain the address of aliased MSIIR register for
+  platforms that have such an alias.
 
 - msi-available-ranges: use <start count> style section to define which
   msi interrupt can be used in the 256 msi interrupts. This property is
index 4e25758..7a34f82 100644 (file)
@@ -136,7 +136,7 @@ file.
        void __iomem *base;
     };
 
-    struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+    struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
                                     struct dentry *parent,
                                     struct debugfs_regset32 *regset);
 
index b4a3d76..74acd96 100644 (file)
@@ -429,3 +429,9 @@ filemap_write_and_wait_range() so that all dirty pages are synced out properly.
 You must also keep in mind that ->fsync() is not called with i_mutex held
 anymore, so if you require i_mutex locking you must make sure to take it and
 release it yourself.
+
+--
+[mandatory]
+       d_alloc_root() is gone, along with a lot of bugs caused by code
+misusing it.  Replacement: d_make_root(inode).  The difference is,
+d_make_root() drops the reference to inode if dentry allocation fails.  
diff --git a/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt
new file mode 100644 (file)
index 0000000..050223e
--- /dev/null
@@ -0,0 +1,174 @@
+The QNX6 Filesystem
+===================
+
+The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino)
+It got introduced in QNX 6.4.0 and is used default since 6.4.1.
+
+Option
+======
+
+mmi_fs         Mount filesystem as used for example by Audi MMI 3G system
+
+Specification
+=============
+
+qnx6fs shares many properties with traditional Unix filesystems. It has the
+concepts of blocks, inodes and directories.
+On QNX it is possible to create little endian and big endian qnx6 filesystems.
+This feature makes it possible to create and use a different endianness fs
+for the target (QNX is used on quite a range of embedded systems) plattform
+running on a different endianess.
+The Linux driver handles endianness transparently. (LE and BE)
+
+Blocks
+------
+
+The space in the device or file is split up into blocks. These are a fixed
+size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
+created.
+Blockpointers are 32bit, so the maximum space that can be adressed is
+2^32 * 4096 bytes or 16TB
+
+The superblocks
+---------------
+
+The superblock contains all global information about the filesystem.
+Each qnx6fs got two superblocks, each one having a 64bit serial number.
+That serial number is used to identify the "active" superblock.
+In write mode with reach new snapshot (after each synchronous write), the
+serial of the new master superblock is increased (old superblock serial + 1)
+
+So basically the snapshot functionality is realized by an atomic final
+update of the serial number. Before updating that serial, all modifications
+are done by copying all modified blocks during that specific write request
+(or period) and building up a new (stable) filesystem structure under the
+inactive superblock.
+
+Each superblock holds a set of root inodes for the different filesystem
+parts. (Inode, Bitmap and Longfilenames)
+Each of these root nodes holds information like total size of the stored
+data and the adressing levels in that specific tree.
+If the level value is 0, up to 16 direct blocks can be adressed by each
+node.
+Level 1 adds an additional indirect adressing level where each indirect
+adressing block holds up to blocksize / 4 bytes pointers to data blocks.
+Level 2 adds an additional indirect adressig block level (so, already up
+to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a
+
+Unused block pointers are always set to ~0 - regardless of root node,
+indirect adressing blocks or inodes.
+Data leaves are always on the lowest level. So no data is stored on upper
+tree levels.
+
+The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
+The Audi MMI 3G first superblock directly starts at byte 0.
+Second superblock position can either be calculated from the superblock
+information (total number of filesystem blocks) or by taking the highest
+device address, zeroing the last 3 bytes and then substracting 0x1000 from
+that address.
+
+0x1000 is the size reserved for each superblock - regardless of the
+blocksize of the filesystem.
+
+Inodes
+------
+
+Each object in the filesystem is represented by an inode. (index node)
+The inode structure contains pointers to the filesystem blocks which contain
+the data held in the object and all of the metadata about an object except
+its longname. (filenames longer than 27 characters)
+The metadata about an object includes the permissions, owner, group, flags,
+size, number of blocks used, access time, change time and modification time.
+
+Object mode field is POSIX format. (which makes things easier)
+
+There are also pointers to the first 16 blocks, if the object data can be
+adressed with 16 direct blocks.
+For more than 16 blocks an indirect adressing in form of another tree is
+used. (scheme is the same as the one used for the superblock root nodes)
+
+The filesize is stored 64bit. Inode counting starts with 1. (whilst long
+filename inodes start with 0)
+
+Directories
+-----------
+
+A directory is a filesystem object and has an inode just like a file.
+It is a specially formatted file containing records which associate each
+name with an inode number.
+'.' inode number points to the directory inode
+'..' inode number points to the parent directory inode
+Eeach filename record additionally got a filename length field.
+
+One special case are long filenames or subdirectory names.
+These got set a filename length field of 0xff in the corresponding directory
+record plus the longfile inode number also stored in that record.
+With that longfilename inode number, the longfilename tree can be walked
+starting with the superblock longfilename root node pointers.
+
+Special files
+-------------
+
+Symbolic links are also filesystem objects with inodes. They got a specific
+bit in the inode mode field identifying them as symbolic link.
+The directory entry file inode pointer points to the target file inode.
+
+Hard links got an inode, a directory entry, but a specific mode bit set,
+no block pointers and the directory file record pointing to the target file
+inode.
+
+Character and block special devices do not exist in QNX as those files
+are handled by the QNX kernel/drivers and created in /dev independant of the
+underlaying filesystem.
+
+Long filenames
+--------------
+
+Long filenames are stored in a seperate adressing tree. The staring point
+is the longfilename root node in the active superblock.
+Each data block (tree leaves) holds one long filename. That filename is
+limited to 510 bytes. The first two starting bytes are used as length field
+for the actual filename.
+If that structure shall fit for all allowed blocksizes, it is clear why there
+is a limit of 510 bytes for the actual filename stored.
+
+Bitmap
+------
+
+The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap
+root node in the superblock and each bit in the bitmap represents one
+filesystem block.
+The first block is block 0, which starts 0x1000 after superblock start.
+So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical
+address at which block 0 is located.
+
+Bits at the end of the last bitmap block are set to 1, if the device is
+smaller than addressing space in the bitmap.
+
+Bitmap system area
+------------------
+
+The bitmap itself is devided into three parts.
+First the system area, that is split into two halfs.
+Then userspace.
+
+The requirement for a static, fixed preallocated system area comes from how
+qnx6fs deals with writes.
+Each superblock got it's own half of the system area. So superblock #1
+always uses blocks from the lower half whilst superblock #2 just writes to
+blocks represented by the upper half bitmap system area bits.
+
+Bitmap blocks, Inode blocks and indirect addressing blocks for those two
+tree structures are treated as system blocks.
+
+The rational behind that is that a write request can work on a new snapshot
+(system area of the inactive - resp. lower serial numbered superblock) while
+at the same time there is still a complete stable filesystem structer in the
+other half of the system area.
+
+When finished with writing (a sync write is completed, the maximum sync leap
+time or a filesystem sync is requested), serial of the previously inactive
+superblock atomically is increased and the fs switches over to that - then
+stable declared - superblock.
+
+For all data outside the system area, blocks are just copied while writing.
index 68fbfb6..3b7488f 100644 (file)
@@ -218,6 +218,7 @@ Code  Seq#(hex)     Include File            Comments
 'h'    00-7F                           conflict! Charon filesystem
                                        <mailto:zapman@interlan.net>
 'h'    00-1F   linux/hpet.h            conflict!
+'h'    80-8F   fs/hfsplus/ioctl.c
 'i'    00-3F   linux/i2o-dev.h         conflict!
 'i'    0B-1F   linux/ipmi.h            conflict!
 'i'    80-8F   linux/i8k.h
index 7f531ad..d86adcd 100644 (file)
@@ -102,6 +102,10 @@ implemented in the module can be called after doing:
      If _expiry is non-NULL, the expiry time (TTL) of the result will be
      returned also.
 
+The kernel maintains an internal keyring in which it caches looked up keys.
+This can be cleared by any process that has the CAP_SYS_ADMIN capability by
+the use of KEYCTL_KEYRING_CLEAR on the keyring ID.
+
 
 ===============================
 READING DNS KEYS FROM USERSPACE
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
new file mode 100644 (file)
index 0000000..3007bc9
--- /dev/null
@@ -0,0 +1,270 @@
+
+                   Firmware-Assisted Dump
+                   ------------------------
+                       July 2011
+
+The goal of firmware-assisted dump is to enable the dump of
+a crashed system, and to do so from a fully-reset system, and
+to minimize the total elapsed time until the system is back
+in production use.
+
+- Firmware assisted dump (fadump) infrastructure is intended to replace
+  the existing phyp assisted dump.
+- Fadump uses the same firmware interfaces and memory reservation model
+  as phyp assisted dump.
+- Unlike phyp dump, fadump exports the memory dump through /proc/vmcore
+  in the ELF format in the same way as kdump. This helps us reuse the
+  kdump infrastructure for dump capture and filtering.
+- Unlike phyp dump, userspace tool does not need to refer any sysfs
+  interface while reading /proc/vmcore.
+- Unlike phyp dump, fadump allows user to release all the memory reserved
+  for dump, with a single operation of echo 1 > /sys/kernel/fadump_release_mem.
+- Once enabled through kernel boot parameter, fadump can be
+  started/stopped through /sys/kernel/fadump_registered interface (see
+  sysfs files section below) and can be easily integrated with kdump
+  service start/stop init scripts.
+
+Comparing with kdump or other strategies, firmware-assisted
+dump offers several strong, practical advantages:
+
+-- Unlike kdump, the system has been reset, and loaded
+   with a fresh copy of the kernel.  In particular,
+   PCI and I/O devices have been reinitialized and are
+   in a clean, consistent state.
+-- Once the dump is copied out, the memory that held the dump
+   is immediately available to the running kernel. And therefore,
+   unlike kdump, fadump doesn't need a 2nd reboot to get back
+   the system to the production configuration.
+
+The above can only be accomplished by coordination with,
+and assistance from the Power firmware. The procedure is
+as follows:
+
+-- The first kernel registers the sections of memory with the
+   Power firmware for dump preservation during OS initialization.
+   These registered sections of memory are reserved by the first
+   kernel during early boot.
+
+-- When a system crashes, the Power firmware will save
+   the low memory (boot memory of size larger of 5% of system RAM
+   or 256MB) of RAM to the previous registered region. It will
+   also save system registers, and hardware PTE's.
+
+   NOTE: The term 'boot memory' means size of the low memory chunk
+         that is required for a kernel to boot successfully when
+         booted with restricted memory. By default, the boot memory
+         size will be the larger of 5% of system RAM or 256MB.
+         Alternatively, user can also specify boot memory size
+         through boot parameter 'fadump_reserve_mem=' which will
+         override the default calculated size. Use this option
+         if default boot memory size is not sufficient for second
+         kernel to boot successfully.
+
+-- After the low memory (boot memory) area has been saved, the
+   firmware will reset PCI and other hardware state.  It will
+   *not* clear the RAM. It will then launch the bootloader, as
+   normal.
+
+-- The freshly booted kernel will notice that there is a new
+   node (ibm,dump-kernel) in the device tree, indicating that
+   there is crash data available from a previous boot. During
+   the early boot OS will reserve rest of the memory above
+   boot memory size effectively booting with restricted memory
+   size. This will make sure that the second kernel will not
+   touch any of the dump memory area.
+
+-- User-space tools will read /proc/vmcore to obtain the contents
+   of memory, which holds the previous crashed kernel dump in ELF
+   format. The userspace tools may copy this info to disk, or
+   network, nas, san, iscsi, etc. as desired.
+
+-- Once the userspace tool is done saving dump, it will echo
+   '1' to /sys/kernel/fadump_release_mem to release the reserved
+   memory back to general use, except the memory required for
+   next firmware-assisted dump registration.
+
+   e.g.
+     # echo 1 > /sys/kernel/fadump_release_mem
+
+Please note that the firmware-assisted dump feature
+is only available on Power6 and above systems with recent
+firmware versions.
+
+Implementation details:
+----------------------
+
+During boot, a check is made to see if firmware supports
+this feature on that particular machine. If it does, then
+we check to see if an active dump is waiting for us. If yes
+then everything but boot memory size of RAM is reserved during
+early boot (See Fig. 2). This area is released once we finish
+collecting the dump from user land scripts (e.g. kdump scripts)
+that are run. If there is dump data, then the
+/sys/kernel/fadump_release_mem file is created, and the reserved
+memory is held.
+
+If there is no waiting dump data, then only the memory required
+to hold CPU state, HPTE region, boot memory dump and elfcore
+header, is reserved at the top of memory (see Fig. 1). This area
+is *not* released: this region will be kept permanently reserved,
+so that it can act as a receptacle for a copy of the boot memory
+content in addition to CPU state and HPTE region, in the case a
+crash does occur.
+
+  o Memory Reservation during first kernel
+
+  Low memory                                        Top of memory
+  0      boot memory size                                       |
+  |           |                       |<--Reserved dump area -->|
+  V           V                       |   Permanent Reservation V
+  +-----------+----------/ /----------+---+----+-----------+----+
+  |           |                       |CPU|HPTE|  DUMP     |ELF |
+  +-----------+----------/ /----------+---+----+-----------+----+
+        |                                           ^
+        |                                           |
+        \                                           /
+         -------------------------------------------
+          Boot memory content gets transferred to
+          reserved area by firmware at the time of
+          crash
+                   Fig. 1
+
+  o Memory Reservation during second kernel after crash
+
+  Low memory                                        Top of memory
+  0      boot memory size                                       |
+  |           |<------------- Reserved dump area ----------- -->|
+  V           V                                                 V
+  +-----------+----------/ /----------+---+----+-----------+----+
+  |           |                       |CPU|HPTE|  DUMP     |ELF |
+  +-----------+----------/ /----------+---+----+-----------+----+
+        |                                                    |
+        V                                                    V
+   Used by second                                    /proc/vmcore
+   kernel to boot
+                   Fig. 2
+
+Currently the dump will be copied from /proc/vmcore to a
+a new file upon user intervention. The dump data available through
+/proc/vmcore will be in ELF format. Hence the existing kdump
+infrastructure (kdump scripts) to save the dump works fine with
+minor modifications.
+
+The tools to examine the dump will be same as the ones
+used for kdump.
+
+How to enable firmware-assisted dump (fadump):
+-------------------------------------
+
+1. Set config option CONFIG_FA_DUMP=y and build kernel.
+2. Boot into linux kernel with 'fadump=on' kernel cmdline option.
+3. Optionally, user can also set 'fadump_reserve_mem=' kernel cmdline
+   to specify size of the memory to reserve for boot memory dump
+   preservation.
+
+NOTE: If firmware-assisted dump fails to reserve memory then it will
+   fallback to existing kdump mechanism if 'crashkernel=' option
+   is set at kernel cmdline.
+
+Sysfs/debugfs files:
+------------
+
+Firmware-assisted dump feature uses sysfs file system to hold
+the control files and debugfs file to display memory reserved region.
+
+Here is the list of files under kernel sysfs:
+
+ /sys/kernel/fadump_enabled
+
+    This is used to display the fadump status.
+    0 = fadump is disabled
+    1 = fadump is enabled
+
+    This interface can be used by kdump init scripts to identify if
+    fadump is enabled in the kernel and act accordingly.
+
+ /sys/kernel/fadump_registered
+
+    This is used to display the fadump registration status as well
+    as to control (start/stop) the fadump registration.
+    0 = fadump is not registered.
+    1 = fadump is registered and ready to handle system crash.
+
+    To register fadump echo 1 > /sys/kernel/fadump_registered and
+    echo 0 > /sys/kernel/fadump_registered for un-register and stop the
+    fadump. Once the fadump is un-registered, the system crash will not
+    be handled and vmcore will not be captured. This interface can be
+    easily integrated with kdump service start/stop.
+
+ /sys/kernel/fadump_release_mem
+
+    This file is available only when fadump is active during
+    second kernel. This is used to release the reserved memory
+    region that are held for saving crash dump. To release the
+    reserved memory echo 1 to it:
+
+    echo 1  > /sys/kernel/fadump_release_mem
+
+    After echo 1, the content of the /sys/kernel/debug/powerpc/fadump_region
+    file will change to reflect the new memory reservations.
+
+    The existing userspace tools (kdump infrastructure) can be easily
+    enhanced to use this interface to release the memory reserved for
+    dump and continue without 2nd reboot.
+
+Here is the list of files under powerpc debugfs:
+(Assuming debugfs is mounted on /sys/kernel/debug directory.)
+
+ /sys/kernel/debug/powerpc/fadump_region
+
+    This file shows the reserved memory regions if fadump is
+    enabled otherwise this file is empty. The output format
+    is:
+    <region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size>
+
+    e.g.
+    Contents when fadump is registered during first kernel
+
+    # cat /sys/kernel/debug/powerpc/fadump_region
+    CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0
+    HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0
+    DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0
+
+    Contents when fadump is active during second kernel
+
+    # cat /sys/kernel/debug/powerpc/fadump_region
+    CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020
+    HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000
+    DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000
+        : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000
+
+NOTE: Please refer to Documentation/filesystems/debugfs.txt on
+      how to mount the debugfs filesystem.
+
+
+TODO:
+-----
+ o Need to come up with the better approach to find out more
+   accurate boot memory size that is required for a kernel to
+   boot successfully when booted with restricted memory.
+ o The fadump implementation introduces a fadump crash info structure
+   in the scratch area before the ELF core header. The idea of introducing
+   this structure is to pass some important crash info data to the second
+   kernel which will help second kernel to populate ELF core header with
+   correct data before it gets exported through /proc/vmcore. The current
+   design implementation does not address a possibility of introducing
+   additional fields (in future) to this structure without affecting
+   compatibility. Need to come up with the better approach to address this.
+   The possible approaches are:
+       1. Introduce version field for version tracking, bump up the version
+       whenever a new field is added to the structure in future. The version
+       field can be used to find out what fields are valid for the current
+       version of the structure.
+       2. Reserve the area of predefined size (say PAGE_SIZE) for this
+       structure and have unused area as reserved (initialized to zero)
+       for future field additions.
+   The advantage of approach 1 over 2 is we don't need to reserve extra space.
+---
+Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+This document is based on the original documentation written for phyp
+assisted dump by Linas Vepstas and Manish Ahuja.
index 10dd4ab..0d540a3 100644 (file)
@@ -2,7 +2,7 @@ Linux 2.6.x on MPC52xx family
 -----------------------------
 
 For the latest info, go to http://www.246tNt.com/mpc52xx/
+
 To compile/use :
 
   - U-Boot:
@@ -10,23 +10,23 @@ To compile/use :
         if you wish to ).
      # make lite5200_defconfig
      # make uImage
-    
+
      then, on U-boot:
      => tftpboot 200000 uImage
      => tftpboot 400000 pRamdisk
      => bootm 200000 400000
-    
+
   - DBug:
      # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION
         if you wish to ).
      # make lite5200_defconfig
      # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz
-     # make zImage.initrd 
-     # make 
+     # make zImage.initrd
+     # make
 
      then in DBug:
      DBug> dn -i zImage.initrd.lite5200
-     
+
 
 Some remarks :
  - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100
diff --git a/Documentation/powerpc/phyp-assisted-dump.txt b/Documentation/powerpc/phyp-assisted-dump.txt
deleted file mode 100644 (file)
index ad34020..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-
-                   Hypervisor-Assisted Dump
-                   ------------------------
-                       November 2007
-
-The goal of hypervisor-assisted dump is to enable the dump of
-a crashed system, and to do so from a fully-reset system, and
-to minimize the total elapsed time until the system is back
-in production use.
-
-As compared to kdump or other strategies, hypervisor-assisted
-dump offers several strong, practical advantages:
-
--- Unlike kdump, the system has been reset, and loaded
-   with a fresh copy of the kernel.  In particular,
-   PCI and I/O devices have been reinitialized and are
-   in a clean, consistent state.
--- As the dump is performed, the dumped memory becomes
-   immediately available to the system for normal use.
--- After the dump is completed, no further reboots are
-   required; the system will be fully usable, and running
-   in its normal, production mode on its normal kernel.
-
-The above can only be accomplished by coordination with,
-and assistance from the hypervisor. The procedure is
-as follows:
-
--- When a system crashes, the hypervisor will save
-   the low 256MB of RAM to a previously registered
-   save region. It will also save system state, system
-   registers, and hardware PTE's.
-
--- After the low 256MB area has been saved, the
-   hypervisor will reset PCI and other hardware state.
-   It will *not* clear RAM. It will then launch the
-   bootloader, as normal.
-
--- The freshly booted kernel will notice that there
-   is a new node (ibm,dump-kernel) in the device tree,
-   indicating that there is crash data available from
-   a previous boot. It will boot into only 256MB of RAM,
-   reserving the rest of system memory.
-
--- Userspace tools will parse /sys/kernel/release_region
-   and read /proc/vmcore to obtain the contents of memory,
-   which holds the previous crashed kernel. The userspace
-   tools may copy this info to disk, or network, nas, san,
-   iscsi, etc. as desired.
-
-   For Example: the values in /sys/kernel/release-region
-   would look something like this (address-range pairs).
-   CPU:0x177fee000-0x10000: HPTE:0x177ffe020-0x1000: /
-   DUMP:0x177fff020-0x10000000, 0x10000000-0x16F1D370A
-
--- As the userspace tools complete saving a portion of
-   dump, they echo an offset and size to
-   /sys/kernel/release_region to release the reserved
-   memory back to general use.
-
-   An example of this is:
-     "echo 0x40000000 0x10000000 > /sys/kernel/release_region"
-   which will release 256MB at the 1GB boundary.
-
-Please note that the hypervisor-assisted dump feature
-is only available on Power6-based systems with recent
-firmware versions.
-
-Implementation details:
-----------------------
-
-During boot, a check is made to see if firmware supports
-this feature on this particular machine. If it does, then
-we check to see if a active dump is waiting for us. If yes
-then everything but 256 MB of RAM is reserved during early
-boot. This area is released once we collect a dump from user
-land scripts that are run. If there is dump data, then
-the /sys/kernel/release_region file is created, and
-the reserved memory is held.
-
-If there is no waiting dump data, then only the highest
-256MB of the ram is reserved as a scratch area. This area
-is *not* released: this region will be kept permanently
-reserved, so that it can act as a receptacle for a copy
-of the low 256MB in the case a crash does occur. See,
-however, "open issues" below, as to whether
-such a reserved region is really needed.
-
-Currently the dump will be copied from /proc/vmcore to a
-a new file upon user intervention. The starting address
-to be read and the range for each data point in provided
-in /sys/kernel/release_region.
-
-The tools to examine the dump will be same as the ones
-used for kdump.
-
-General notes:
---------------
-Security: please note that there are potential security issues
-with any sort of dump mechanism. In particular, plaintext
-(unencrypted) data, and possibly passwords, may be present in
-the dump data. Userspace tools must take adequate precautions to
-preserve security.
-
-Open issues/ToDo:
-------------
- o The various code paths that tell the hypervisor that a crash
-   occurred, vs. it simply being a normal reboot, should be
-   reviewed, and possibly clarified/fixed.
-
- o Instead of using /sys/kernel, should there be a /sys/dump
-   instead? There is a dump_subsys being created by the s390 code,
-   perhaps the pseries code should use a similar layout as well.
-
- o Is reserving a 256MB region really required? The goal of
-   reserving a 256MB scratch area is to make sure that no
-   important crash data is clobbered when the hypervisor
-   save low mem to the scratch area. But, if one could assure
-   that nothing important is located in some 256MB area, then
-   it would not need to be reserved. Something that can be
-   improved in subsequent versions.
-
- o Still working the kdump team to integrate this with kdump,
-   some work remains but this would not affect the current
-   patches.
-
- o Still need to write a shell script, to copy the dump away.
-   Currently I am parsing it manually.
index 99b85d3..eeed1de 100644 (file)
@@ -6,6 +6,8 @@ SELinux.txt
        - how to get started with the SELinux security enhancement.
 Smack.txt
        - documentation on the Smack Linux Security Module.
+Yama.txt
+       - documentation on the Yama Linux Security Module.
 apparmor.txt
        - documentation on the AppArmor security extension.
 credentials.txt
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt
new file mode 100644 (file)
index 0000000..a9511f1
--- /dev/null
@@ -0,0 +1,65 @@
+Yama is a Linux Security Module that collects a number of system-wide DAC
+security protections that are not handled by the core kernel itself. To
+select it at boot time, specify "security=yama" (though this will disable
+any other LSM).
+
+Yama is controlled through sysctl in /proc/sys/kernel/yama:
+
+- ptrace_scope
+
+==============================================================
+
+ptrace_scope:
+
+As Linux grows in popularity, it will become a larger target for
+malware. One particularly troubling weakness of the Linux process
+interfaces is that a single user is able to examine the memory and
+running state of any of their processes. For example, if one application
+(e.g. Pidgin) was compromised, it would be possible for an attacker to
+attach to other running processes (e.g. Firefox, SSH sessions, GPG agent,
+etc) to extract additional credentials and continue to expand the scope
+of their attack without resorting to user-assisted phishing.
+
+This is not a theoretical problem. SSH session hijacking
+(http://www.storm.net.nz/projects/7) and arbitrary code injection
+(http://c-skills.blogspot.com/2007/05/injectso.html) attacks already
+exist and remain possible if ptrace is allowed to operate as before.
+Since ptrace is not commonly used by non-developers and non-admins, system
+builders should be allowed the option to disable this debugging system.
+
+For a solution, some applications use prctl(PR_SET_DUMPABLE, ...) to
+specifically disallow such ptrace attachment (e.g. ssh-agent), but many
+do not. A more general solution is to only allow ptrace directly from a
+parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still
+work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID"
+still work as root).
+
+For software that has defined application-specific relationships
+between a debugging process and its inferior (crash handlers, etc),
+prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which
+other process (and its descendents) are allowed to call PTRACE_ATTACH
+against it. Only one such declared debugging process can exists for
+each inferior at a time. For example, this is used by KDE, Chromium, and
+Firefox's crash handlers, and by Wine for allowing only Wine processes
+to ptrace each other. If a process wishes to entirely disable these ptrace
+restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
+so that any otherwise allowed process (even those in external pid namespaces)
+may attach.
+
+The sysctl settings are:
+
+0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
+    process running under the same uid, as long as it is dumpable (i.e.
+    did not transition uids, start privileged, or have called
+    prctl(PR_SET_DUMPABLE...) already).
+
+1 - restricted ptrace: a process must have a predefined relationship
+    with the inferior it wants to call PTRACE_ATTACH on. By default,
+    this relationship is that of only its descendants when the above
+    classic criteria is also met. To change the relationship, an
+    inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
+    an allowed debugger PID to call PTRACE_ATTACH on the inferior.
+
+The original children-only logic was based on the restrictions in grsecurity.
+
+==============================================================
index fcbe7a7..7877170 100644 (file)
@@ -554,6 +554,10 @@ The keyctl syscall functions are:
      process must have write permission on the keyring, and it must be a
      keyring (or else error ENOTDIR will result).
 
+     This function can also be used to clear special kernel keyrings if they
+     are appropriately marked if the user has CAP_SYS_ADMIN capability.  The
+     DNS resolver cache keyring is an example of this.
+
 
  (*) Link a key into a keyring:
 
index 92f9924..58f6035 100644 (file)
@@ -4071,7 +4071,7 @@ M:        Josh Boyer <jwboyer@gmail.com>
 M:     Matt Porter <mporter@kernel.crashing.org>
 W:     http://www.penguinppc.org/
 L:     linuxppc-dev@lists.ozlabs.org
-T:     git git://git.infradead.org/users/jwboyer/powerpc-4xx.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
 S:     Maintained
 F:     arch/powerpc/platforms/40x/
 F:     arch/powerpc/platforms/44x/
index 3fcfad4..d1f474d 100644 (file)
@@ -46,6 +46,7 @@ static struct linux_binfmt loader_format = {
 
 static int __init init_loader_binfmt(void)
 {
-       return insert_binfmt(&loader_format);
+       insert_binfmt(&loader_format);
+       return 0;
 }
 arch_initcall(init_loader_binfmt);
index 1fa26d9..ea49bd9 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/module.h>
 
 #include <mach/iomap.h>
 
@@ -58,6 +59,7 @@ unsigned long long tegra_chip_uid(void)
        hi = fuse_readl(FUSE_UID_HIGH);
        return (hi << 32ull) | lo;
 }
+EXPORT_SYMBOL(tegra_chip_uid);
 
 int tegra_sku_id(void)
 {
index ae413d4..d318c60 100644 (file)
@@ -7,6 +7,7 @@ config M68K
        select GENERIC_IRQ_SHOW
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select GENERIC_CPU_DEVICES
+       select FPU if MMU
 
 config RWSEM_GENERIC_SPINLOCK
        bool
@@ -24,9 +25,6 @@ config ARCH_HAS_ILOG2_U64
 config GENERIC_CLOCKEVENTS
        bool
 
-config GENERIC_CMOS_UPDATE
-       def_bool !MMU
-
 config GENERIC_GPIO
        bool
 
@@ -67,6 +65,9 @@ config CPU_HAS_NO_MULDIV64
 config CPU_HAS_ADDRESS_SPACES
        bool
 
+config FPU
+       bool
+
 config HZ
        int
        default 1000 if CLEOPATRA
index 9015ead..6972236 100644 (file)
 #define        MCFDMA_BASE1            (MCF_MBAR + 0x240)      /* Base address DMA 1 */
 
 #if defined(CONFIG_NETtel)
-#define        MCFUART_BASE1           0x180           /* Base address of UART1 */
-#define        MCFUART_BASE2           0x140           /* Base address of UART2 */
+#define        MCFUART_BASE0           (MCF_MBAR + 0x180)      /* Base address UART0 */
+#define        MCFUART_BASE1           (MCF_MBAR + 0x140)      /* Base address UART1 */
 #else
-#define        MCFUART_BASE1           0x140           /* Base address of UART1 */
-#define        MCFUART_BASE2           0x180           /* Base address of UART2 */
+#define        MCFUART_BASE0           (MCF_MBAR + 0x140)      /* Base address UART0 */
+#define        MCFUART_BASE1           (MCF_MBAR + 0x180)      /* Base address UART1 */
 #endif
 
 /*
  */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
+#define        MCF_IRQ_UART0           73              /* UART0 */
+#define        MCF_IRQ_UART1           74              /* UART1 */
 
 /*
  *     Generic GPIO
index eda62de..17f2aab 100644 (file)
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
+#define MCFINT_FECRX0      36          /* Interrupt number for FEC RX */
+#define MCFINT_FECTX0      40          /* Interrupt number for FEC RX */
+#define MCFINT_FECENTC0            42          /* Interrupt number for FEC RX */
 #define MCFINT_PIT1         4           /* Interrupt number for PIT1 (PIT0 in processor) */
 
+#define MCF_IRQ_UART0      (MCFINT_VECBASE + MCFINT_UART0)
+#define MCF_IRQ_UART1      (MCFINT_VECBASE + MCFINT_UART1)
+#define MCF_IRQ_UART2      (MCFINT_VECBASE + MCFINT_UART2)
+
+#define MCF_IRQ_FECRX0     (MCFINT_VECBASE + MCFINT_FECRX0)
+#define MCF_IRQ_FECTX0     (MCFINT_VECBASE + MCFINT_FECTX0)
+#define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define        MCF_IRQ_QSPI        (MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *  SDRAM configuration registers.
  */
 /*
  *  UART module.
  */
-#define MCFUART_BASE1          0xFC060000      /* Base address of UART1 */
-#define MCFUART_BASE2          0xFC064000      /* Base address of UART2 */
-#define MCFUART_BASE3          0xFC068000      /* Base address of UART2 */
+#define MCFUART_BASE0          0xFC060000      /* Base address of UART0 */
+#define MCFUART_BASE1          0xFC064000      /* Base address of UART1 */
+#define MCFUART_BASE2          0xFC068000      /* Base address of UART2 */
 
 /*
  *  FEC module.
  */
-#define        MCFFEC_BASE             0xFC030000      /* Base of FEC ethernet */
-#define        MCFFEC_SIZE             0x800           /* Register set size */
+#define        MCFFEC_BASE0            0xFC030000      /* Base of FEC ethernet */
+#define        MCFFEC_SIZE0            0x800           /* Register set size */
+
+/*
+ *  QSPI module.
+ */
+#define        MCFQSPI_BASE            0xFC05C000      /* Base of QSPI module */
+#define        MCFQSPI_SIZE            0x40            /* Register set size */
+
+#define        MCFQSPI_CS0             46
+#define        MCFQSPI_CS1             47
+#define        MCFQSPI_CS2             27
 
 /*
  *  Reset Control Unit.
index 6235921..075062d 100644 (file)
 
 #define        MCFINT_VECBASE          64              /* Vector base number */
 #define        MCFINT_UART0            13              /* Interrupt number for UART0 */
-#define        MCFINT_PIT1             36              /* Interrupt number for PIT1 */
+#define        MCFINT_UART1            14              /* Interrupt number for UART1 */
+#define        MCFINT_UART2            15              /* Interrupt number for UART2 */
 #define MCFINT_QSPI            18              /* Interrupt number for QSPI */
+#define        MCFINT_FECRX0           23              /* Interrupt number for FEC */
+#define        MCFINT_FECTX0           27              /* Interrupt number for FEC */
+#define        MCFINT_FECENTC0         29              /* Interrupt number for FEC */
+#define        MCFINT_PIT1             36              /* Interrupt number for PIT1 */
+
+#define        MCF_IRQ_UART0           (MCFINT_VECBASE + MCFINT_UART0)
+#define        MCF_IRQ_UART1           (MCFINT_VECBASE + MCFINT_UART1)
+#define        MCF_IRQ_UART2           (MCFINT_VECBASE + MCFINT_UART2)
+
+#define        MCF_IRQ_FECRX0          (MCFINT_VECBASE + MCFINT_FECRX0)
+#define        MCF_IRQ_FECTX0          (MCFINT_VECBASE + MCFINT_FECTX0)
+#define        MCF_IRQ_FECENTC0        (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
 
 /*
  *     SDRAM configuration registers.
@@ -50,8 +65,8 @@
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define        MCF_RCR                 0x110000
-#define        MCF_RSR                 0x110001
+#define        MCF_RCR                 (MCF_IPSBAR + 0x110000)
+#define        MCF_RSR                 (MCF_IPSBAR + 0x110001)
 
 #define        MCF_RCR_SWRESET         0x80            /* Software reset bit */
 #define        MCF_RCR_FRCSTOUT        0x40            /* Force external reset */
 /*
  *  UART module.
  */
-#define MCFUART_BASE1          (MCF_IPSBAR + 0x200)
-#define MCFUART_BASE2          (MCF_IPSBAR + 0x240)
-#define MCFUART_BASE3          (MCF_IPSBAR + 0x280)
+#define MCFUART_BASE0          (MCF_IPSBAR + 0x200)
+#define MCFUART_BASE1          (MCF_IPSBAR + 0x240)
+#define MCFUART_BASE2          (MCF_IPSBAR + 0x280)
 
 /*
  *  FEC ethernet module.
  */
-#define        MCFFEC_BASE             (MCF_IPSBAR + 0x1000)
-#define        MCFFEC_SIZE             0x800
+#define        MCFFEC_BASE0            (MCF_IPSBAR + 0x1000)
+#define        MCFFEC_SIZE0            0x800
+
+/*
+ *  QSPI module.
+ */
+#define        MCFQSPI_BASE            (MCF_IPSBAR + 0x340)
+#define        MCFQSPI_SIZE            0x40
+
+#define        MCFQSPI_CS0             91
+#define        MCFQSPI_CS1             92
+#define        MCFQSPI_CS2             103
+#define        MCFQSPI_CS3             99
 
 /*
  *  GPIO module.
index 805714c..7f0c2c3 100644 (file)
 /*
  *     UART module.
  */
-#define MCFUART_BASE1          0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2          0x200           /* Base address of UART2 */
+#define MCFUART_BASE0          (MCF_MBAR + 0x1c0)      /* Base address UART0 */
+#define MCFUART_BASE1          (MCF_MBAR + 0x200)      /* Base address UART1 */
+
+/*
+ *     QSPI module.
+ */
+#define        MCFQSPI_BASE            (MCF_MBAR + 0x300)      /* Base address QSPI */
+#define        MCFQSPI_SIZE            0x40                    /* Register set size */
+
+#define        MCFQSPI_CS0             29
+#define        MCFQSPI_CS1             24
+#define        MCFQSPI_CS2             21
+#define        MCFQSPI_CS3             22
 
 /*
  *     DMA unit base addresses.
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
 
+#define        MCF_IRQ_UART0           73              /* UART0 */
+#define        MCF_IRQ_UART1           74              /* UART1 */
+
 /*
  *     General purpose IO registers (in MBAR2).
  */
index 759c2b0..a58f176 100644 (file)
@@ -68,8 +68,8 @@
 #define        MCFSIM_DCMR1            0x5c            /* DRAM 1 Mask reg (r/w) */
 #define        MCFSIM_DCCR1            0x63            /* DRAM 1 Control reg (r/w) */
 
-#define        MCFUART_BASE1           0x100           /* Base address of UART1 */
-#define        MCFUART_BASE2           0x140           /* Base address of UART2 */
+#define        MCFUART_BASE0           (MCF_MBAR + 0x100) /* Base address UART0 */
+#define        MCFUART_BASE1           (MCF_MBAR + 0x140) /* Base address UART1 */
 
 #define        MCFSIM_PACNT            (MCF_MBAR + 0x80) /* Port A Control (r/w) */
 #define        MCFSIM_PADDR            (MCF_MBAR + 0x84) /* Port A Direction (r/w) */
@@ -88,6 +88,9 @@
 #define        MCFTIMER_BASE3          (MCF_MBAR + 0x240) /* Base address TIMER4 */
 #define        MCFTIMER_BASE4          (MCF_MBAR + 0x260) /* Base address TIMER3 */
 
+#define        MCFFEC_BASE0            (MCF_MBAR + 0x840) /* Base FEC ethernet */
+#define        MCFFEC_SIZE0            0x1d0
+
 /*
  *     Define system peripheral IRQ usage.
  */
 #define        MCF_IRQ_TIMER2          70              /* Timer 2 */
 #define        MCF_IRQ_TIMER3          71              /* Timer 3 */
 #define        MCF_IRQ_TIMER4          72              /* Timer 4 */
-#define        MCF_IRQ_UART1           73              /* UART 1 */
-#define        MCF_IRQ_UART2           74              /* UART 2 */
+#define        MCF_IRQ_UART0           73              /* UART 0 */
+#define        MCF_IRQ_UART1           74              /* UART 1 */
 #define        MCF_IRQ_PLIP            75              /* PLIC 2Khz Periodic */
 #define        MCF_IRQ_PLIA            76              /* PLIC Asynchronous */
 #define        MCF_IRQ_USB0            77              /* USB Endpoint 0 */
 #define        MCF_IRQ_USB6            83              /* USB Endpoint 6 */
 #define        MCF_IRQ_USB7            84              /* USB Endpoint 7 */
 #define        MCF_IRQ_DMA             85              /* DMA Controller */
-#define        MCF_IRQ_ERX             86              /* Ethernet Receiver */
-#define        MCF_IRQ_ETX             87              /* Ethernet Transmitter */
-#define        MCF_IRQ_ENTC            88              /* Ethernet Non-Time Critical */
+#define        MCF_IRQ_FECRX0          86              /* Ethernet Receiver */
+#define        MCF_IRQ_FECTX0          87              /* Ethernet Transmitter */
+#define        MCF_IRQ_FECENTC0        88              /* Ethernet Non-Time Critical */
 #define        MCF_IRQ_QSPI            89              /* Queued Serial Interface */
 #define        MCF_IRQ_EINT5           90              /* External Interrupt 5 */
 #define        MCF_IRQ_EINT6           91              /* External Interrupt 6 */
index 758810e..83db810 100644 (file)
 #define        MCFINT_UART1            14              /* Interrupt number for UART1 */
 #define        MCFINT_UART2            15              /* Interrupt number for UART2 */
 #define        MCFINT_QSPI             18              /* Interrupt number for QSPI */
+#define        MCFINT_FECRX0           23              /* Interrupt number for FEC0 */
+#define        MCFINT_FECTX0           27              /* Interrupt number for FEC0 */
+#define        MCFINT_FECENTC0         29              /* Interrupt number for FEC0 */
 #define        MCFINT_PIT1             36              /* Interrupt number for PIT1 */
 
+#define        MCFINT2_VECBASE         128             /* Vector base number 2 */
+#define        MCFINT2_FECRX1          23              /* Interrupt number for FEC1 */
+#define        MCFINT2_FECTX1          27              /* Interrupt number for FEC1 */
+#define        MCFINT2_FECENTC1        29              /* Interrupt number for FEC1 */
+
+#define        MCF_IRQ_UART0           (MCFINT_VECBASE + MCFINT_UART0)
+#define        MCF_IRQ_UART1           (MCFINT_VECBASE + MCFINT_UART1)
+#define        MCF_IRQ_UART2           (MCFINT_VECBASE + MCFINT_UART2)
+
+#define        MCF_IRQ_FECRX0          (MCFINT_VECBASE + MCFINT_FECRX0)
+#define        MCF_IRQ_FECTX0          (MCFINT_VECBASE + MCFINT_FECTX0)
+#define        MCF_IRQ_FECENTC0        (MCFINT_VECBASE + MCFINT_FECENTC0)
+#define        MCF_IRQ_FECRX1          (MCFINT2_VECBASE + MCFINT2_FECRX1)
+#define        MCF_IRQ_FECTX1          (MCFINT2_VECBASE + MCFINT2_FECTX1)
+#define        MCF_IRQ_FECENTC1        (MCFINT2_VECBASE + MCFINT2_FECENTC1)
+
+#define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *     SDRAM configuration registers.
  */
@@ -72,9 +93,9 @@
 /*
  *     UART module.
  */
-#define MCFUART_BASE1          (MCF_IPSBAR + 0x200)
-#define MCFUART_BASE2          (MCF_IPSBAR + 0x240)
-#define MCFUART_BASE3          (MCF_IPSBAR + 0x280)
+#define MCFUART_BASE0          (MCF_IPSBAR + 0x200)
+#define MCFUART_BASE1          (MCF_IPSBAR + 0x240)
+#define MCFUART_BASE2          (MCF_IPSBAR + 0x280)
 
 /*
  *     FEC ethernet module.
 #define        MCFFEC_BASE1            (MCF_IPSBAR + 0x1800)
 #define        MCFFEC_SIZE1            0x800
 
+/*
+ *     QSPI module.
+ */
+#define        MCFQSPI_BASE            (MCF_IPSBAR + 0x340)
+#define        MCFQSPI_SIZE            0x40
+
+#ifdef CONFIG_M5271
+#define        MCFQSPI_CS0             91
+#define        MCFQSPI_CS1             92
+#define        MCFQSPI_CS2             99
+#define        MCFQSPI_CS3             103
+#endif
+#ifdef CONFIG_M5275
+#define        MCFQSPI_CS0             59
+#define        MCFQSPI_CS1             60
+#define        MCFQSPI_CS2             61
+#define        MCFQSPI_CS3             62
+#endif
+
+/*
+ *     GPIO module.
+ */
 #ifdef CONFIG_M5271
 #define MCFGPIO_PODR_ADDR      (MCF_IPSBAR + 0x100000)
 #define MCFGPIO_PODR_DATAH     (MCF_IPSBAR + 0x100001)
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define        MCF_RCR                 0x110000
-#define        MCF_RSR                 0x110001
+#define        MCF_RCR                 (MCF_IPSBAR + 0x110000)
+#define        MCF_RSR                 (MCF_IPSBAR + 0x110001)
 
 #define        MCF_RCR_SWRESET         0x80            /* Software reset bit */
 #define        MCF_RCR_FRCSTOUT        0x40            /* Force external reset */
index d798bd5..569476f 100644 (file)
 
 #define        MCFINT_VECBASE          64              /* Vector base number */
 #define        MCFINT_UART0            13              /* Interrupt number for UART0 */
+#define        MCFINT_UART1            14              /* Interrupt number for UART1 */
+#define        MCFINT_UART2            15              /* Interrupt number for UART2 */
 #define        MCFINT_QSPI             18              /* Interrupt number for QSPI */
+#define        MCFINT_FECRX0           23              /* Interrupt number for FEC */
+#define        MCFINT_FECTX0           27              /* Interrupt number for FEC */
+#define        MCFINT_FECENTC0         29              /* Interrupt number for FEC */
 #define        MCFINT_PIT1             55              /* Interrupt number for PIT1 */
 
+#define        MCF_IRQ_UART0           (MCFINT_VECBASE + MCFINT_UART0)
+#define        MCF_IRQ_UART1           (MCFINT_VECBASE + MCFINT_UART1)
+#define        MCF_IRQ_UART2           (MCFINT_VECBASE + MCFINT_UART2)
+
+#define        MCF_IRQ_FECRX0          (MCFINT_VECBASE + MCFINT_FECRX0)
+#define        MCF_IRQ_FECTX0          (MCFINT_VECBASE + MCFINT_FECTX0)
+#define        MCF_IRQ_FECENTC0        (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
+
 /*
  *     SDRAM configuration registers.
  */
 /*
  *     UART module.
  */
-#define        MCFUART_BASE1           (MCF_IPSBAR + 0x00000200)
-#define        MCFUART_BASE2           (MCF_IPSBAR + 0x00000240)
-#define        MCFUART_BASE3           (MCF_IPSBAR + 0x00000280)
+#define        MCFUART_BASE0           (MCF_IPSBAR + 0x00000200)
+#define        MCFUART_BASE1           (MCF_IPSBAR + 0x00000240)
+#define        MCFUART_BASE2           (MCF_IPSBAR + 0x00000280)
 
 /*
  *     FEC ethernet module.
  */
-#define        MCFFEC_BASE             (MCF_IPSBAR + 0x00001000)
-#define        MCFFEC_SIZE             0x800
+#define        MCFFEC_BASE0            (MCF_IPSBAR + 0x00001000)
+#define        MCFFEC_SIZE0            0x800
+
+/*
+ *     QSPI module.
+ */
+#define        MCFQSPI_IOBASE          (MCF_IPSBAR + 0x340)
+#define        MCFQSPI_SIZE            0x40
+
+#define        MCFQSPI_CS0             147
+#define        MCFQSPI_CS1             148
+#define        MCFQSPI_CS2             149
+#define        MCFQSPI_CS3             150
 
 /*
  *     GPIO registers
 /*
  *  Reset Control Unit (relative to IPSBAR).
  */
-#define        MCF_RCR                 0x110000
-#define        MCF_RSR                 0x110001
+#define        MCF_RCR                 (MCF_IPSBAR + 0x110000)
+#define        MCF_RSR                 (MCF_IPSBAR + 0x110001)
 
 #define        MCF_RCR_SWRESET         0x80            /* Software reset bit */
 #define        MCF_RCR_FRCSTOUT        0x40            /* Force external reset */
index 8f8609f..3bc3ada 100644 (file)
  *  UART module.
  */
 #if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
-#define MCFUART_BASE1          0x200           /* Base address of UART1 */
-#define MCFUART_BASE2          0x1c0           /* Base address of UART2 */
+#define MCFUART_BASE0          (MCF_MBAR + 0x200)      /* Base address UART0 */
+#define MCFUART_BASE1          (MCF_MBAR + 0x1c0)      /* Base address UART1 */
 #else
-#define MCFUART_BASE1          0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2          0x200           /* Base address of UART2 */
+#define MCFUART_BASE0          (MCF_MBAR + 0x1c0)      /* Base address UART0 */
+#define MCFUART_BASE1          (MCF_MBAR + 0x200)      /* Base address UART1 */
 #endif
 
 /*
  */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
+#define        MCF_IRQ_UART0           73              /* UART0 */
+#define        MCF_IRQ_UART1           74              /* UART1 */
 
 /****************************************************************************/
 #endif /* m5307sim_h */
index ba4cc78..29b66e2 100644 (file)
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
+#define MCFINT_FECRX0      36          /* Interrupt number for FEC */
+#define MCFINT_FECTX0      40          /* Interrupt number for FEC */
+#define MCFINT_FECENTC0            42          /* Interrupt number for FEC */
+
+#define MCF_IRQ_UART0       (MCFINT_VECBASE + MCFINT_UART0)
+#define MCF_IRQ_UART1       (MCFINT_VECBASE + MCFINT_UART1)
+#define MCF_IRQ_UART2       (MCFINT_VECBASE + MCFINT_UART2)
+
+#define MCF_IRQ_FECRX0     (MCFINT_VECBASE + MCFINT_FECRX0)
+#define MCF_IRQ_FECTX0     (MCFINT_VECBASE + MCFINT_FECTX0)
+#define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
+
+#define        MCF_IRQ_QSPI        (MCFINT_VECBASE + MCFINT_QSPI)
 
 #define MCF_WTM_WCR    MCF_REG16(0xFC098000)
 
 /*
  *  UART module.
  */
-#define MCFUART_BASE1          0xFC060000      /* Base address of UART1 */
-#define MCFUART_BASE2          0xFC064000      /* Base address of UART2 */
-#define MCFUART_BASE3          0xFC068000      /* Base address of UART3 */
+#define MCFUART_BASE0          0xFC060000      /* Base address of UART1 */
+#define MCFUART_BASE1          0xFC064000      /* Base address of UART2 */
+#define MCFUART_BASE2          0xFC068000      /* Base address of UART3 */
+
+/*
+ *  FEC module.
+ */
+#define        MCFFEC_BASE0            0xFC030000      /* Base address of FEC0 */
+#define        MCFFEC_SIZE0            0x800           /* Size of FEC0 region */
+
+/*
+ *  QSPI module.
+ */
+#define        MCFQSPI_BASE            0xFC058000      /* Base address of QSPI */
+#define        MCFQSPI_SIZE            0x40            /* Size of QSPI region */
+
+#define        MCFQSPI_CS0             84
+#define        MCFQSPI_CS1             85
+#define        MCFQSPI_CS2             86
 
 /*
  *  Timer module.
index 51e00b0..79f58dd 100644 (file)
@@ -85,8 +85,8 @@
 #define MCFTIMER_BASE1         (MCF_MBAR + 0x140)      /* Base of TIMER1 */
 #define MCFTIMER_BASE2         (MCF_MBAR + 0x180)      /* Base of TIMER2 */
 
-#define MCFUART_BASE1          0x1c0           /* Base address of UART1 */
-#define MCFUART_BASE2          0x200           /* Base address of UART2 */
+#define MCFUART_BASE0          (MCF_MBAR + 0x1c0)      /* Base address UART0 */
+#define MCFUART_BASE1          (MCF_MBAR + 0x200)      /* Base address UART1 */
 
 #define        MCFSIM_PADDR            (MCF_MBAR + 0x244)
 #define        MCFSIM_PADAT            (MCF_MBAR + 0x248)
  */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
+#define        MCF_IRQ_UART0           73              /* UART0 */
+#define        MCF_IRQ_UART1           74              /* UART1 */
 
 /****************************************************************************/
 #endif /* m5407sim_h */
index 1ed8bfb..ae56b88 100644 (file)
 /*
  *     UART module.
  */
-#define MCFUART_BASE1          0x8600          /* Base address of UART1 */
-#define MCFUART_BASE2          0x8700          /* Base address of UART2 */
-#define MCFUART_BASE3          0x8800          /* Base address of UART3 */
-#define MCFUART_BASE4          0x8900          /* Base address of UART4 */
+#define MCFUART_BASE0          (MCF_MBAR + 0x8600)     /* Base address UART0 */
+#define MCFUART_BASE1          (MCF_MBAR + 0x8700)     /* Base address UART1 */
+#define MCFUART_BASE2          (MCF_MBAR + 0x8800)     /* Base address UART2 */
+#define MCFUART_BASE3          (MCF_MBAR + 0x8900)     /* Base address UART3 */
 
 /*
  *     Define system peripheral IRQ usage.
  */
-#define MCF_IRQ_TIMER          (64 + 54)       /* Slice Timer 0 */
-#define MCF_IRQ_PROFILER       (64 + 53)       /* Slice Timer 1 */
+#define MCF_IRQ_TIMER          (MCFINT_VECBASE + 54)   /* Slice Timer 0 */
+#define MCF_IRQ_PROFILER       (MCFINT_VECBASE + 53)   /* Slice Timer 1 */
+#define MCF_IRQ_UART0          (MCFINT_VECBASE + 35)
+#define MCF_IRQ_UART1          (MCFINT_VECBASE + 34)
+#define MCF_IRQ_UART2          (MCFINT_VECBASE + 33)
+#define MCF_IRQ_UART3          (MCFINT_VECBASE + 32)
 
 /*
  *     Generic GPIO support
index 789f3b2..825c1c8 100644 (file)
@@ -22,8 +22,6 @@ extern unsigned int (*mach_get_ss)(void);
 extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_clock_mmss)(unsigned long);
-extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
-                           int *min, int *sec);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
 extern void (*mach_power_off)( void );
@@ -35,9 +33,8 @@ extern void (*mach_l2_flush) (int);
 extern void (*mach_beep) (unsigned int, unsigned int);
 
 /* Hardware clock functions */
-extern void hw_timer_init(void);
+extern void hw_timer_init(irq_handler_t handler);
 extern unsigned long hw_timer_offset(void);
-extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
 
index 7fe6319..7b51416 100644 (file)
 #ifndef mcfqspi_h
 #define mcfqspi_h
 
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-#define        MCFQSPI_IOBASE          (MCF_IPSBAR + 0x340)
-#elif defined(CONFIG_M5249)
-#define MCFQSPI_IOBASE         (MCF_MBAR + 0x300)
-#elif defined(CONFIG_M520x)
-#define MCFQSPI_IOBASE         0xFC05C000
-#elif defined(CONFIG_M532x)
-#define MCFQSPI_IOBASE         0xFC058000
-#endif
-#define MCFQSPI_IOSIZE         0x40
-
 /**
  * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver
  * @setup: setup the control; allocate gpio's, etc. May be NULL.
index 2abedff..2d3bc77 100644 (file)
@@ -41,7 +41,10 @@ struct mcf_platform_uart {
 #define        MCFUART_UTF             0x28            /* Transmitter FIFO (r/w) */
 #define        MCFUART_URF             0x2c            /* Receiver FIFO (r/w) */
 #define        MCFUART_UFPD            0x30            /* Frac Prec. Divider (r/w) */
-#else
+#endif
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+        defined(CONFIG_M5249) || defined(CONFIG_M5307) || \
+        defined(CONFIG_M5407)
 #define        MCFUART_UIVR            0x30            /* Interrupt Vector (r/w) */
 #endif
 #define        MCFUART_UIPR            0x34            /* Input Port (r) */
index 6cf4bd6..c54ef92 100644 (file)
@@ -1,5 +1,378 @@
+/*
+ *  linux/arch/m68k/kernel/process.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  68060 fixes by Jesper Skov
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/reboot.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+
+asmlinkage void ret_from_fork(void);
+
+
+/*
+ * Return saved PC from a blocked thread
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
+       /* Check whether the thread is blocked in resume() */
+       if (in_sched_functions(sw->retpc))
+               return ((unsigned long *)sw->a6)[1];
+       else
+               return sw->retpc;
+}
+
+/*
+ * The idle loop on an m68k..
+ */
+static void default_idle(void)
+{
+       if (!need_resched())
+#if defined(MACH_ATARI_ONLY)
+               /* block out HSYNC on the atari (falcon) */
+               __asm__("stop #0x2200" : : : "cc");
+#else
+               __asm__("stop #0x2000" : : : "cc");
+#endif
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       while (1) {
+               while (!need_resched())
+                       idle();
+               schedule_preempt_disabled();
+       }
+}
+
+void machine_restart(char * __unused)
+{
+       if (mach_reset)
+               mach_reset();
+       for (;;);
+}
+
+void machine_halt(void)
+{
+       if (mach_halt)
+               mach_halt();
+       for (;;);
+}
+
+void machine_power_off(void)
+{
+       if (mach_power_off)
+               mach_power_off();
+       for (;;);
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+       printk("\n");
+       printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
+              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
+       printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
+              regs->orig_d0, regs->d0, regs->a2, regs->a1);
+       printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
+              regs->a0, regs->d5, regs->d4);
+       printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
+              regs->d3, regs->d2, regs->d1);
+       if (!(regs->sr & PS_S))
+               printk("USP: %08lx\n", rdusp());
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       int pid;
+       mm_segment_t fs;
+
+       fs = get_fs();
+       set_fs (KERNEL_DS);
+
+       {
+       register long retval __asm__ ("d0");
+       register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
+
+       retval = __NR_clone;
+       __asm__ __volatile__
+         ("clrl %%d2\n\t"
+          "trap #0\n\t"                /* Linux/m68k system call */
+          "tstl %0\n\t"                /* child or parent */
+          "jne 1f\n\t"                 /* parent - jump */
+#ifdef CONFIG_MMU
+          "lea %%sp@(%c7),%6\n\t"      /* reload current */
+          "movel %6@,%6\n\t"
+#endif
+          "movel %3,%%sp@-\n\t"        /* push argument */
+          "jsr %4@\n\t"                /* call fn */
+          "movel %0,%%d1\n\t"          /* pass exit value */
+          "movel %2,%%d0\n\t"          /* exit */
+          "trap #0\n"
+          "1:"
+          : "+d" (retval)
+          : "i" (__NR_clone), "i" (__NR_exit),
+            "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
+            "i" (-THREAD_SIZE)
+          : "d2");
+
+       pid = retval;
+       }
+
+       set_fs (fs);
+       return pid;
+}
+EXPORT_SYMBOL(kernel_thread);
+
+void flush_thread(void)
+{
+       current->thread.fs = __USER_DS;
+#ifdef CONFIG_FPU
+       if (!FPU_IS_EMU) {
+               unsigned long zero = 0;
+               asm volatile("frestore %0": :"m" (zero));
+       }
+#endif
+}
+
+/*
+ * "m68k_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+
+asmlinkage int m68k_fork(struct pt_regs *regs)
+{
 #ifdef CONFIG_MMU
-#include "process_mm.c"
+       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
 #else
-#include "process_no.c"
+       return -EINVAL;
 #endif
+}
+
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
+                      NULL, NULL);
+}
+
+asmlinkage int m68k_clone(struct pt_regs *regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+       int __user *parent_tidptr, *child_tidptr;
+
+       /* syscall2 puts clone_flags in d1 and usp in d2 */
+       clone_flags = regs->d1;
+       newsp = regs->d2;
+       parent_tidptr = (int __user *)regs->d3;
+       child_tidptr = (int __user *)regs->d4;
+       if (!newsp)
+               newsp = rdusp();
+       return do_fork(clone_flags, newsp, regs, 0,
+                      parent_tidptr, child_tidptr);
+}
+
+int copy_thread(unsigned long clone_flags, unsigned long usp,
+                unsigned long unused,
+                struct task_struct * p, struct pt_regs * regs)
+{
+       struct pt_regs * childregs;
+       struct switch_stack * childstack, *stack;
+       unsigned long *retp;
+
+       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+
+       *childregs = *regs;
+       childregs->d0 = 0;
+
+       retp = ((unsigned long *) regs);
+       stack = ((struct switch_stack *) retp) - 1;
+
+       childstack = ((struct switch_stack *) childregs) - 1;
+       *childstack = *stack;
+       childstack->retpc = (unsigned long)ret_from_fork;
+
+       p->thread.usp = usp;
+       p->thread.ksp = (unsigned long)childstack;
+
+       if (clone_flags & CLONE_SETTLS)
+               task_thread_info(p)->tp_value = regs->d5;
+
+       /*
+        * Must save the current SFC/DFC value, NOT the value when
+        * the parent was last descheduled - RGH  10-08-96
+        */
+       p->thread.fs = get_fs().seg;
+
+#ifdef CONFIG_FPU
+       if (!FPU_IS_EMU) {
+               /* Copy the current fpu state */
+               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
+
+               if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
+                       if (CPU_IS_COLDFIRE) {
+                               asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
+                                             "fmovel %/fpiar,%1\n\t"
+                                             "fmovel %/fpcr,%2\n\t"
+                                             "fmovel %/fpsr,%3"
+                                             :
+                                             : "m" (p->thread.fp[0]),
+                                               "m" (p->thread.fpcntl[0]),
+                                               "m" (p->thread.fpcntl[1]),
+                                               "m" (p->thread.fpcntl[2])
+                                             : "memory");
+                       } else {
+                               asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+                                             "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+                                             :
+                                             : "m" (p->thread.fp[0]),
+                                               "m" (p->thread.fpcntl[0])
+                                             : "memory");
+                       }
+               }
+
+               /* Restore the state in case the fpu was busy */
+               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+       }
+#endif /* CONFIG_FPU */
+
+       return 0;
+}
+
+/* Fill in the fpu structure for a core dump.  */
+#ifdef CONFIG_FPU
+int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+{
+       char fpustate[216];
+
+       if (FPU_IS_EMU) {
+               int i;
+
+               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
+               memcpy(fpu->fpregs, current->thread.fp, 96);
+               /* Convert internal fpu reg representation
+                * into long double format
+                */
+               for (i = 0; i < 24; i += 3)
+                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
+                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
+               return 1;
+       }
+
+       /* First dump the fpu context to avoid protocol violation.  */
+       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+       if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
+               return 0;
+
+       if (CPU_IS_COLDFIRE) {
+               asm volatile ("fmovel %/fpiar,%0\n\t"
+                             "fmovel %/fpcr,%1\n\t"
+                             "fmovel %/fpsr,%2\n\t"
+                             "fmovemd %/fp0-%/fp7,%3"
+                             :
+                             : "m" (fpu->fpcntl[0]),
+                               "m" (fpu->fpcntl[1]),
+                               "m" (fpu->fpcntl[2]),
+                               "m" (fpu->fpregs[0])
+                             : "memory");
+       } else {
+               asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+                             :
+                             : "m" (fpu->fpcntl[0])
+                             : "memory");
+               asm volatile ("fmovemx %/fp0-%/fp7,%0"
+                             :
+                             : "m" (fpu->fpregs[0])
+                             : "memory");
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL(dump_fpu);
+#endif /* CONFIG_FPU */
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char __user *name,
+                         const char __user *const __user *argv,
+                         const char __user *const __user *envp)
+{
+       int error;
+       char * filename;
+       struct pt_regs *regs = (struct pt_regs *) &name;
+
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               return error;
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+       return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long fp, pc;
+       unsigned long stack_page;
+       int count = 0;
+       if (!p || p == current || p->state == TASK_RUNNING)
+               return 0;
+
+       stack_page = (unsigned long)task_stack_page(p);
+       fp = ((struct switch_stack *)p->thread.ksp)->a6;
+       do {
+               if (fp < stack_page+sizeof(struct thread_info) ||
+                   fp >= 8184+stack_page)
+                       return 0;
+               pc = ((unsigned long *)fp)[1];
+               if (!in_sched_functions(pc))
+                       return pc;
+               fp = *(unsigned long *) fp;
+       } while (count++ < 16);
+       return 0;
+}
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
deleted file mode 100644 (file)
index fe4186b..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/reboot.h>
-#include <linux/init_task.h>
-#include <linux/mqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-
-asmlinkage void ret_from_fork(void);
-
-
-/*
- * Return saved PC from a blocked thread
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-       /* Check whether the thread is blocked in resume() */
-       if (in_sched_functions(sw->retpc))
-               return ((unsigned long *)sw->a6)[1];
-       else
-               return sw->retpc;
-}
-
-/*
- * The idle loop on an m68k..
- */
-static void default_idle(void)
-{
-       if (!need_resched())
-#if defined(MACH_ATARI_ONLY)
-               /* block out HSYNC on the atari (falcon) */
-               __asm__("stop #0x2200" : : : "cc");
-#else
-               __asm__("stop #0x2000" : : : "cc");
-#endif
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-       /* endless idle loop with no priority at all */
-       while (1) {
-               while (!need_resched())
-                       idle();
-               schedule_preempt_disabled();
-       }
-}
-
-void machine_restart(char * __unused)
-{
-       if (mach_reset)
-               mach_reset();
-       for (;;);
-}
-
-void machine_halt(void)
-{
-       if (mach_halt)
-               mach_halt();
-       for (;;);
-}
-
-void machine_power_off(void)
-{
-       if (mach_power_off)
-               mach_power_off();
-       for (;;);
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
-void show_regs(struct pt_regs * regs)
-{
-       printk("\n");
-       printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-       printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-              regs->orig_d0, regs->d0, regs->a2, regs->a1);
-       printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
-              regs->a0, regs->d5, regs->d4);
-       printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
-              regs->d3, regs->d2, regs->d1);
-       if (!(regs->sr & PS_S))
-               printk("USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       int pid;
-       mm_segment_t fs;
-
-       fs = get_fs();
-       set_fs (KERNEL_DS);
-
-       {
-       register long retval __asm__ ("d0");
-       register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
-
-       retval = __NR_clone;
-       __asm__ __volatile__
-         ("clrl %%d2\n\t"
-          "trap #0\n\t"                /* Linux/m68k system call */
-          "tstl %0\n\t"                /* child or parent */
-          "jne 1f\n\t"                 /* parent - jump */
-          "lea %%sp@(%c7),%6\n\t"      /* reload current */
-          "movel %6@,%6\n\t"
-          "movel %3,%%sp@-\n\t"        /* push argument */
-          "jsr %4@\n\t"                /* call fn */
-          "movel %0,%%d1\n\t"          /* pass exit value */
-          "movel %2,%%d0\n\t"          /* exit */
-          "trap #0\n"
-          "1:"
-          : "+d" (retval)
-          : "i" (__NR_clone), "i" (__NR_exit),
-            "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
-            "i" (-THREAD_SIZE)
-          : "d2");
-
-       pid = retval;
-       }
-
-       set_fs (fs);
-       return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
-void flush_thread(void)
-{
-       unsigned long zero = 0;
-
-       current->thread.fs = __USER_DS;
-       if (!FPU_IS_EMU)
-               asm volatile("frestore %0": :"m" (zero));
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
-                      NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-       int __user *parent_tidptr, *child_tidptr;
-
-       /* syscall2 puts clone_flags in d1 and usp in d2 */
-       clone_flags = regs->d1;
-       newsp = regs->d2;
-       parent_tidptr = (int __user *)regs->d3;
-       child_tidptr = (int __user *)regs->d4;
-       if (!newsp)
-               newsp = rdusp();
-       return do_fork(clone_flags, newsp, regs, 0,
-                      parent_tidptr, child_tidptr);
-}
-
-int copy_thread(unsigned long clone_flags, unsigned long usp,
-                unsigned long unused,
-                struct task_struct * p, struct pt_regs * regs)
-{
-       struct pt_regs * childregs;
-       struct switch_stack * childstack, *stack;
-       unsigned long *retp;
-
-       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-       *childregs = *regs;
-       childregs->d0 = 0;
-
-       retp = ((unsigned long *) regs);
-       stack = ((struct switch_stack *) retp) - 1;
-
-       childstack = ((struct switch_stack *) childregs) - 1;
-       *childstack = *stack;
-       childstack->retpc = (unsigned long)ret_from_fork;
-
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childstack;
-
-       if (clone_flags & CLONE_SETTLS)
-               task_thread_info(p)->tp_value = regs->d5;
-
-       /*
-        * Must save the current SFC/DFC value, NOT the value when
-        * the parent was last descheduled - RGH  10-08-96
-        */
-       p->thread.fs = get_fs().seg;
-
-       if (!FPU_IS_EMU) {
-               /* Copy the current fpu state */
-               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-               if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) {
-                       if (CPU_IS_COLDFIRE) {
-                               asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t"
-                                             "fmovel %/fpiar,%1\n\t"
-                                             "fmovel %/fpcr,%2\n\t"
-                                             "fmovel %/fpsr,%3"
-                                             :
-                                             : "m" (p->thread.fp[0]),
-                                               "m" (p->thread.fpcntl[0]),
-                                               "m" (p->thread.fpcntl[1]),
-                                               "m" (p->thread.fpcntl[2])
-                                             : "memory");
-                       } else {
-                               asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-                                             "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-                                             :
-                                             : "m" (p->thread.fp[0]),
-                                               "m" (p->thread.fpcntl[0])
-                                             : "memory");
-                       }
-               }
-
-               /* Restore the state in case the fpu was busy */
-               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-       }
-
-       return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-       char fpustate[216];
-
-       if (FPU_IS_EMU) {
-               int i;
-
-               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-               memcpy(fpu->fpregs, current->thread.fp, 96);
-               /* Convert internal fpu reg representation
-                * into long double format
-                */
-               for (i = 0; i < 24; i += 3)
-                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
-               return 1;
-       }
-
-       /* First dump the fpu context to avoid protocol violation.  */
-       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-       if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
-               return 0;
-
-       if (CPU_IS_COLDFIRE) {
-               asm volatile ("fmovel %/fpiar,%0\n\t"
-                             "fmovel %/fpcr,%1\n\t"
-                             "fmovel %/fpsr,%2\n\t"
-                             "fmovemd %/fp0-%/fp7,%3"
-                             :
-                             : "m" (fpu->fpcntl[0]),
-                               "m" (fpu->fpcntl[1]),
-                               "m" (fpu->fpcntl[2]),
-                               "m" (fpu->fpregs[0])
-                             : "memory");
-       } else {
-               asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-                             :
-                             : "m" (fpu->fpcntl[0])
-                             : "memory");
-               asm volatile ("fmovemx %/fp0-%/fp7,%0"
-                             :
-                             : "m" (fpu->fpregs[0])
-                             : "memory");
-       }
-
-       return 1;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
-                         const char __user *const __user *argv,
-                         const char __user *const __user *envp)
-{
-       int error;
-       char * filename;
-       struct pt_regs *regs = (struct pt_regs *) &name;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-       unsigned long fp, pc;
-       unsigned long stack_page;
-       int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
-               return 0;
-
-       stack_page = (unsigned long)task_stack_page(p);
-       fp = ((struct switch_stack *)p->thread.ksp)->a6;
-       do {
-               if (fp < stack_page+sizeof(struct thread_info) ||
-                   fp >= 8184+stack_page)
-                       return 0;
-               pc = ((unsigned long *)fp)[1];
-               if (!in_sched_functions(pc))
-                       return pc;
-               fp = *(unsigned long *) fp;
-       } while (count++ < 16);
-       return 0;
-}
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
deleted file mode 100644 (file)
index f7fe6c3..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- *
- *  uClinux changes
- *  Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-asmlinkage void ret_from_fork(void);
-
-/*
- * The following aren't currently used.
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-/*
- * The idle loop on an m68knommu..
- */
-static void default_idle(void)
-{
-       local_irq_disable();
-       while (!need_resched()) {
-               /* This stop will re-enable interrupts */
-               __asm__("stop #0x2000" : : : "cc");
-               local_irq_disable();
-       }
-       local_irq_enable();
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-       /* endless idle loop with no priority at all */
-       while (1) {
-               idle();
-               schedule_preempt_disabled();
-       }
-}
-
-void machine_restart(char * __unused)
-{
-       if (mach_reset)
-               mach_reset();
-       for (;;);
-}
-
-void machine_halt(void)
-{
-       if (mach_halt)
-               mach_halt();
-       for (;;);
-}
-
-void machine_power_off(void)
-{
-       if (mach_power_off)
-               mach_power_off();
-       for (;;);
-}
-
-void show_regs(struct pt_regs * regs)
-{
-       printk(KERN_NOTICE "\n");
-       printk(KERN_NOTICE "Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-       printk(KERN_NOTICE "ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-              regs->orig_d0, regs->d0, regs->a2, regs->a1);
-       printk(KERN_NOTICE "A0: %08lx  D5: %08lx  D4: %08lx\n",
-              regs->a0, regs->d5, regs->d4);
-       printk(KERN_NOTICE "D3: %08lx  D2: %08lx  D1: %08lx\n",
-              regs->d3, regs->d2, regs->d1);
-       if (!(regs->sr & PS_S))
-               printk(KERN_NOTICE "USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       int retval;
-       long clone_arg = flags | CLONE_VM;
-       mm_segment_t fs;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-
-       __asm__ __volatile__ (
-                       "movel  %%sp, %%d2\n\t"
-                       "movel  %5, %%d1\n\t"
-                       "movel  %1, %%d0\n\t"
-                       "trap   #0\n\t"
-                       "cmpl   %%sp, %%d2\n\t"
-                       "jeq    1f\n\t"
-                       "movel  %3, %%sp@-\n\t"
-                       "jsr    %4@\n\t"
-                       "movel  %2, %%d0\n\t"
-                       "trap   #0\n"
-                       "1:\n\t"
-                       "movel  %%d0, %0\n"
-               : "=d" (retval)
-               : "i" (__NR_clone),
-                 "i" (__NR_exit),
-                 "a" (arg),
-                 "a" (fn),
-                 "a" (clone_arg)
-               : "cc", "%d0", "%d1", "%d2");
-
-       set_fs(fs);
-       return retval;
-}
-EXPORT_SYMBOL(kernel_thread);
-
-void flush_thread(void)
-{
-#ifdef CONFIG_FPU
-       unsigned long zero = 0;
-#endif
-
-       current->thread.fs = __USER_DS;
-#ifdef CONFIG_FPU
-       if (!FPU_IS_EMU)
-               asm volatile (".chip 68k/68881\n\t"
-                             "frestore %0\n\t"
-                             ".chip 68k" : : "m" (zero));
-#endif
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-       /* fork almost works, enough to trick you into looking elsewhere :-( */
-       return(-EINVAL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-
-       /* syscall2 puts clone_flags in d1 and usp in d2 */
-       clone_flags = regs->d1;
-       newsp = regs->d2;
-       if (!newsp)
-               newsp = rdusp();
-        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
-}
-
-int copy_thread(unsigned long clone_flags,
-               unsigned long usp, unsigned long topstk,
-               struct task_struct * p, struct pt_regs * regs)
-{
-       struct pt_regs * childregs;
-       struct switch_stack * childstack, *stack;
-       unsigned long *retp;
-
-       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-       *childregs = *regs;
-       childregs->d0 = 0;
-
-       retp = ((unsigned long *) regs);
-       stack = ((struct switch_stack *) retp) - 1;
-
-       childstack = ((struct switch_stack *) childregs) - 1;
-       *childstack = *stack;
-       childstack->retpc = (unsigned long)ret_from_fork;
-
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childstack;
-
-       if (clone_flags & CLONE_SETTLS)
-               task_thread_info(p)->tp_value = regs->d5;
-
-       /*
-        * Must save the current SFC/DFC value, NOT the value when
-        * the parent was last descheduled - RGH  10-08-96
-        */
-       p->thread.fs = get_fs().seg;
-
-#ifdef CONFIG_FPU
-       if (!FPU_IS_EMU) {
-               /* Copy the current fpu state */
-               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-               if (p->thread.fpstate[0])
-                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
-                               : "memory");
-               /* Restore the state in case the fpu was busy */
-               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-       }
-#endif
-
-       return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-#ifdef CONFIG_FPU
-       char fpustate[216];
-
-       if (FPU_IS_EMU) {
-               int i;
-
-               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-               memcpy(fpu->fpregs, current->thread.fp, 96);
-               /* Convert internal fpu reg representation
-                * into long double format
-                */
-               for (i = 0; i < 24; i += 3)
-                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
-               return 1;
-       }
-
-       /* First dump the fpu context to avoid protocol violation.  */
-       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-       if (!fpustate[0])
-               return 0;
-
-       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-               :: "m" (fpu->fpcntl[0])
-               : "memory");
-       asm volatile ("fmovemx %/fp0-%/fp7,%0"
-               :: "m" (fpu->fpregs[0])
-               : "memory");
-#endif
-       return 1;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
- *     Generic dumping code. Used for panic and debug.
- */
-void dump(struct pt_regs *fp)
-{
-       unsigned long   *sp;
-       unsigned char   *tp;
-       int             i;
-
-       printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
-       printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
-
-       if (current->mm) {
-               printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
-                       (int) current->mm->start_code,
-                       (int) current->mm->end_code,
-                       (int) current->mm->start_data,
-                       (int) current->mm->end_data,
-                       (int) current->mm->end_data,
-                       (int) current->mm->brk);
-               printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
-                       (int) current->mm->start_stack,
-                       (int)(((unsigned long) current) + THREAD_SIZE));
-       }
-
-       printk(KERN_EMERG "PC: %08lx\n", fp->pc);
-       printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
-       printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-               fp->d0, fp->d1, fp->d2, fp->d3);
-       printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-               fp->d4, fp->d5, fp->a0, fp->a1);
-       printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %p\n",
-               (unsigned int) rdusp(), fp);
-
-       printk(KERN_EMERG "\nCODE:");
-       tp = ((unsigned char *) fp->pc) - 0x20;
-       for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-
-       printk(KERN_EMERG "KERNEL STACK:");
-       tp = ((unsigned char *) fp) - 0x40;
-       for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-
-       printk(KERN_EMERG "USER STACK:");
-       tp = (unsigned char *) (rdusp() - 0x10);
-       for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *name,
-                         const char *const *argv,
-                         const char *const *envp)
-{
-       int error;
-       char * filename;
-       struct pt_regs *regs = (struct pt_regs *) &name;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-       unsigned long fp, pc;
-       unsigned long stack_page;
-       int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
-               return 0;
-
-       stack_page = (unsigned long)p;
-       fp = ((struct switch_stack *)p->thread.ksp)->a6;
-       do {
-               if (fp < stack_page+sizeof(struct thread_info) ||
-                   fp >= THREAD_SIZE-8+stack_page)
-                       return 0;
-               pc = ((unsigned long *)fp)[1];
-               if (!in_sched_functions(pc))
-                       return pc;
-               fp = *(unsigned long *) fp;
-       } while (count++ < 16);
-       return 0;
-}
-
-/*
- * Return saved PC of a blocked thread.
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-
-       /* Check whether the thread is blocked in resume() */
-       if (in_sched_functions(sw->retpc))
-               return ((unsigned long *)sw->a6)[1];
-       else
-               return sw->retpc;
-}
-
index 07a4175..149a05f 100644 (file)
@@ -1,5 +1,305 @@
+/*
+ *  linux/arch/m68k/kernel/ptrace.c
+ *
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/tracehook.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x001f
+
+/* sets the trace bits. */
+#define TRACE_BITS 0xC000
+#define T1_BIT 0x8000
+#define T0_BIT 0x4000
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
+                        - sizeof(struct switch_stack))
+/* Mapping from PT_xxx to the stack offset at which the register is
+   saved.  Notice that usp has no stack-slot and needs to be treated
+   specially (see get_reg/put_reg below). */
+static const int regoff[] = {
+       [0]     = PT_REG(d1),
+       [1]     = PT_REG(d2),
+       [2]     = PT_REG(d3),
+       [3]     = PT_REG(d4),
+       [4]     = PT_REG(d5),
+       [5]     = SW_REG(d6),
+       [6]     = SW_REG(d7),
+       [7]     = PT_REG(a0),
+       [8]     = PT_REG(a1),
+       [9]     = PT_REG(a2),
+       [10]    = SW_REG(a3),
+       [11]    = SW_REG(a4),
+       [12]    = SW_REG(a5),
+       [13]    = SW_REG(a6),
+       [14]    = PT_REG(d0),
+       [15]    = -1,
+       [16]    = PT_REG(orig_d0),
+       [17]    = PT_REG(sr),
+       [18]    = PT_REG(pc),
+};
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+       else
+               return 0;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR)
+                       return *(unsigned short *)addr;
+       }
+       return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+                         unsigned long data)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+       else
+               return -1;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR) {
+                       *(unsigned short *)addr = data;
+                       return 0;
+               }
+       }
+       *addr = data;
+       return 0;
+}
+
+/*
+ * Make sure the single step bit is not set.
+ */
+static inline void singlestep_disable(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp);
+       clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       singlestep_disable(child);
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T1_BIT);
+       set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
 #ifdef CONFIG_MMU
-#include "ptrace_mm.c"
-#else
-#include "ptrace_no.c"
+void user_enable_block_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T0_BIT);
+}
 #endif
+
+void user_disable_single_step(struct task_struct *child)
+{
+       singlestep_disable(child);
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+                unsigned long addr, unsigned long data)
+{
+       unsigned long tmp;
+       int i, ret = 0;
+       int regno = addr >> 2; /* temporary hack. */
+       unsigned long __user *datap = (unsigned long __user *) data;
+
+       switch (request) {
+       /* read the word at location addr in the USER area. */
+       case PTRACE_PEEKUSR:
+               if (addr & 3)
+                       goto out_eio;
+
+               if (regno >= 0 && regno < 19) {
+                       tmp = get_reg(child, regno);
+               } else if (regno >= 21 && regno < 49) {
+                       tmp = child->thread.fp[regno - 21];
+                       /* Convert internal fpu reg representation
+                        * into long double format
+                        */
+                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
+                               tmp = ((tmp & 0xffff0000) << 15) |
+                                     ((tmp & 0x0000ffff) << 16);
+#ifndef CONFIG_MMU
+               } else if (regno == 49) {
+                       tmp = child->mm->start_code;
+               } else if (regno == 50) {
+                       tmp = child->mm->start_data;
+               } else if (regno == 51) {
+                       tmp = child->mm->end_code;
+#endif
+               } else
+                       goto out_eio;
+               ret = put_user(tmp, datap);
+               break;
+
+       case PTRACE_POKEUSR:
+       /* write the word at location addr in the USER area */
+               if (addr & 3)
+                       goto out_eio;
+
+               if (regno == PT_SR) {
+                       data &= SR_MASK;
+                       data |= get_reg(child, PT_SR) & ~SR_MASK;
+               }
+               if (regno >= 0 && regno < 19) {
+                       if (put_reg(child, regno, data))
+                               goto out_eio;
+               } else if (regno >= 21 && regno < 48) {
+                       /* Convert long double format
+                        * into internal fpu reg representation
+                        */
+                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
+                               data <<= 15;
+                               data = (data & 0xffff0000) |
+                                      ((data & 0x0000ffff) >> 1);
+                       }
+                       child->thread.fp[regno - 21] = data;
+               } else
+                       goto out_eio;
+               break;
+
+       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
+               for (i = 0; i < 19; i++) {
+                       tmp = get_reg(child, i);
+                       ret = put_user(tmp, datap);
+                       if (ret)
+                               break;
+                       datap++;
+               }
+               break;
+
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               for (i = 0; i < 19; i++) {
+                       ret = get_user(tmp, datap);
+                       if (ret)
+                               break;
+                       if (i == PT_SR) {
+                               tmp &= SR_MASK;
+                               tmp |= get_reg(child, PT_SR) & ~SR_MASK;
+                       }
+                       put_reg(child, i, tmp);
+                       datap++;
+               }
+               break;
+
+       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
+               if (copy_to_user(datap, &child->thread.fp,
+                                sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
+               if (copy_from_user(&child->thread.fp, datap,
+                                  sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(task_thread_info(child)->tp_value, datap);
+               break;
+
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       }
+
+       return ret;
+out_eio:
+       return -EIO;
+}
+
+asmlinkage void syscall_trace(void)
+{
+       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+                                ? 0x80 : 0));
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
+
+#ifdef CONFIG_COLDFIRE
+asmlinkage int syscall_trace_enter(void)
+{
+       int ret = 0;
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(task_pt_regs(current));
+       return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(task_pt_regs(current), 0);
+}
+#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c
deleted file mode 100644 (file)
index 7bc999b..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file COPYING in the main directory of
- * this archive for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0xC000
-#define T1_BIT 0x8000
-#define T0_BIT 0x4000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
-                        - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static const int regoff[] = {
-       [0]     = PT_REG(d1),
-       [1]     = PT_REG(d2),
-       [2]     = PT_REG(d3),
-       [3]     = PT_REG(d4),
-       [4]     = PT_REG(d5),
-       [5]     = SW_REG(d6),
-       [6]     = SW_REG(d7),
-       [7]     = PT_REG(a0),
-       [8]     = PT_REG(a1),
-       [9]     = PT_REG(a2),
-       [10]    = SW_REG(a3),
-       [11]    = SW_REG(a4),
-       [12]    = SW_REG(a5),
-       [13]    = SW_REG(a6),
-       [14]    = PT_REG(d0),
-       [15]    = -1,
-       [16]    = PT_REG(orig_d0),
-       [17]    = PT_REG(sr),
-       [18]    = PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return 0;
-       /* Need to take stkadj into account. */
-       if (regno == PT_SR || regno == PT_PC) {
-               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-               addr = (unsigned long *) ((unsigned long)addr + stkadj);
-               /* The sr is actually a 16 bit register.  */
-               if (regno == PT_SR)
-                       return *(unsigned short *)addr;
-       }
-       return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-                         unsigned long data)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return -1;
-       /* Need to take stkadj into account. */
-       if (regno == PT_SR || regno == PT_PC) {
-               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-               addr = (unsigned long *) ((unsigned long)addr + stkadj);
-               /* The sr is actually a 16 bit register.  */
-               if (regno == PT_SR) {
-                       *(unsigned short *)addr = data;
-                       return 0;
-               }
-       }
-       *addr = data;
-       return 0;
-}
-
-/*
- * Make sure the single step bit is not set.
- */
-static inline void singlestep_disable(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp);
-       clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- */
-void ptrace_disable(struct task_struct *child)
-{
-       singlestep_disable(child);
-}
-
-void user_enable_single_step(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp | T1_BIT);
-       set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-void user_enable_block_step(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp | T0_BIT);
-}
-
-void user_disable_single_step(struct task_struct *child)
-{
-       singlestep_disable(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-                unsigned long addr, unsigned long data)
-{
-       unsigned long tmp;
-       int i, ret = 0;
-       int regno = addr >> 2; /* temporary hack. */
-       unsigned long __user *datap = (unsigned long __user *) data;
-
-       switch (request) {
-       /* read the word at location addr in the USER area. */
-       case PTRACE_PEEKUSR:
-               if (addr & 3)
-                       goto out_eio;
-
-               if (regno >= 0 && regno < 19) {
-                       tmp = get_reg(child, regno);
-               } else if (regno >= 21 && regno < 49) {
-                       tmp = child->thread.fp[regno - 21];
-                       /* Convert internal fpu reg representation
-                        * into long double format
-                        */
-                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
-                               tmp = ((tmp & 0xffff0000) << 15) |
-                                     ((tmp & 0x0000ffff) << 16);
-               } else
-                       goto out_eio;
-               ret = put_user(tmp, datap);
-               break;
-
-       case PTRACE_POKEUSR:
-       /* write the word at location addr in the USER area */
-               if (addr & 3)
-                       goto out_eio;
-
-               if (regno == PT_SR) {
-                       data &= SR_MASK;
-                       data |= get_reg(child, PT_SR) & ~SR_MASK;
-               }
-               if (regno >= 0 && regno < 19) {
-                       if (put_reg(child, regno, data))
-                               goto out_eio;
-               } else if (regno >= 21 && regno < 48) {
-                       /* Convert long double format
-                        * into internal fpu reg representation
-                        */
-                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
-                               data <<= 15;
-                               data = (data & 0xffff0000) |
-                                      ((data & 0x0000ffff) >> 1);
-                       }
-                       child->thread.fp[regno - 21] = data;
-               } else
-                       goto out_eio;
-               break;
-
-       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
-               for (i = 0; i < 19; i++) {
-                       tmp = get_reg(child, i);
-                       ret = put_user(tmp, datap);
-                       if (ret)
-                               break;
-                       datap++;
-               }
-               break;
-
-       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
-               for (i = 0; i < 19; i++) {
-                       ret = get_user(tmp, datap);
-                       if (ret)
-                               break;
-                       if (i == PT_SR) {
-                               tmp &= SR_MASK;
-                               tmp |= get_reg(child, PT_SR) & ~SR_MASK;
-                       }
-                       put_reg(child, i, tmp);
-                       datap++;
-               }
-               break;
-
-       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
-               if (copy_to_user(datap, &child->thread.fp,
-                                sizeof(struct user_m68kfp_struct)))
-                       ret = -EFAULT;
-               break;
-
-       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
-               if (copy_from_user(&child->thread.fp, datap,
-                                  sizeof(struct user_m68kfp_struct)))
-                       ret = -EFAULT;
-               break;
-
-       case PTRACE_GET_THREAD_AREA:
-               ret = put_user(task_thread_info(child)->tp_value, datap);
-               break;
-
-       default:
-               ret = ptrace_request(child, request, addr, data);
-               break;
-       }
-
-       return ret;
-out_eio:
-       return -EIO;
-}
-
-asmlinkage void syscall_trace(void)
-{
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                ? 0x80 : 0));
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
-}
-
-#ifdef CONFIG_COLDFIRE
-asmlinkage int syscall_trace_enter(void)
-{
-       int ret = 0;
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               ret = tracehook_report_syscall_entry(task_pt_regs(current));
-       return ret;
-}
-
-asmlinkage void syscall_trace_leave(void)
-{
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               tracehook_report_syscall_exit(task_pt_regs(current), 0);
-}
-#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c
deleted file mode 100644 (file)
index 6709fb7..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file COPYING in the main directory of
- * this archive for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0x8000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
-                        - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static int regoff[] = {
-       PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
-       PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
-       PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
-       SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
-       PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return 0;
-       return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-                         unsigned long data)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
-       else
-               return -1;
-       *addr = data;
-       return 0;
-}
-
-void user_enable_single_step(struct task_struct *task)
-{
-       unsigned long srflags;
-       srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
-       put_reg(task, PT_SR, srflags);
-}
-
-void user_disable_single_step(struct task_struct *task)
-{
-       unsigned long srflags;
-       srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
-       put_reg(task, PT_SR, srflags);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-       /* make sure the single step bit is not set. */
-       user_disable_single_step(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-                unsigned long addr, unsigned long data)
-{
-       int ret;
-       int regno = addr >> 2;
-       unsigned long __user *datap = (unsigned long __user *) data;
-
-       switch (request) {
-               /* read the word at location addr in the USER area. */
-               case PTRACE_PEEKUSR: {
-                       unsigned long tmp;
-                       
-                       ret = -EIO;
-                       if ((addr & 3) || addr > sizeof(struct user) - 3)
-                               break;
-                       
-                       tmp = 0;  /* Default return condition */
-                       ret = -EIO;
-                       if (regno < 19) {
-                               tmp = get_reg(child, regno);
-                               if (regno == PT_SR)
-                                       tmp >>= 16;
-                       } else if (regno >= 21 && regno < 49) {
-                               tmp = child->thread.fp[regno - 21];
-                       } else if (regno == 49) {
-                               tmp = child->mm->start_code;
-                       } else if (regno == 50) {
-                               tmp = child->mm->start_data;
-                       } else if (regno == 51) {
-                               tmp = child->mm->end_code;
-                       } else
-                               break;
-                       ret = put_user(tmp, datap);
-                       break;
-               }
-
-               case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-                       ret = -EIO;
-                       if ((addr & 3) || addr > sizeof(struct user) - 3)
-                               break;
-
-                       if (regno == PT_SR) {
-                               data &= SR_MASK;
-                               data <<= 16;
-                               data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                       }
-                       if (regno < 19) {
-                               if (put_reg(child, regno, data))
-                                       break;
-                               ret = 0;
-                               break;
-                       }
-                       if (regno >= 21 && regno < 48)
-                       {
-                               child->thread.fp[regno - 21] = data;
-                               ret = 0;
-                       }
-                       break;
-
-               case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           tmp = get_reg(child, i);
-                           if (i == PT_SR)
-                               tmp >>= 16;
-                           if (put_user(tmp, datap)) {
-                               ret = -EFAULT;
-                               break;
-                           }
-                           datap++;
-                       }
-                       ret = 0;
-                       break;
-               }
-
-               case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           if (get_user(tmp, datap)) {
-                               ret = -EFAULT;
-                               break;
-                           }
-                           if (i == PT_SR) {
-                               tmp &= SR_MASK;
-                               tmp <<= 16;
-                               tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                           }
-                           put_reg(child, i, tmp);
-                           datap++;
-                       }
-                       ret = 0;
-                       break;
-               }
-
-#ifdef PTRACE_GETFPREGS
-               case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-                       ret = 0;
-                       if (copy_to_user(datap, &child->thread.fp,
-                                        sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-#endif
-
-#ifdef PTRACE_SETFPREGS
-               case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-                       ret = 0;
-                       if (copy_from_user(&child->thread.fp, datap,
-                                          sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-#endif
-
-       case PTRACE_GET_THREAD_AREA:
-               ret = put_user(task_thread_info(child)->tp_value, datap);
-               break;
-
-               default:
-                       ret = ptrace_request(child, request, addr, data);
-                       break;
-       }
-       return ret;
-}
-
-asmlinkage int syscall_trace_enter(void)
-{
-       int ret = 0;
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               ret = tracehook_report_syscall_entry(task_pt_regs(current));
-       return ret;
-}
-
-asmlinkage void syscall_trace_leave(void)
-{
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               tracehook_report_syscall_exit(task_pt_regs(current), 0);
-}
index ca3df0d..7dc186b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/initrd.h>
 #include <linux/root_dev.h>
+#include <linux/rtc.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -47,7 +48,9 @@ EXPORT_SYMBOL(memory_end);
 char __initdata command_line[COMMAND_LINE_SIZE];
 
 /* machine dependent timer functions */
+void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL;
 int (*mach_set_clock_mmss)(unsigned long);
+int (*mach_hwclk) (int, struct rtc_time*);
 
 /* machine dependent reboot functions */
 void (*mach_reset)(void);
index 75ab79b..d7deb7f 100644 (file)
@@ -1,5 +1,111 @@
-#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE)
-#include "time_mm.c"
-#else
-#include "time_no.c"
-#endif
+/*
+ *  linux/arch/m68k/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the m68k-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/irq_regs.h>
+
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "xtime_update()" routine every clocktick
+ */
+static irqreturn_t timer_interrupt(int irq, void *dummy)
+{
+       xtime_update(1);
+       update_process_times(user_mode(get_irq_regs()));
+       profile_tick(CPU_PROFILING);
+
+#ifdef CONFIG_HEARTBEAT
+       /* use power LED as a heartbeat instead -- much more useful
+          for debugging -- based on the version for PReP by Cort */
+       /* acts like an actual heart beat -- ie thump-thump-pause... */
+       if (mach_heartbeat) {
+           static unsigned cnt = 0, period = 0, dist = 0;
+
+           if (cnt == 0 || cnt == dist)
+               mach_heartbeat( 1 );
+           else if (cnt == 7 || cnt == dist+7)
+               mach_heartbeat( 0 );
+
+           if (++cnt > period) {
+               cnt = 0;
+               /* The hyperbolic function below modifies the heartbeat period
+                * length in dependency of the current (5min) load. It goes
+                * through the points f(0)=126, f(1)=86, f(5)=51,
+                * f(inf)->30. */
+               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+               dist = period / 4;
+           }
+       }
+#endif /* CONFIG_HEARTBEAT */
+       return IRQ_HANDLED;
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+       struct rtc_time time;
+       ts->tv_sec = 0;
+       ts->tv_nsec = 0;
+
+       if (mach_hwclk) {
+               mach_hwclk(0, &time);
+
+               if ((time.tm_year += 1900) < 1970)
+                       time.tm_year += 100;
+               ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
+                                     time.tm_hour, time.tm_min, time.tm_sec);
+       }
+}
+
+void __init time_init(void)
+{
+       mach_sched_init(timer_interrupt);
+}
+
+#ifdef CONFIG_M68KCLASSIC
+
+u32 arch_gettimeoffset(void)
+{
+       return mach_gettimeoffset() * 1000;
+}
+
+static int __init rtc_init(void)
+{
+       struct platform_device *pdev;
+
+       if (!mach_hwclk)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
+}
+
+module_init(rtc_init);
+
+#endif /* CONFIG_M68KCLASSIC */
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c
deleted file mode 100644 (file)
index 18b34ee..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *  linux/arch/m68k/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/rtc.h>
-#include <linux/platform_device.h>
-
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/irq_regs.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/profile.h>
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-  if (mach_set_clock_mmss)
-    return mach_set_clock_mmss (nowtime);
-  return -1;
-}
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-static irqreturn_t timer_interrupt(int irq, void *dummy)
-{
-       xtime_update(1);
-       update_process_times(user_mode(get_irq_regs()));
-       profile_tick(CPU_PROFILING);
-
-#ifdef CONFIG_HEARTBEAT
-       /* use power LED as a heartbeat instead -- much more useful
-          for debugging -- based on the version for PReP by Cort */
-       /* acts like an actual heart beat -- ie thump-thump-pause... */
-       if (mach_heartbeat) {
-           static unsigned cnt = 0, period = 0, dist = 0;
-
-           if (cnt == 0 || cnt == dist)
-               mach_heartbeat( 1 );
-           else if (cnt == 7 || cnt == dist+7)
-               mach_heartbeat( 0 );
-
-           if (++cnt > period) {
-               cnt = 0;
-               /* The hyperbolic function below modifies the heartbeat period
-                * length in dependency of the current (5min) load. It goes
-                * through the points f(0)=126, f(1)=86, f(5)=51,
-                * f(inf)->30. */
-               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
-               dist = period / 4;
-           }
-       }
-#endif /* CONFIG_HEARTBEAT */
-       return IRQ_HANDLED;
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-       struct rtc_time time;
-       ts->tv_sec = 0;
-       ts->tv_nsec = 0;
-
-       if (mach_hwclk) {
-               mach_hwclk(0, &time);
-
-               if ((time.tm_year += 1900) < 1970)
-                       time.tm_year += 100;
-               ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
-                                     time.tm_hour, time.tm_min, time.tm_sec);
-       }
-}
-
-void __init time_init(void)
-{
-       mach_sched_init(timer_interrupt);
-}
-
-u32 arch_gettimeoffset(void)
-{
-       return mach_gettimeoffset() * 1000;
-}
-
-static int __init rtc_init(void)
-{
-       struct platform_device *pdev;
-
-       if (!mach_hwclk)
-               return -ENODEV;
-
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-
-       return 0;
-}
-
-module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c
deleted file mode 100644 (file)
index 3ef0f77..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/profile.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/machdep.h>
-#include <asm/irq_regs.h>
-
-#define        TICK_SIZE (tick_nsec / 1000)
-
-/* machine dependent timer functions */
-void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-       if (mach_set_clock_mmss)
-               return mach_set_clock_mmss (nowtime);
-       return -1;
-}
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-irqreturn_t arch_timer_interrupt(int irq, void *dummy)
-{
-
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-
-       xtime_update(1);
-
-       update_process_times(user_mode(get_irq_regs()));
-
-       return(IRQ_HANDLED);
-}
-#endif
-
-static unsigned long read_rtc_mmss(void)
-{
-       unsigned int year, mon, day, hour, min, sec;
-
-       if (mach_gettod) {
-               mach_gettod(&year, &mon, &day, &hour, &min, &sec);
-               if ((year += 1900) < 1970)
-                       year += 100;
-       } else {
-               year = 1970;
-               mon = day = 1;
-               hour = min = sec = 0;
-       }
-
-
-       return  mktime(year, mon, day, hour, min, sec);
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-       ts->tv_sec = read_rtc_mmss();
-       ts->tv_nsec = 0;
-}
-
-int update_persistent_clock(struct timespec now)
-{
-       return set_rtc_mmss(now.tv_sec);
-}
-
-void time_init(void)
-{
-       hw_timer_init();
-}
index 8e66ccb..40e02d9 100644 (file)
 /*
  *     vmlinux.lds.S -- master linker script for m68knommu arch
  *
- *     (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
+ *     (C) Copyright 2002-2012, Greg Ungerer <gerg@snapgear.com>
  *
  *     This linker script is equipped to build either ROM loaded or RAM
  *     run kernels.
  */
 
-#include <asm-generic/vmlinux.lds.h>
-#include <asm/page.h>
-#include <asm/thread_info.h>
-
 #if defined(CONFIG_RAMKERNEL)
-#define        RAM_START       CONFIG_KERNELBASE
-#define        RAM_LENGTH      (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
-#define        TEXT            ram
-#define        DATA            ram
-#define        INIT            ram
-#define        BSSS            ram
-#endif
-#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
-#define        RAM_START       CONFIG_RAMBASE
-#define        RAM_LENGTH      CONFIG_RAMSIZE
-#define        ROMVEC_START    CONFIG_ROMVEC
-#define        ROMVEC_LENGTH   CONFIG_ROMVECSIZE
-#define        ROM_START       CONFIG_ROMSTART
-#define        ROM_LENGTH      CONFIG_ROMSIZE
-#define        TEXT            rom
-#define        DATA            ram
-#define        INIT            ram
-#define        BSSS            ram
+#define        KTEXT_ADDR      CONFIG_KERNELBASE
 #endif
-
-#ifndef DATA_ADDR
-#define        DATA_ADDR
+#if defined(CONFIG_ROMKERNEL)
+#define        KTEXT_ADDR      CONFIG_ROMSTART
+#define        KDATA_ADDR      CONFIG_KERNELBASE
+#define        LOAD_OFFSET     KDATA_ADDR + (ADDR(.text) + SIZEOF(.text))
 #endif
 
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm-generic/vmlinux.lds.h>
 
 OUTPUT_ARCH(m68k)
 ENTRY(_start)
 
-MEMORY {
-       ram     : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
-#ifdef ROM_START
-       romvec  : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
-       rom     : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
-#endif
-}
-
 jiffies = jiffies_64 + 4;
 
 SECTIONS {
 
-#ifdef ROMVEC_START
-       . = ROMVEC_START ;
+#ifdef CONFIG_ROMVEC
+       . = CONFIG_ROMVEC;
        .romvec : {
-               __rom_start = . ;
+               __rom_start = .;
                _romvec = .;
+               *(.romvec)
                *(.data..initvect)
-       } > romvec
+       }
 #endif
 
+       . = KTEXT_ADDR;
+
+       _text = .;
+       _stext = .;
        .text : {
-               _text = .;
-               _stext = . ;
                HEAD_TEXT
                TEXT_TEXT
                SCHED_TEXT
                LOCK_TEXT
-               *(.text..lock)
                *(.fixup)
+               . = ALIGN(16);
+       }
+       _etext = .;
+
+#ifdef KDATA_ADDR
+       . = KDATA_ADDR;
+#endif
+
+       _sdata = .;
+       RO_DATA_SECTION(PAGE_SIZE)
+       RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
+       _edata = .;
 
-               . = ALIGN(16);          /* Exception table              */
-               __start___ex_table = .;
-               *(__ex_table)
-               __stop___ex_table = .;
-
-               *(.rodata) *(.rodata.*)
-               *(__vermagic)           /* Kernel version magic */
-               *(.rodata1)
-               *(.rodata.str1.1)
-
-               /* Kernel symbol table: Normal symbols */
-               . = ALIGN(4);
-               __start___ksymtab = .;
-               *(SORT(___ksymtab+*))
-               __stop___ksymtab = .;
-
-               /* Kernel symbol table: GPL-only symbols */
-               __start___ksymtab_gpl = .;
-               *(SORT(___ksymtab_gpl+*))
-               __stop___ksymtab_gpl = .;
-
-               /* Kernel symbol table: Normal unused symbols */
-               __start___ksymtab_unused = .;
-               *(SORT(___ksymtab_unused+*))
-               __stop___ksymtab_unused = .;
-
-               /* Kernel symbol table: GPL-only unused symbols */
-               __start___ksymtab_unused_gpl = .;
-               *(SORT(___ksymtab_unused_gpl+*))
-               __stop___ksymtab_unused_gpl = .;
-
-               /* Kernel symbol table: GPL-future symbols */
-               __start___ksymtab_gpl_future = .;
-               *(SORT(___ksymtab_gpl_future+*))
-               __stop___ksymtab_gpl_future = .;
-
-               /* Kernel symbol table: Normal symbols */
-               __start___kcrctab = .;
-               *(SORT(___kcrctab+*))
-               __stop___kcrctab = .;
-
-               /* Kernel symbol table: GPL-only symbols */
-               __start___kcrctab_gpl = .;
-               *(SORT(___kcrctab_gpl+*))
-               __stop___kcrctab_gpl = .;
-
-               /* Kernel symbol table: Normal unused symbols */
-               __start___kcrctab_unused = .;
-               *(SORT(___kcrctab_unused+*))
-               __stop___kcrctab_unused = .;
-
-               /* Kernel symbol table: GPL-only unused symbols */
-               __start___kcrctab_unused_gpl = .;
-               *(SORT(___kcrctab_unused_gpl+*))
-               __stop___kcrctab_unused_gpl = .;
-
-               /* Kernel symbol table: GPL-future symbols */
-               __start___kcrctab_gpl_future = .;
-               *(SORT(___kcrctab_gpl_future+*))
-               __stop___kcrctab_gpl_future = .;
-
-               /* Kernel symbol table: strings */
-               *(__ksymtab_strings)
-
-               /* Built-in module parameters */
-               . = ALIGN(4) ;
-               __start___param = .;
-               *(__param)
-               __stop___param = .;
-
-               /* Built-in module versions */
-               . = ALIGN(4) ;
-               __start___modver = .;
-               *(__modver)
-               __stop___modver = .;
-
-               . = ALIGN(4) ;
-               _etext = . ;
-       } > TEXT
-
-       .data DATA_ADDR : {
-               . = ALIGN(4);
-               _sdata = . ;
-               DATA_DATA
-               CACHELINE_ALIGNED_DATA(32)
-               PAGE_ALIGNED_DATA(PAGE_SIZE)
-               *(.data..shared_aligned)
-               INIT_TASK_DATA(THREAD_SIZE)
-               _edata = . ;
-       } > DATA
+       EXCEPTION_TABLE(16)
+       NOTES
 
+       . = ALIGN(PAGE_SIZE);
+       __init_begin = .;
+       INIT_TEXT_SECTION(PAGE_SIZE)
+       INIT_DATA_SECTION(16)
+       PERCPU_SECTION(16)
        .m68k_fixup : {
                __start_fixup = .;
                *(.m68k_fixup)
                __stop_fixup = .;
-       } > DATA
-       NOTES > DATA
-
-       .init.text : {
-               . = ALIGN(PAGE_SIZE);
-               __init_begin = .;
-       } > INIT
-       INIT_TEXT_SECTION(PAGE_SIZE) > INIT
-       INIT_DATA_SECTION(16) > INIT
+       }
        .init.data : {
                . = ALIGN(PAGE_SIZE);
                __init_end = .;
-       } > INIT
-
-       .bss : {
-               . = ALIGN(4);
-               _sbss = . ;
-               *(.bss)
-               *(COMMON)
-               . = ALIGN(4) ;
-               _ebss = . ;
-               _end = . ;
-       } > BSSS
+       }
+
+       _sbss = .;
+       BSS_SECTION(0, 0, 0)
+       _ebss = .;
+
+       _end = .;
+
+       STABS_DEBUG
+       .comment 0 : { *(.comment) }
 
+       /* Sections to be discarded */
        DISCARDS
 }
 
index 6fa3f80..6bfbeeb 100644 (file)
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5206_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5206_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5206_uart_platform,
-};
-
-static struct platform_device *m5206_devices[] __initdata = {
-       &m5206_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5206_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5206_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5206_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5206_uart_init_line(line, m5206_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5206_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5206_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
 
 /***************************************************************************/
 
@@ -104,9 +27,7 @@ void __init config_BSP(char *commandp, int size)
        commandp[size-1] = 0;
 #endif /* CONFIG_NETtel */
 
-       mach_reset = m5206_cpu_reset;
-       m5206_timers_init();
-       m5206_uarts_init();
+       mach_sched_init = hw_timer_init;
 
        /* Only support the external interrupts on their primary level */
        mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -115,13 +36,3 @@ void __init config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index 8a98683..2359478 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m520x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m520x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m520x_uart_platform,
-};
-
-static struct resource m520x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 36,
-               .end            = 64 + 36,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 40,
-               .end            = 64 + 40,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 42,
-               .end            = 64 + 42,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m520x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m520x_fec_resources),
-       .resource               = m520x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m520x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    46
-#define MCFQSPI_CS1    47
-#define MCFQSPI_CS2    27
-
-static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m520x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       }
-}
-
-static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m520x_cs_control = {
-       .setup                  = m520x_cs_setup,
-       .teardown               = m520x_cs_teardown,
-       .select                 = m520x_cs_select,
-       .deselect               = m520x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m520x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 3,
-       .cs_control             = &m520x_cs_control,
-};
-
-static struct platform_device m520x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m520x_qspi_resources),
-       .resource               = m520x_qspi_resources,
-       .dev.platform_data      = &m520x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m520x_qspi_init(void)
 {
@@ -214,54 +34,28 @@ static void __init m520x_qspi_init(void)
        par &= 0x00ff;
        writew(par, MCF_GPIO_PAR_UART);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
 
-static struct platform_device *m520x_devices[] __initdata = {
-       &m520x_uart,
-       &m520x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m520x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m520x_uart_init_line(int line, int irq)
+static void __init m520x_uarts_init(void)
 {
        u16 par;
        u8 par2;
 
-       switch (line) {
-       case 0:
-               par = readw(MCF_GPIO_PAR_UART);
-               par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
-                      MCF_GPIO_PAR_UART_PAR_URXD0;
-               writew(par, MCF_GPIO_PAR_UART);
-               break;
-       case 1:
-               par = readw(MCF_GPIO_PAR_UART);
-               par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
-                      MCF_GPIO_PAR_UART_PAR_URXD1;
-               writew(par, MCF_GPIO_PAR_UART);
-               break;
-       case 2:
-               par2 = readb(MCF_GPIO_PAR_FECI2C);
-               par2 &= ~0x0F;
-               par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
-                       MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-               writeb(par2, MCF_GPIO_PAR_FECI2C);
-               break;
-       }
-}
-
-static void __init m520x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m520x_uart_platform);
-       int line;
+       /* UART0 and UART1 GPIO pin setup */
+       par = readw(MCF_GPIO_PAR_UART);
+       par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0;
+       par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1;
+       writew(par, MCF_GPIO_PAR_UART);
 
-       for (line = 0; (line < nrlines); line++)
-               m520x_uart_init_line(line, m520x_uart_platform[line].irq);
+       /* UART1 GPIO pin setup */
+       par2 = readb(MCF_GPIO_PAR_FECI2C);
+       par2 &= ~0x0F;
+       par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
+               MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+       writeb(par2, MCF_GPIO_PAR_FECI2C);
 }
 
 /***************************************************************************/
@@ -280,32 +74,14 @@ static void __init m520x_fec_init(void)
 
 /***************************************************************************/
 
-static void m520x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-       mach_reset = m520x_cpu_reset;
+       mach_sched_init = hw_timer_init;
        m520x_uarts_init();
        m520x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
        m520x_qspi_init();
 #endif
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index 71f4436..c8b405d 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m523x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
-       },
-       { },
-};
-
-static struct platform_device m523x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m523x_uart_platform,
-};
-
-static struct resource m523x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m523x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m523x_fec_resources),
-       .resource               = m523x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m523x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    103
-#define MCFQSPI_CS3    99
-
-static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m523x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m523x_cs_control = {
-       .setup                  = m523x_cs_setup,
-       .teardown               = m523x_cs_teardown,
-       .select                 = m523x_cs_select,
-       .deselect               = m523x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m523x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m523x_cs_control,
-};
-
-static struct platform_device m523x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m523x_qspi_resources),
-       .resource               = m523x_qspi_resources,
-       .dev.platform_data      = &m523x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m523x_qspi_init(void)
 {
@@ -237,15 +35,8 @@ static void __init m523x_qspi_init(void)
        par &= 0x3f3f;
        writew(par, MCFGPIO_PAR_TIMER);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m523x_devices[] __initdata = {
-       &m523x_uart,
-       &m523x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m523x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
@@ -263,31 +54,13 @@ static void __init m523x_fec_init(void)
 
 /***************************************************************************/
 
-static void m523x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-       mach_reset = m523x_cpu_reset;
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
+       mach_sched_init = hw_timer_init;
        m523x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
        m523x_qspi_init();
 #endif
-       platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
-       return 0;
 }
 
-arch_initcall(init_BSP);
-
 /***************************************************************************/
index ceb31e5..bbf0513 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
+#include <linux/platform_device.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5249_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5249_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5249_uart_platform,
-};
-
 #ifdef CONFIG_M5249C3
 
 static struct resource m5249_smc91x_resources[] = {
@@ -64,153 +43,15 @@ static struct platform_device m5249_smc91x = {
 
 #endif /* CONFIG_M5249C3 */
 
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m5249_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_QSPI,
-               .end            = MCF_IRQ_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    29
-#define MCFQSPI_CS1    24
-#define MCFQSPI_CS2    21
-#define MCFQSPI_CS3    22
-
-static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m5249_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m5249_cs_control = {
-       .setup                  = m5249_cs_setup,
-       .teardown               = m5249_cs_teardown,
-       .select                 = m5249_cs_select,
-       .deselect               = m5249_cs_deselect,
+static struct platform_device *m5249_devices[] __initdata = {
+#ifdef CONFIG_M5249C3
+       &m5249_smc91x,
+#endif
 };
 
-static struct mcfqspi_platform_data m5249_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m5249_cs_control,
-};
+/***************************************************************************/
 
-static struct platform_device m5249_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5249_qspi_resources),
-       .resource               = m5249_qspi_resources,
-       .dev.platform_data      = &m5249_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m5249_qspi_init(void)
 {
@@ -219,42 +60,8 @@ static void __init m5249_qspi_init(void)
               MCF_MBAR + MCFSIM_QSPIICR);
        mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-
-static struct platform_device *m5249_devices[] __initdata = {
-       &m5249_uart,
-#ifdef CONFIG_M5249C3
-       &m5249_smc91x,
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m5249_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m5249_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5249_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5249_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5249_uart_init_line(line, m5249_uart_platform[line].irq);
-}
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
@@ -276,43 +83,14 @@ static void __init m5249_smc91x_init(void)
 
 /***************************************************************************/
 
-static void __init m5249_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5249_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-       mach_reset = m5249_cpu_reset;
-       m5249_timers_init();
-       m5249_uarts_init();
+       mach_sched_init = hw_timer_init;
+
 #ifdef CONFIG_M5249C3
        m5249_smc91x_init();
 #endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
        m5249_qspi_init();
 #endif
 }
index 65bb582..e68bc7a 100644 (file)
@@ -30,84 +30,18 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5272_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = MCF_IRQ_UART1,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = MCF_IRQ_UART2,
-       },
-       { },
-};
-
-static struct platform_device m5272_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5272_uart_platform,
-};
-
-static struct resource m5272_fec_resources[] = {
-       {
-               .start          = MCF_MBAR + 0x840,
-               .end            = MCF_MBAR + 0x840 + 0x1cf,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_ERX,
-               .end            = MCF_IRQ_ERX,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_ETX,
-               .end            = MCF_IRQ_ETX,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_ENTC,
-               .end            = MCF_IRQ_ENTC,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m5272_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5272_fec_resources),
-       .resource               = m5272_fec_resources,
-};
-
-static struct platform_device *m5272_devices[] __initdata = {
-       &m5272_uart,
-       &m5272_fec,
-};
-
-/***************************************************************************/
-
-static void __init m5272_uart_init_line(int line, int irq)
+static void __init m5272_uarts_init(void)
 {
        u32 v;
 
-       if ((line >= 0) && (line < 2)) {
-               /* Enable the output lines for the serial ports */
-               v = readl(MCF_MBAR + MCFSIM_PBCNT);
-               v = (v & ~0x000000ff) | 0x00000055;
-               writel(v, MCF_MBAR + MCFSIM_PBCNT);
-
-               v = readl(MCF_MBAR + MCFSIM_PDCNT);
-               v = (v & ~0x000003fc) | 0x000002a8;
-               writel(v, MCF_MBAR + MCFSIM_PDCNT);
-       }
-}
-
-static void __init m5272_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5272_uart_platform);
-       int line;
+       /* Enable the output lines for the serial ports */
+       v = readl(MCF_MBAR + MCFSIM_PBCNT);
+       v = (v & ~0x000000ff) | 0x00000055;
+       writel(v, MCF_MBAR + MCFSIM_PBCNT);
 
-       for (line = 0; (line < nrlines); line++)
-               m5272_uart_init_line(line, m5272_uart_platform[line].irq);
+       v = readl(MCF_MBAR + MCFSIM_PDCNT);
+       v = (v & ~0x000003fc) | 0x000002a8;
+       writel(v, MCF_MBAR + MCFSIM_PDCNT);
 }
 
 /***************************************************************************/
@@ -146,6 +80,7 @@ void __init config_BSP(char *commandp, int size)
 #endif
 
        mach_reset = m5272_cpu_reset;
+       mach_sched_init = hw_timer_init;
 }
 
 /***************************************************************************/
@@ -167,7 +102,6 @@ static int __init init_BSP(void)
 {
        m5272_uarts_init();
        fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
-       platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
        return 0;
 }
 
index 3ebc769..7ed848c 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m527x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m527x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m527x_uart_platform,
-};
-
-static struct resource m527x_fec0_resources[] = {
-       {
-               .start          = MCFFEC_BASE0,
-               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource m527x_fec1_resources[] = {
-       {
-               .start          = MCFFEC_BASE1,
-               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 128 + 23,
-               .end            = 128 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 128 + 27,
-               .end            = 128 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 128 + 29,
-               .end            = 128 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m527x_fec[] = {
-       {
-               .name           = "fec",
-               .id             = 0,
-               .num_resources  = ARRAY_SIZE(m527x_fec0_resources),
-               .resource       = m527x_fec0_resources,
-       },
-       {
-               .name           = "fec",
-               .id             = 1,
-               .num_resources  = ARRAY_SIZE(m527x_fec1_resources),
-               .resource       = m527x_fec1_resources,
-       },
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m527x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#if defined(CONFIG_M5271)
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    99
-#define MCFQSPI_CS3    103
-#elif defined(CONFIG_M5275)
-#define MCFQSPI_CS0    59
-#define MCFQSPI_CS1    60
-#define MCFQSPI_CS2    61
-#define MCFQSPI_CS3    62
-#endif
-
-static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m527x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m527x_cs_control = {
-       .setup                  = m527x_cs_setup,
-       .teardown               = m527x_cs_teardown,
-       .select                 = m527x_cs_select,
-       .deselect               = m527x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m527x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m527x_cs_control,
-};
-
-static struct platform_device m527x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m527x_qspi_resources),
-       .resource               = m527x_qspi_resources,
-       .dev.platform_data      = &m527x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m527x_qspi_init(void)
 {
@@ -280,50 +41,23 @@ static void __init m527x_qspi_init(void)
        writew(0x003e, MCFGPIO_PAR_QSPI);
 #endif
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m527x_devices[] __initdata = {
-       &m527x_uart,
-       &m527x_fec[0],
-#ifdef CONFIG_FEC2
-       &m527x_fec[1],
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m527x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m527x_uart_init_line(int line, int irq)
+static void __init m527x_uarts_init(void)
 {
        u16 sepmask;
 
-       if ((line < 0) || (line > 2))
-               return;
-
        /*
         * External Pin Mask Setting & Enable External Pin for Interface
         */
        sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-       if (line == 0)
-               sepmask |= UART0_ENABLE_MASK;
-       else if (line == 1)
-               sepmask |= UART1_ENABLE_MASK;
-       else if (line == 2)
-               sepmask |= UART2_ENABLE_MASK;
+       sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK;
        writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
 }
 
-static void __init m527x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m527x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m527x_uart_init_line(line, m527x_uart_platform[line].irq);
-}
-
 /***************************************************************************/
 
 static void __init m527x_fec_init(void)
@@ -353,32 +87,14 @@ static void __init m527x_fec_init(void)
 
 /***************************************************************************/
 
-static void m527x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
-       mach_reset = m527x_cpu_reset;
+       mach_sched_init = hw_timer_init;
        m527x_uarts_init();
        m527x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
        m527x_qspi_init();
 #endif
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index 7abe77a..d449292 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m528x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
-       },
-       { },
-};
-
-static struct platform_device m528x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m528x_uart_platform,
-};
-
-static struct resource m528x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m528x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m528x_fec_resources),
-       .resource               = m528x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m528x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    147
-#define MCFQSPI_CS1    148
-#define MCFQSPI_CS2    149
-#define MCFQSPI_CS3    150
-
-static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m528x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m528x_cs_control = {
-       .setup                  = m528x_cs_setup,
-       .teardown               = m528x_cs_teardown,
-       .select                 = m528x_cs_select,
-       .deselect               = m528x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m528x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m528x_cs_control,
-};
-
-static struct platform_device m528x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m528x_qspi_resources),
-       .resource               = m528x_qspi_resources,
-       .dev.platform_data      = &m528x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m528x_qspi_init(void)
 {
        /* setup Port QS for QSPI with gpio CS control */
        __raw_writeb(0x07, MCFGPIO_PQSPAR);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-static struct platform_device *m528x_devices[] __initdata = {
-       &m528x_uart,
-       &m528x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m528x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m528x_uart_init_line(int line, int irq)
+static void __init m528x_uarts_init(void)
 {
        u8 port;
 
-       if ((line < 0) || (line > 2))
-               return;
-
        /* make sure PUAPAR is set for UART0 and UART1 */
-       if (line < 2) {
-               port = readb(MCF5282_GPIO_PUAPAR);
-               port |= (0x03 << (line * 2));
-               writeb(port, MCF5282_GPIO_PUAPAR);
-       }
-}
-
-static void __init m528x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m528x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m528x_uart_init_line(line, m528x_uart_platform[line].irq);
+       port = readb(MCF5282_GPIO_PUAPAR);
+       port |= 0x03 | (0x03 << 2);
+       writeb(port, MCF5282_GPIO_PUAPAR);
 }
 
 /***************************************************************************/
@@ -256,14 +60,6 @@ static void __init m528x_fec_init(void)
 
 /***************************************************************************/
 
-static void m528x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
 #ifdef CONFIG_WILDFIRE
 void wildfire_halt(void)
 {
@@ -299,22 +95,12 @@ void __init config_BSP(char *commandp, int size)
 #ifdef CONFIG_WILDFIREMOD
        mach_halt = wildfiremod_halt;
 #endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       mach_reset = m528x_cpu_reset;
+       mach_sched_init = hw_timer_init;
        m528x_uarts_init();
        m528x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
        m528x_qspi_init();
 #endif
-       platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
-       return 0;
 }
 
-arch_initcall(init_BSP);
-
 /***************************************************************************/
index 00900ac..a568d28 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
@@ -29,82 +28,6 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m5307_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5307_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5307_uart_platform,
-};
-
-static struct platform_device *m5307_devices[] __initdata = {
-       &m5307_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5307_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5307_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5307_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5307_uart_init_line(line, m5307_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5307_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5307_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
 #if defined(CONFIG_NETtel) || \
@@ -114,9 +37,7 @@ void __init config_BSP(char *commandp, int size)
        commandp[size-1] = 0;
 #endif
 
-       mach_reset = m5307_cpu_reset;
-       m5307_timers_init();
-       m5307_uarts_init();
+       mach_sched_init = hw_timer_init;
 
        /* Only support the external interrupts on their primary level */
        mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -135,13 +56,3 @@ void __init config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index ca51323..2bec347 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
-#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m532x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m532x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m532x_uart_platform,
-};
-
-static struct resource m532x_fec_resources[] = {
-       {
-               .start          = 0xfc030000,
-               .end            = 0xfc0307ff,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 36,
-               .end            = 64 + 36,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 40,
-               .end            = 64 + 40,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 42,
-               .end            = 64 + 42,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m532x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m532x_fec_resources),
-       .resource               = m532x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m532x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    84
-#define MCFQSPI_CS1    85
-#define MCFQSPI_CS2    86
-
-static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m532x_cs_control = {
-       .setup                  = m532x_cs_setup,
-       .teardown               = m532x_cs_teardown,
-       .select                 = m532x_cs_select,
-       .deselect               = m532x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m532x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 3,
-       .cs_control             = &m532x_cs_control,
-};
-
-static struct platform_device m532x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m532x_qspi_resources),
-       .resource               = m532x_qspi_resources,
-       .dev.platform_data      = &m532x_qspi_data,
-};
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
 
 static void __init m532x_qspi_init(void)
 {
        /* setup QSPS pins for QSPI with gpio CS control */
        writew(0x01f0, MCF_GPIO_PAR_QSPI);
 }
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
 
-
-static struct platform_device *m532x_devices[] __initdata = {
-       &m532x_uart,
-       &m532x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m532x_qspi,
-#endif
-};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
 
 /***************************************************************************/
 
-static void __init m532x_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x000F;
-       } else if (line == 1) {
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x0FF0;
-       }
-}
-
 static void __init m532x_uarts_init(void)
 {
-       const int nrlines = ARRAY_SIZE(m532x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m532x_uart_init_line(line, m532x_uart_platform[line].irq);
+       /* UART GPIO initialization */
+       MCF_GPIO_PAR_UART |= 0x0FFF;
 }
+
 /***************************************************************************/
 
 static void __init m532x_fec_init(void)
@@ -242,14 +61,6 @@ static void __init m532x_fec_init(void)
 
 /***************************************************************************/
 
-static void m532x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
 void __init config_BSP(char *commandp, int size)
 {
 #if !defined(CONFIG_BOOTPARAM)
@@ -263,6 +74,13 @@ void __init config_BSP(char *commandp, int size)
        }
 #endif
 
+       mach_sched_init = hw_timer_init;
+       m532x_uarts_init();
+       m532x_fec_init();
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+       m532x_qspi_init();
+#endif
+
 #ifdef CONFIG_BDM_DISABLE
        /*
         * Disable the BDM clocking.  This also turns off most of the rest of
@@ -273,21 +91,6 @@ void __init config_BSP(char *commandp, int size)
 #endif
 }
 
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       m532x_uarts_init();
-       m532x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m532x_qspi_init();
-#endif
-       platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
 /***************************************************************************/
 /* Board initialization */
 /***************************************************************************/
index 70ea789..bb6c746 100644 (file)
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5407_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5407_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5407_uart_platform,
-};
-
-static struct platform_device *m5407_devices[] __initdata = {
-       &m5407_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5407_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5407_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5407_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5407_uart_init_line(line, m5407_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5407_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5407_cpu_reset(void)
-{
-       local_irq_disable();
-       /* set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
 
 /***************************************************************************/
 
 void __init config_BSP(char *commandp, int size)
 {
-       mach_reset = m5407_cpu_reset;
-       m5407_timers_init();
-       m5407_uarts_init();
+       mach_sched_init = hw_timer_init;
 
        /* Only support the external interrupts on their primary level */
        mcf_mapirq2imr(25, MCFINTC_EINT1);
@@ -110,13 +31,3 @@ void __init config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index ee04354..2081c6c 100644 (file)
 
 /***************************************************************************/
 
-static struct mcf_platform_uart m54xx_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 64 + 35,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 64 + 34,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE3,
-               .irq            = 64 + 33,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE4,
-               .irq            = 64 + 32,
-       },
-};
-
-static struct platform_device m54xx_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m54xx_uart_platform,
-};
-
-static struct platform_device *m54xx_devices[] __initdata = {
-       &m54xx_uart,
-};
-
-
-/***************************************************************************/
-
-static void __init m54xx_uart_init_line(int line, int irq)
-{
-       int rts_cts;
-
-       /* enable io pins */
-       switch (line) {
-       case 0:
-               rts_cts = 0; break;
-       case 1:
-               rts_cts = MCF_PAR_PSC_RTS_RTS; break;
-       case 2:
-               rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
-       case 3:
-               rts_cts = 0; break;
-       }
-       __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
-                                               MCF_MBAR + MCF_PAR_PSC(line));
-}
-
 static void __init m54xx_uarts_init(void)
 {
-       const int nrlines = ARRAY_SIZE(m54xx_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m54xx_uart_init_line(line, m54xx_uart_platform[line].irq);
+       /* enable io pins */
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD,
+               MCF_MBAR + MCF_PAR_PSC(0));
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS,
+               MCF_MBAR + MCF_PAR_PSC(1));
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS |
+               MCF_PAR_PSC_CTS_CTS, MCF_MBAR + MCF_PAR_PSC(2));
+       __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD,
+               MCF_MBAR + MCF_PAR_PSC(3));
 }
 
 /***************************************************************************/
@@ -145,18 +98,8 @@ void __init config_BSP(char *commandp, int size)
        mmu_context_init();
 #endif
        mach_reset = mcf54xx_reset;
+       mach_sched_init = hw_timer_init;
        m54xx_uarts_init();
 }
 
 /***************************************************************************/
-
-static int __init init_BSP(void)
-{
-
-       platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
index d70bf26..44b8665 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/rtc.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
 #include <asm/MC68328.h>
@@ -26,7 +27,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 
@@ -48,7 +49,7 @@ void config_BSP(char *command, int len)
   printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
   printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
 
-  mach_gettod = m68328_timer_gettod;
+  mach_hwclk = m68328_hwclk;
   mach_reset = m68328_reset;
 }
 
index 4bd4565..b3810fe 100644 (file)
@@ -68,8 +68,6 @@ asmlinkage irqreturn_t inthandler5(void);
 asmlinkage irqreturn_t inthandler6(void);
 asmlinkage irqreturn_t inthandler7(void);
 
-extern e_vector *_ramvec;
-
 /* The 68k family did not have a good way to determine the source
  * of interrupts until later in the family.  The EC000 core does
  * not provide the vector number on the stack, we vector everything
index f267886..b15ddef 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/clocksource.h>
+#include <linux/rtc.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -119,14 +120,17 @@ void hw_timer_init(void)
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec)
+int m68328_hwclk(int set, struct rtc_time *t)
 {
-       long now = RTCTIME;
-
-       *year = *mon = *day = 1;
-       *hour = (now >> 24) % 24;
-       *min = (now >> 16) % 60;
-       *sec = now % 60;
+       if (!set) {
+               long now = RTCTIME;
+               t->tm_year = t->tm_mon = t->tm_mday = 1;
+               t->tm_hour = (now >> 24) % 24;
+               t->tm_min = (now >> 16) % 60;
+               t->tm_sec = now % 60;
+       }
+
+       return 0;
 }
 
 /***************************************************************************/
index 9dd5bca..599a594 100644 (file)
@@ -103,11 +103,6 @@ void hw_timer_init(void)
   pquicc->timer_tgcr  = tgcr_save;
 }
 
-void BSP_gettod (int *yearp, int *monp, int *dayp,
-                  int *hourp, int *minp, int *secp)
-{
-}
-
 int BSP_set_clock_mmss(unsigned long nowtime)
 {
 #if 0
@@ -181,6 +176,5 @@ void config_BSP(char *command, int len)
   scc1_hwaddr = "\00\01\02\03\04\05";
 #endif
  
-  mach_gettod          = BSP_gettod;
-  mach_reset           = BSP_reset;
+  mach_reset = BSP_reset;
 }
index 7b40202..8cd4269 100644 (file)
@@ -32,8 +32,6 @@ asmlinkage void trap(void);
 asmlinkage void bad_interrupt(void);
 asmlinkage void inthandler(void);
 
-extern void *_ramvec[];
-
 static void intc_irq_unmask(struct irq_data *d)
 {
        pquicc->intr_cimr |= (1 << d->irq);
index 1be1a16..dd2c535 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/rtc.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
@@ -25,7 +26,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 
@@ -69,7 +70,7 @@ void config_BSP(char *command, int len)
   else command[0] = 0;
 #endif
  
-  mach_gettod = m68328_timer_gettod;
+  mach_hwclk = m68328_hwclk;
   mach_reset = m68ez328_reset;
 }
 
index eabaabe..25ec673 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/rtc.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -33,7 +34,7 @@
 
 /***************************************************************************/
 
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+int m68328_hwclk(int set, struct rtc_time *t);
 
 /***************************************************************************/
 /*                        Init Drangon Engine hardware                     */
@@ -181,7 +182,7 @@ void config_BSP(char *command, int size)
 
        init_hardware(command, size);
 
-       mach_gettod = m68328_timer_gettod;
+       mach_hwclk = m68328_hwclk;
        mach_reset = m68vz328_reset;
 }
 
index a8967ba..a0815c6 100644 (file)
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
 
-obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206)    += timers.o intc.o
-obj-$(CONFIG_M5206e)   += timers.o intc.o
-obj-$(CONFIG_M520x)    += pit.o intc-simr.o
-obj-$(CONFIG_M523x)    += pit.o dma_timer.o intc-2.o
-obj-$(CONFIG_M5249)    += timers.o intc.o
-obj-$(CONFIG_M527x)    += pit.o intc-2.o
+obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o
+obj-$(CONFIG_M5206)    += timers.o intc.o reset.o
+obj-$(CONFIG_M5206e)   += timers.o intc.o reset.o
+obj-$(CONFIG_M520x)    += pit.o intc-simr.o reset.o
+obj-$(CONFIG_M523x)    += pit.o dma_timer.o intc-2.o reset.o
+obj-$(CONFIG_M5249)    += timers.o intc.o reset.o
+obj-$(CONFIG_M527x)    += pit.o intc-2.o reset.o
 obj-$(CONFIG_M5272)    += timers.o
-obj-$(CONFIG_M528x)    += pit.o intc-2.o
-obj-$(CONFIG_M5307)    += timers.o intc.o
-obj-$(CONFIG_M532x)    += timers.o intc-simr.o
-obj-$(CONFIG_M5407)    += timers.o intc.o
+obj-$(CONFIG_M528x)    += pit.o intc-2.o reset.o
+obj-$(CONFIG_M5307)    += timers.o intc.o reset.o
+obj-$(CONFIG_M532x)    += timers.o intc-simr.o reset.o
+obj-$(CONFIG_M5407)    += timers.o intc.o reset.o
 obj-$(CONFIG_M54xx)    += sltimers.o intc-2.o
 
 obj-y                  += pinmux.o gpio.o
diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c
new file mode 100644 (file)
index 0000000..fa50c48
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * device.c  -- common ColdFire SoC device support
+ *
+ * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/*
+ *     All current ColdFire parts contain from 2, 3 or 4 UARTS.
+ */
+static struct mcf_platform_uart mcf_uart_platform_data[] = {
+       {
+               .mapbase        = MCFUART_BASE0,
+               .irq            = MCF_IRQ_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCF_IRQ_UART1,
+       },
+#ifdef MCFUART_BASE2
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCF_IRQ_UART2,
+       },
+#endif
+#ifdef MCFUART_BASE3
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCF_IRQ_UART3,
+       },
+#endif
+       { },
+};
+
+static struct platform_device mcf_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = mcf_uart_platform_data,
+};
+
+#ifdef CONFIG_FEC
+/*
+ *     Some ColdFire cores contain the Fast Ethernet Controller (FEC)
+ *     block. It is Freescale's own hardware block. Some ColdFires
+ *     have 2 of these.
+ */
+static struct resource mcf_fec0_resources[] = {
+       {
+               .start          = MCFFEC_BASE0,
+               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_FECRX0,
+               .end            = MCF_IRQ_FECRX0,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECTX0,
+               .end            = MCF_IRQ_FECTX0,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECENTC0,
+               .end            = MCF_IRQ_FECENTC0,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mcf_fec0 = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_fec0_resources),
+       .resource               = mcf_fec0_resources,
+};
+
+#ifdef MCFFEC_BASE1
+static struct resource mcf_fec1_resources[] = {
+       {
+               .start          = MCFFEC_BASE1,
+               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_FECRX1,
+               .end            = MCF_IRQ_FECRX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECTX1,
+               .end            = MCF_IRQ_FECTX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_FECENTC1,
+               .end            = MCF_IRQ_FECENTC1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mcf_fec1 = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_fec1_resources),
+       .resource               = mcf_fec1_resources,
+};
+#endif /* MCFFEC_BASE1 */
+#endif /* CONFIG_FEC */
+
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+/*
+ *     The ColdFire QSPI module is an SPI protocol hardware block used
+ *     on a number of different ColdFire CPUs.
+ */
+static struct resource mcf_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_BASE,
+               .end            = MCFQSPI_BASE + MCFQSPI_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_QSPI,
+               .end            = MCF_IRQ_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+#ifdef MCFQSPI_CS3
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               gpio_free(MCFQSPI_CS3);
+               goto fail3;
+       }
+#endif
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+#ifdef MCFQSPI_CS3
+       gpio_free(MCFQSPI_CS3);
+#endif
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
+                         u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+#ifdef MCFQSPI_CS3
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+#endif
+       }
+}
+
+static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+#ifdef MCFQSPI_CS3
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+#endif
+       }
+}
+
+static struct mcfqspi_cs_control mcf_cs_control = {
+       .setup                  = mcf_cs_setup,
+       .teardown               = mcf_cs_teardown,
+       .select                 = mcf_cs_select,
+       .deselect               = mcf_cs_deselect,
+};
+
+static struct mcfqspi_platform_data mcf_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &mcf_cs_control,
+};
+
+static struct platform_device mcf_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_qspi_resources),
+       .resource               = mcf_qspi_resources,
+       .dev.platform_data      = &mcf_qspi_data,
+};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
+
+static struct platform_device *mcf_devices[] __initdata = {
+       &mcf_uart,
+#ifdef CONFIG_FEC
+       &mcf_fec0,
+#ifdef MCFFEC_BASE1
+       &mcf_fec1,
+#endif
+#endif
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+       &mcf_qspi,
+#endif
+};
+
+/*
+ *     Some ColdFire UARTs let you set the IRQ line to use.
+ */
+static void __init mcf_uart_set_irq(void)
+{
+#ifdef MCFUART_UIVR
+       /* UART0 interrupt setup */
+       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+       writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
+       mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
+
+       /* UART1 interrupt setup */
+       writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+       writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
+       mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
+#endif
+}
+
+static int __init mcf_init_devices(void)
+{
+       mcf_uart_set_irq();
+       platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
+       return 0;
+}
+
+arch_initcall(mcf_init_devices);
+
index 38f04a3..c3db70e 100644 (file)
@@ -158,6 +158,10 @@ _start:
 #if defined(CONFIG_UBOOT)
        movel   %sp,_init_sp                    /* save initial stack pointer */
 #endif
+#ifdef CONFIG_MBAR
+       movel   #CONFIG_MBAR+1,%d0              /* configured MBAR address */
+       movec   %d0,%MBAR                       /* set it */
+#endif
 
        /*
         *      Do any platform or board specific setup now. Most boards
index 02663d2..e62dbbc 100644 (file)
@@ -149,7 +149,7 @@ static struct clocksource pit_clk = {
 
 /***************************************************************************/
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
        cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
        cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c
new file mode 100644 (file)
index 0000000..933e54e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * reset.c  -- common ColdFire SoC reset support
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ *     There are 2 common methods amongst the ColdFure parts for reseting
+ *     the CPU. But there are couple of exceptions, the 5272 and the 547x
+ *     have something completely special to them, and we let their specific
+ *     subarch code handle them.
+ */
+
+#ifdef MCFSIM_SYPCR
+static void mcf_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+#endif
+
+#ifdef MCF_RCR
+static void mcf_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+#endif
+
+static int __init mcf_setup_reset(void)
+{
+       mach_reset = mcf_cpu_reset;
+       return 0;
+}
+
+arch_initcall(mcf_setup_reset);
index 54e1452..2027fc2 100644 (file)
@@ -81,12 +81,14 @@ void mcfslt_profile_init(void)
 static u32 mcfslt_cycles_per_jiffy;
 static u32 mcfslt_cnt;
 
+static irq_handler_t timer_interrupt;
+
 static irqreturn_t mcfslt_tick(int irq, void *dummy)
 {
        /* Reset Slice Timer 0 */
        __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
        mcfslt_cnt += mcfslt_cycles_per_jiffy;
-       return arch_timer_interrupt(irq, dummy);
+       return timer_interrupt(irq, dummy);
 }
 
 static struct irqaction mcfslt_timer_irq = {
@@ -121,7 +123,7 @@ static struct clocksource mcfslt_clk = {
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
        mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
        /*
@@ -136,6 +138,7 @@ void hw_timer_init(void)
        /* initialize mcfslt_cnt knowing that slice timers count down */
        mcfslt_cnt = mcfslt_cycles_per_jiffy;
 
+       timer_interrupt = handler;
        setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
 
        clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
index 0d90da3..ed96ce5 100644 (file)
@@ -47,6 +47,27 @@ void coldfire_profile_init(void);
 static u32 mcftmr_cycles_per_jiffy;
 static u32 mcftmr_cnt;
 
+static irq_handler_t timer_interrupt;
+
+/***************************************************************************/
+
+static void init_timer_irq(void)
+{
+#ifdef MCFSIM_ICR_AUTOVEC
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+#endif /* MCFSIM_ICR_AUTOVEC */
+}
+
 /***************************************************************************/
 
 static irqreturn_t mcftmr_tick(int irq, void *dummy)
@@ -55,7 +76,7 @@ static irqreturn_t mcftmr_tick(int irq, void *dummy)
        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
 
        mcftmr_cnt += mcftmr_cycles_per_jiffy;
-       return arch_timer_interrupt(irq, dummy);
+       return timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
@@ -94,7 +115,7 @@ static struct clocksource mcftmr_clk = {
 
 /***************************************************************************/
 
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
 {
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
        mcftmr_cycles_per_jiffy = FREQ / HZ;
@@ -110,6 +131,8 @@ void hw_timer_init(void)
 
        clocksource_register_hz(&mcftmr_clk, FREQ);
 
+       timer_interrupt = handler;
+       init_timer_irq();
        setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
 
 #ifdef CONFIG_HIGHPROFILE
index 3a7cc52..a4dbdec 100644 (file)
@@ -33,8 +33,6 @@ asmlinkage void dbginterrupt_c(struct frame *fp)
 
 /***************************************************************************/
 
-extern e_vector        *_ramvec;
-
 /* Assembler routines */
 asmlinkage void buserr(void);
 asmlinkage void trap(void);
index 303703d..d219ebe 100644 (file)
@@ -134,6 +134,7 @@ config PPC
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
        select HAVE_GENERIC_HARDIRQS
        select HAVE_SPARSE_IRQ
+       select SPARSE_IRQ
        select IRQ_PER_CPU
        select IRQ_DOMAIN
        select GENERIC_IRQ_SHOW
@@ -377,13 +378,16 @@ config CRASH_DUMP
          The same kernel binary can be used as production kernel and dump
          capture kernel.
 
-config PHYP_DUMP
-       bool "Hypervisor-assisted dump (EXPERIMENTAL)"
-       depends on PPC_PSERIES && EXPERIMENTAL
+config FA_DUMP
+       bool "Firmware-assisted dump"
+       depends on PPC64 && PPC_RTAS && CRASH_DUMP
        help
-         Hypervisor-assisted dump is meant to be a kdump replacement
-         offering robustness and speed not possible without system
-         hypervisor assistance.
+         A robust mechanism to get reliable kernel crash dump with
+         assistance from firmware. This approach does not use kexec,
+         instead firmware assists in booting the kdump kernel
+         while preserving memory contents. Firmware-assisted dump
+         is meant to be a kdump replacement offering robustness and
+         speed not possible without system firmware assistance.
 
          If unsure, say "N"
 
@@ -612,7 +616,7 @@ endmenu
 
 config ISA_DMA_API
        bool
-       default !PPC_ISERIES || PCI
+       default PCI
 
 menu "Bus options"
 
index 4ccb2a0..72d55db 100644 (file)
@@ -196,13 +196,6 @@ config PPC_EARLY_DEBUG_MAPLE
        help
          Select this to enable early debugging for Maple.
 
-config PPC_EARLY_DEBUG_ISERIES
-       bool "iSeries HV Console"
-       depends on PPC_ISERIES
-       help
-         Select this to enable early debugging for legacy iSeries. You need
-         to hit "Ctrl-x Ctrl-x" to see the messages on the console.
-
 config PPC_EARLY_DEBUG_PAS_REALMODE
        bool "PA Semi real mode"
        depends on PPC_PASEMI
index b8b105c..6524c6e 100644 (file)
@@ -157,6 +157,7 @@ core-y                              += arch/powerpc/kernel/ \
                                   arch/powerpc/net/
 core-$(CONFIG_XMON)            += arch/powerpc/xmon/
 core-$(CONFIG_KVM)             += arch/powerpc/kvm/
+core-$(CONFIG_PERF_EVENTS)     += arch/powerpc/perf/
 
 drivers-$(CONFIG_OPROFILE)     += arch/powerpc/oprofile/
 
index 8844a17..e8461cb 100644 (file)
@@ -184,7 +184,6 @@ image-$(CONFIG_PPC_EFIKA)           += zImage.chrp
 image-$(CONFIG_PPC_PMAC)               += zImage.pmac
 image-$(CONFIG_PPC_HOLLY)              += dtbImage.holly
 image-$(CONFIG_PPC_PRPMC2800)          += dtbImage.prpmc2800
-image-$(CONFIG_PPC_ISERIES)            += zImage.iseries
 image-$(CONFIG_DEFAULT_UIMAGE)         += uImage
 image-$(CONFIG_EPAPR_BOOT)             += zImage.epapr
 
@@ -247,7 +246,7 @@ image-$(CONFIG_ASP834x)                     += dtbImage.asp834x-redboot
 image-$(CONFIG_MPC8540_ADS)            += cuImage.mpc8540ads
 image-$(CONFIG_MPC8560_ADS)            += cuImage.mpc8560ads
 image-$(CONFIG_MPC85xx_CDS)            += cuImage.mpc8541cds \
-                                          cuImage.mpc8548cds \
+                                          cuImage.mpc8548cds_32b \
                                           cuImage.mpc8555cds
 image-$(CONFIG_MPC85xx_MDS)            += cuImage.mpc8568mds
 image-$(CONFIG_MPC85xx_DS)             += cuImage.mpc8544ds \
@@ -311,12 +310,6 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb
 $(obj)/vmlinux.strip: vmlinux
        $(STRIP) -s -R .comment $< -o $@
 
-# The iseries hypervisor won't take an ET_DYN executable, so this
-# changes the type (byte 17) in the file to ET_EXEC (2).
-$(obj)/zImage.iseries: vmlinux
-       $(STRIP) -s -R .comment $< -o $@
-       printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
-
 $(obj)/uImage: vmlinux $(wrapperbits)
        $(call if_changed,wrap,uboot)
 
@@ -364,7 +357,7 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
 # anything not in $(targets)
 clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \
        zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \
-       zImage.iseries zImage.miboot zImage.pmac zImage.pseries \
+       zImage.miboot zImage.pmac zImage.pseries \
        zImage.maple simpleImage.* otheros.bld *.dtb
 
 # clean up files cached by wrapper
diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts
new file mode 100644 (file)
index 0000000..fabe7b7
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * a4m072 board Device Tree Source
+ *
+ * Copyright (C) 2011 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright (C) 2007 Semihalf
+ * Marian Balakowicz <m8@semihalf.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/include/ "mpc5200b.dtsi"
+
+/ {
+       model = "anonymous,a4m072";
+       compatible = "anonymous,a4m072";
+
+       soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <0>; /* From boot loader */
+               system-frequency = <0>; /* From boot loader */
+
+               cdm@200 {
+                       fsl,init-ext-48mhz-en = <0x0>;
+                       fsl,init-fd-enable = <0x01>;
+                       fsl,init-fd-counters = <0x3333>;
+               };
+
+               timer@600 {
+                       fsl,has-wdt;
+               };
+
+               gpt3: timer@630 { /* General Purpose Timer in GPIO mode */
+                       compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt4: timer@640 { /* General Purpose Timer in GPIO mode */
+                       compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               gpt5: timer@650 { /* General Purpose Timer in GPIO mode */
+                       compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+
+               spi@f00 {
+                       status = "disabled";
+               };
+
+               psc@2000 {
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2000 0x100>;
+                       interrupts = <2 1 0>;
+               };
+
+               psc@2200 {
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2200 0x100>;
+                       interrupts = <2 2 0>;
+               };
+
+               psc@2400 {
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2400 0x100>;
+                       interrupts = <2 3 0>;
+               };
+
+               psc@2600 {
+                       status = "disabled";
+               };
+
+               psc@2800 {
+                       status = "disabled";
+               };
+
+               psc@2c00 {
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2c00 0x100>;
+                       interrupts = <2 4 0>;
+               };
+
+               ethernet@3000 {
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       phy0: ethernet-phy@1f {
+                               reg = <0x1f>;
+                               interrupts = <1 2 0>; /* IRQ 2 active low */
+                       };
+               };
+
+               i2c@3d00 {
+                       status = "disabled";
+               };
+
+               i2c@3d40 {
+                       hwmon@2e {
+                               compatible = "nsc,lm87";
+                               reg = <0x2e>;
+                       };
+                       rtc@51 {
+                               compatible = "nxp,rtc8564";
+                               reg = <0x51>;
+                       };
+               };
+       };
+
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0 0xfe000000 0x02000000
+                         1 0 0x62000000 0x00400000
+                         2 0 0x64000000 0x00200000
+                         3 0 0x66000000 0x01000000
+                         6 0 0x68000000 0x01000000
+                         7 0 0x6a000000 0x00000004>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x02000000>;
+                       bank-width = <2>;
+                       #size-cells = <1>;
+                       #address-cells = <1>;
+               };
+               sram0@1,0 {
+                       compatible = "mtd-ram";
+                       reg = <1 0x00000 0x00400000>;
+                       bank-width = <2>;
+               };
+       };
+
+       pci@f0000d00 {
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               compatible = "fsl,mpc5200-pci";
+               reg = <0xf0000d00 0x100>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                                /* IDSEL 0x16 */
+                                0xc000 0 0 1 &mpc5200_pic 1 3 3
+                                0xc000 0 0 2 &mpc5200_pic 1 3 3
+                                0xc000 0 0 3 &mpc5200_pic 1 3 3
+                                0xc000 0 0 4 &mpc5200_pic 1 3 3>;
+               clock-frequency = <0>; /* From boot loader */
+               interrupts = <2 8 0 2 9 0 2 10 0>;
+               bus-range = <0 0>;
+               ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000
+                         0x02000000 0 0x90000000 0x90000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
+       };
+};
index 74876f7..7bda373 100644 (file)
@@ -33,7 +33,7 @@
        aliases {
                ethernet0 = &EMAC0;
                serial0 = &UART0;
-               //serial1 = &UART1; --gcl missing UART1 label
+               serial1 = &UART1;
        };
 
        cpus {
@@ -52,7 +52,7 @@
                        d-cache-size = <32768>;
                        dcr-controller;
                        dcr-access-method = "native";
-                       //next-level-cache = <&L2C0>; --gcl missing L2C0 label
+                       next-level-cache = <&L2C0>;
                };
        };
 
                dcr-reg = <0x00c 0x002>;
        };
 
+       L2C0: l2c {
+               compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache";
+               dcr-reg = <0x020 0x008
+                          0x030 0x008>;
+               cache-line-size = <32>;
+               cache-size = <262144>;
+               interrupt-parent = <&UIC1>;
+               interrupts = <11 1>;
+       };
+
        plb {
                compatible = "ibm,plb4";
                #address-cells = <2>;
                                                reg = <0x001a0000 0x00060000>;
                                        };
                                };
+
+                               ndfc@1,0 {
+                                       compatible = "ibm,ndfc";
+                                       reg = <0x00000003 0x00000000 0x00002000>;
+                                       ccr = <0x00001000>;
+                                       bank-settings = <0x80002222>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       /* 2Gb Nand Flash */
+                                       nand {
+                                               #address-cells = <1>;
+                                               #size-cells = <1>;
+
+                                               partition@0 {
+                                                       label = "firmware";
+                                                       reg   = <0x00000000 0x00C00000>;
+                                               };
+                                               partition@c00000 {
+                                                       label = "environment";
+                                                       reg   = <0x00C00000 0x00B00000>;
+                                               };
+                                               partition@1700000 {
+                                                       label = "kernel";
+                                                       reg   = <0x01700000 0x00E00000>;
+                                               };
+                                               partition@2500000 {
+                                                       label = "root";
+                                                       reg   = <0x02500000 0x08200000>;
+                                               };
+                                               partition@a700000 {
+                                                       label = "device-tree";
+                                                       reg   = <0x0A700000 0x00B00000>;
+                                               };
+                                               partition@b200000 {
+                                                       label = "config";
+                                                       reg   = <0x0B200000 0x00D00000>;
+                                               };
+                                               partition@bf00000 {
+                                                       label = "diag";
+                                                       reg   = <0x0BF00000 0x00C00000>;
+                                               };
+                                               partition@cb00000 {
+                                                       label = "vendor";
+                                                       reg   = <0x0CB00000 0x3500000>;
+                                               };
+                                       };
+                               };
                        };
 
                        UART0: serial@ef600300 {
                                interrupts = <0x1 0x4>;
                        };
 
+                       UART1: serial@ef600400 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600400 0x00000008>;
+                               virtual-reg = <0xef600400>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               current-speed = <0>; /* Filled in by U-Boot */
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x1 0x4>;
+                       };
+
                        IIC0: i2c@ef600700 {
                                compatible = "ibm,iic";
                                reg = <0xef600700 0x00000014>;
                                interrupt-parent = <&UIC0>;
                                interrupts = <0x2 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               rtc@68 {
+                                       compatible = "stm,m41t80";
+                                       reg = <0x68>;
+                                       interrupt-parent = <&UIC0>;
+                                       interrupts = <0x9 0x8>;
+                               };
+                               sttm@4C {
+                                       compatible = "adm,adm1032";
+                                       reg = <0x4C>;
+                                       interrupt-parent = <&UIC1>;
+                                       interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */
+                               };
                        };
 
                        IIC1: i2c@ef600800 {
                        };
                };
 
+               PCIE0: pciex@d00000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex";
+                       primary;
+                       port = <0x0>; /* port number */
+                       reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
+                              0x0000000c 0x08010000 0x00001000>;       /* Registers */
+                       dcr-reg = <0x100 0x020>;
+                       sdr-base = <0x300>;
+
+                       /* Outbound ranges, one memory and one IO,
+                        * later cannot be changed
+                        */
+                       ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+                                 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
+                                 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+                       /* Inbound 2GB range starting at 0 */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+                       /* This drives busses 40 to 0x7f */
+                       bus-range = <0x40 0x7f>;
+
+                       /* Legacy interrupts (note the weird polarity, the bridge seems
+                        * to invert PCIe legacy interrupts).
+                        * We are de-swizzling here because the numbers are actually for
+                        * port of the root complex virtual P2P bridge. But I want
+                        * to avoid putting a node for it in the tree, so the numbers
+                        * below are basically de-swizzled numbers.
+                        * The real slot is on idsel 0, so the swizzling is 1:1
+                        */
+                       interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
+                               0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
+                               0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
+                               0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
+               };
        };
 };
index b37da56..c8b2daa 100644 (file)
 /include/ "pq3-etsec1-timer-0.dtsi"
 
        usb@22000 {
-               compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+               compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
                reg = <0x22000 0x1000>;
                #address-cells = <1>;
                #size-cells = <0>;
        };
 
        usb@23000 {
-               compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+               compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
                reg = <0x23000 0x1000>;
                #address-cells = <1>;
                #size-cells = <0>;
index 9d8023a..579d76c 100644 (file)
        };
 };
 
+&rio {
+       compatible = "fsl,srio";
+       interrupts = <48 2 0 0>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+       fsl,srio-rmu-handle = <&rmu>;
+       ranges;
+
+       port1 {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               cell-index = <1>;
+       };
+};
+
 &soc {
        #address-cells = <1>;
        #size-cells = <1>;
 
 /include/ "pq3-sec2.1-0.dtsi"
 /include/ "pq3-mpic.dtsi"
+/include/ "pq3-rmu-0.dtsi"
 
        global-utilities@e0000 {
                compatible = "fsl,mpc8548-guts";
index 289f121..720422d 100644 (file)
@@ -43,7 +43,9 @@
                serial0 = &serial0;
                serial1 = &serial1;
                ethernet0 = &enet0;
-               ethernet1 = &enet2;
+               ethernet1 = &enet1;
+               ethernet2 = &enet2;
+               ethernet3 = &enet3;
                pci0 = &pci0;
                pci1 = &pci1;
                pci2 = &pci2;
index a97d126..0bde9ee 100644 (file)
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 /include/ "pq3-esdhc-0.dtsi"
        sdhc@2e000 {
                compatible = "fsl,p1010-esdhc", "fsl,esdhc";
index 5de5fc3..68cc5e7 100644 (file)
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 /include/ "pq3-usb2-dr-1.dtsi"
+       usb@23000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 
 /include/ "pq3-esdhc-0.dtsi"
        sdhc@2e000 {
index 38ba54d..4252ef8 100644 (file)
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 
 /include/ "pq3-esdhc-0.dtsi"
+       sdhc@2e000 {
+               sdhci,auto-cmd12;
+       };
+
 /include/ "pq3-sec3.3-0.dtsi"
 
 /include/ "pq3-mpic.dtsi"
index ff9ed1d..06216b8 100644 (file)
 &lbc {
        #address-cells = <2>;
        #size-cells = <1>;
-       compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
+       /*
+        * The localbus on the P1022 is not a simple-bus because of the eLBC
+        * pin muxing when the DIU is enabled.
+        */
+       compatible = "fsl,p1022-elbc", "fsl,elbc";
        interrupts = <19 2 0 0>;
 };
 
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 /include/ "pq3-usb2-dr-1.dtsi"
+       usb@23000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 
 /include/ "pq3-esdhc-0.dtsi"
        sdhc@2e000 {
index b06bb4c..941fa15 100644 (file)
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 
        crypto: crypto@300000 {
                compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
index 332e9e7..884e01b 100644 (file)
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-usb2-dr-0.dtsi"
+       usb@22000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
+       };
 /include/ "pq3-etsec1-0.dtsi"
 /include/ "pq3-etsec1-timer-0.dtsi"
 
index 234a399..531eab8 100644 (file)
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
                usb0: usb@210000 {
+                       compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
                        phy_type = "utmi";
                        port0;
                };
 
 /include/ "qoriq-usb2-dr-0.dtsi"
                usb1: usb@211000 {
+                       compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
                        dr_mode = "host";
                        phy_type = "utmi";
                };
index d41d08d..af4ebc8 100644 (file)
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
                usb0: usb@210000 {
+                       compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph";
                        phy_type = "utmi";
                        port0;
                };
 
 /include/ "qoriq-usb2-dr-0.dtsi"
                usb1: usb@211000 {
+                       compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
                        dr_mode = "host";
                        phy_type = "utmi";
                };
index a63edd1..b3e5692 100644 (file)
 /include/ "qoriq-duart-1.dtsi"
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
+       usb@210000 {
+               compatible = "fsl-usb2-mph-v2.2", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+       };
 /include/ "qoriq-usb2-dr-0.dtsi"
+       usb@211000 {
+               compatible = "fsl-usb2-dr-v2.2", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+       };
 /include/ "qoriq-sec4.1-0.dtsi"
 };
index 914074b..64b6abe 100644 (file)
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
                usb0: usb@210000 {
+                       compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
                        phy_type = "utmi";
                        port0;
                };
 
 /include/ "qoriq-usb2-dr-0.dtsi"
                usb1: usb@211000 {
+                       compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
                        dr_mode = "host";
                        phy_type = "utmi";
                };
index a1979ae..3b0650a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@ ethernet@24000 {
        compatible = "gianfar";
        reg = <0x24000 0x1000>;
        ranges = <0x0 0x24000 0x1000>;
+       fsl,magic-packet;
        local-mac-address = [ 00 00 00 00 00 00 ];
        interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>;
 };
index 4c4fdde..96693b4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@ ethernet@25000 {
        compatible = "gianfar";
        reg = <0x25000 0x1000>;
        ranges = <0x0 0x25000 0x1000>;
+       fsl,magic-packet;
        local-mac-address = [ 00 00 00 00 00 00 ];
        interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>;
 };
index 4b8ab43..6b3fab1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@ ethernet@26000 {
        compatible = "gianfar";
        reg = <0x26000 0x1000>;
        ranges = <0x0 0x26000 0x1000>;
+       fsl,magic-packet;
        local-mac-address = [ 00 00 00 00 00 00 ];
        interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>;
 };
index 40c9137..0da592d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ]
  *
- * Copyright 2011 Freescale Semiconductor Inc.
+ * Copyright 2011-2012 Freescale Semiconductor Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -41,6 +41,7 @@ ethernet@27000 {
        compatible = "gianfar";
        reg = <0x27000 0x1000>;
        ranges = <0x0 0x27000 0x1000>;
+       fsl,magic-packet;
        local-mac-address = [ 00 00 00 00 00 00 ];
        interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>;
 };
index 5c80460..fdedf7b 100644 (file)
@@ -39,6 +39,9 @@ mpic: pic@40000 {
        reg = <0x40000 0x40000>;
        compatible = "fsl,mpic";
        device_type = "open-pic";
+       big-endian;
+       single-cpu-affinity;
+       last-interrupt-source = <255>;
 };
 
 timer@41100 {
index bf957a7..d4c9d5d 100644 (file)
  */
 
 crypto@30000 {
-       compatible = "fsl,sec4.4", "fsl,sec4.0";
+       compatible = "fsl,sec-v4.4", "fsl,sec-v4.0";
        #address-cells = <1>;
        #size-cells = <1>;
        reg              = <0x30000 0x10000>;
        interrupts       = <58 2 0 0>;
 
        sec_jr0: jr@1000 {
-               compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+               compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
                reg        = <0x1000 0x1000>;
                interrupts       = <45 2 0 0>;
        };
 
        sec_jr1: jr@2000 {
-               compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+               compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
                reg        = <0x2000 0x1000>;
                interrupts       = <45 2 0 0>;
        };
 
        sec_jr2: jr@3000 {
-               compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+               compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
                reg        = <0x3000 0x1000>;
                interrupts       = <45 2 0 0>;
        };
 
        sec_jr3: jr@4000 {
-               compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring";
+               compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring";
                reg        = <0x4000 0x1000>;
                interrupts       = <45 2 0 0>;
        };
index b9bada6..08f4227 100644 (file)
@@ -53,7 +53,7 @@ timer@41100 {
 
 msi0: msi@41600 {
        compatible = "fsl,mpic-msi";
-       reg = <0x41600 0x200>;
+       reg = <0x41600 0x200 0x44140 4>;
        msi-available-ranges = <0 0x100>;
        interrupts = <
                0xe0 0 0 0
@@ -68,7 +68,7 @@ msi0: msi@41600 {
 
 msi1: msi@41800 {
        compatible = "fsl,mpic-msi";
-       reg = <0x41800 0x200>;
+       reg = <0x41800 0x200 0x45140 4>;
        msi-available-ranges = <0 0x100>;
        interrupts = <
                0xe8 0 0 0
@@ -83,7 +83,7 @@ msi1: msi@41800 {
 
 msi2: msi@41a00 {
        compatible = "fsl,mpic-msi";
-       reg = <0x41a00 0x200>;
+       reg = <0x41a00 0x200 0x46140 4>;
        msi-available-ranges = <0 0x100>;
        interrupts = <
                0xf0 0 0 0
diff --git a/arch/powerpc/boot/dts/ge_imp3a.dts b/arch/powerpc/boot/dts/ge_imp3a.dts
new file mode 100644 (file)
index 0000000..fefae41
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * GE IMP3A Device Tree Source
+ *
+ * Copyright 2010-2011 GE Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: P2020 DS Device Tree Source
+ * Copyright 2009 Freescale Semiconductor Inc.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+       model = "GE_IMP3A";
+       compatible = "ge,imp3a";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@fef05000 {
+               reg = <0 0xfef05000 0 0x1000>;
+
+               ranges = <0x0 0x0 0x0 0xff000000 0x01000000
+                         0x1 0x0 0x0 0xe0000000 0x08000000
+                         0x2 0x0 0x0 0xe8000000 0x08000000
+                         0x3 0x0 0x0 0xfc100000 0x00020000
+                         0x4 0x0 0x0 0xfc000000 0x00008000
+                         0x5 0x0 0x0 0xfc008000 0x00008000
+                         0x6 0x0 0x0 0xfee00000 0x00040000
+                         0x7 0x0 0x0 0xfee80000 0x00040000>;
+
+               /* nor@0,0 is a mirror of part of the memory in nor@1,0
+               nor@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "ge,imp3a-firmware-mirror", "cfi-flash";
+                       reg = <0x0 0x0 0x1000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               label = "firmware";
+                               reg = <0x0 0x1000000>;
+                               read-only;
+                       };
+               };
+               */
+
+               nor@1,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "ge,imp3a-paged-flash", "cfi-flash";
+                       reg = <0x1 0x0 0x8000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               label = "user";
+                               reg = <0x0 0x7800000>;
+                       };
+
+                       partition@7800000 {
+                               label = "firmware";
+                               reg = <0x7800000 0x800000>;
+                               read-only;
+                       };
+               };
+
+               nvram@3,0 {
+                       device_type = "nvram";
+                       compatible = "simtek,stk14ca8";
+                       reg = <0x3 0x0 0x20000>;
+               };
+
+               fpga@4,0 {
+                       compatible = "ge,imp3a-fpga-regs";
+                       reg = <0x4 0x0 0x20>;
+               };
+
+               gef_pic: pic@4,20 {
+                       #interrupt-cells = <1>;
+                       interrupt-controller;
+                       device_type = "interrupt-controller";
+                       compatible = "ge,imp3a-fpga-pic", "gef,fpga-pic-1.00";
+                       reg = <0x4 0x20 0x20>;
+                       interrupts = <6 7 0 0>;
+               };
+
+               gef_gpio: gpio@4,400 {
+                       #gpio-cells = <2>;
+                       compatible = "ge,imp3a-gpio";
+                       reg = <0x4 0x400 0x24>;
+                       gpio-controller;
+               };
+
+               wdt@4,800 {
+                       compatible = "ge,imp3a-fpga-wdt", "gef,fpga-wdt-1.00",
+                               "gef,fpga-wdt";
+                       reg = <0x4 0x800 0x8>;
+                       interrupts = <10 4>;
+                       interrupt-parent = <&gef_pic>;
+               };
+
+               /* Second watchdog available, driver currently supports one.
+               wdt@4,808 {
+                       compatible = "gef,imp3a-fpga-wdt", "gef,fpga-wdt-1.00",
+                               "gef,fpga-wdt";
+                       reg = <0x4 0x808 0x8>;
+                       interrupts = <9 4>;
+                       interrupt-parent = <&gef_pic>;
+               };
+               */
+
+               nand@6,0 {
+                       compatible = "fsl,elbc-fcm-nand";
+                       reg = <0x6 0x0 0x40000>;
+               };
+
+               nand@7,0 {
+                       compatible = "fsl,elbc-fcm-nand";
+                       reg = <0x7 0x0 0x40000>;
+               };
+       };
+
+       soc: soc@fef00000 {
+               ranges = <0x0 0 0xfef00000 0x100000>;
+
+               i2c@3000 {
+                       hwmon@48 {
+                               compatible = "national,lm92";
+                               reg = <0x48>;
+                       };
+
+                       hwmon@4c {
+                               compatible = "adi,adt7461";
+                               reg = <0x4c>;
+                       };
+
+                       rtc@51 {
+                               compatible = "epson,rx8581";
+                               reg = <0x51>;
+                       };
+
+                       eti@6b {
+                               compatible = "dallas,ds1682";
+                               reg = <0x6b>;
+                       };
+               };
+
+               usb@22000 {
+                       phy_type = "ulpi";
+                       dr_mode = "host";
+               };
+
+               mdio@24520 {
+                       phy0: ethernet-phy@0 {
+                               interrupt-parent = <&gef_pic>;
+                               interrupts = <0xc 0x4>;
+                               reg = <0x1>;
+                       };
+                       phy1: ethernet-phy@1 {
+                               interrupt-parent = <&gef_pic>;
+                               interrupts = <0xb 0x4>;
+                               reg = <0x2>;
+                       };
+                       tbi0: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
+               mdio@25520 {
+                       tbi1: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
+               mdio@26520 {
+                       status = "disabled";
+               };
+
+               enet0: ethernet@24000 {
+                       tbi-handle = <&tbi0>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "gmii";
+               };
+
+               enet1: ethernet@25000 {
+                       tbi-handle = <&tbi1>;
+                       phy-handle = <&phy1>;
+                       phy-connection-type = "gmii";
+               };
+
+               enet2: ethernet@26000 {
+                       status = "disabled";
+               };
+       };
+
+       pci0: pcie@fef08000 {
+               ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xfe020000 0x0 0x10000>;
+               reg = <0 0xfef08000 0 0x1000>;
+
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xc0000000
+                                 0x2000000 0x0 0xc0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x10000>;
+               };
+       };
+
+       pci1: pcie@fef09000 {
+               reg = <0 0xfef09000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xfe010000 0x0 0x10000>;
+
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x10000>;
+               };
+
+       };
+
+       pci2: pcie@fef0a000 {
+               reg = <0 0xfef0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xfe000000 0x0 0x10000>;
+
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0x80000000
+                                 0x2000000 0x0 0x80000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x10000>;
+               };
+       };
+};
+
+/include/ "fsl/p2020si-post.dtsi"
index c0e450a..81dd513 100644 (file)
                                reg = <0x1>;
                                device_type = "ethernet-phy";
                        };
+                       tbi-phy@2 {
+                               device_type = "tbi-phy";
+                               reg = <0x2>;
+                       };
                };
 
                qeic: interrupt-controller@80 {
index c158815..1973622 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC8536 DS Device Tree Source
  *
- * Copyright 2008 Freescale Semiconductor, Inc.
+ * Copyright 2008, 2011 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
 
        lbc: localbus@ffe05000 {
                reg = <0 0xffe05000 0 0x1000>;
+
+               ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+                         0x2 0x0 0x0 0xffa00000 0x00040000
+                         0x3 0x0 0x0 0xffdf0000 0x00008000>;
        };
 
        board_soc: soc: soc@ffe00000 {
index 1462e4c..cc46dbd 100644 (file)
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x8000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       reg = <0x0 0x03000000>;
+                       label = "ramdisk-nor";
+               };
+
+               partition@3000000 {
+                       reg = <0x03000000 0x00e00000>;
+                       label = "diagnostic-nor";
+                       read-only;
+               };
+
+               partition@3e00000 {
+                       reg = <0x03e00000 0x00200000>;
+                       label = "dink-nor";
+                       read-only;
+               };
+
+               partition@4000000 {
+                       reg = <0x04000000 0x00400000>;
+                       label = "kernel-nor";
+               };
+
+               partition@4400000 {
+                       reg = <0x04400000 0x03b00000>;
+                       label = "fs-nor";
+               };
+
+               partition@7f00000 {
+                       reg = <0x07f00000 0x00080000>;
+                       label = "dtb-nor";
+               };
+
+               partition@7f80000 {
+                       reg = <0x07f80000 0x00080000>;
+                       label = "u-boot-nor";
+                       read-only;
+               };
+       };
+
+       nand@2,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8536-fcm-nand",
+                            "fsl,elbc-fcm-nand";
+               reg = <0x2 0x0 0x40000>;
+
+               partition@0 {
+                       reg = <0x0 0x02000000>;
+                       label = "u-boot-nand";
+                       read-only;
+               };
+
+               partition@2000000 {
+                       reg = <0x02000000 0x10000000>;
+                       label = "fs-nand";
+               };
+
+               partition@12000000 {
+                       reg = <0x12000000 0x08000000>;
+                       label = "ramdisk-nand";
+               };
+
+               partition@1a000000 {
+                       reg = <0x1a000000 0x04000000>;
+                       label = "kernel-nand";
+               };
+
+               partition@1e000000 {
+                       reg = <0x1e000000 0x01000000>;
+                       label = "dtb-nand";
+               };
+
+               partition@1f000000 {
+                       reg = <0x1f000000 0x21000000>;
+                       label = "empty-nand";
+               };
+       };
+
+       board-control@3,0 {
+               compatible = "fsl,mpc8536ds-fpga-pixis";
+               reg = <0x3 0x0 0x8000>;
+       };
+};
+
 &board_soc {
        i2c@3100 {
                rtc@68 {
index 8f4b929..f8a3b34 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC8536DS Device Tree Source (36-bit address map)
  *
- * Copyright 2008-2009 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009, 2011 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
        };
 
        lbc: localbus@ffe05000 {
-               reg = <0 0xffe05000 0 0x1000>;
+               reg = <0xf 0xffe05000 0 0x1000>;
+
+               ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+                         0x2 0x0 0xf 0xffa00000 0x00040000
+                         0x3 0x0 0xf 0xffdf0000 0x00008000>;
        };
 
        board_soc: soc: soc@fffe00000 {
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
deleted file mode 100644 (file)
index 07b8dae..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * MPC8548 CDS Device Tree Source
- *
- * Copyright 2006, 2008 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/ "fsl/mpc8548si-pre.dtsi"
-
-/ {
-       model = "MPC8548CDS";
-       compatible = "MPC8548CDS", "MPC85xxCDS";
-
-       aliases {
-               ethernet0 = &enet0;
-               ethernet1 = &enet1;
-               ethernet2 = &enet2;
-               ethernet3 = &enet3;
-               serial0 = &serial0;
-               serial1 = &serial1;
-               pci0 = &pci0;
-               pci1 = &pci1;
-               pci2 = &pci2;
-       };
-
-       memory {
-               device_type = "memory";
-               reg = <0 0 0x0 0x8000000>;      // 128M at 0x0
-       };
-
-       lbc: localbus@e0005000 {
-               reg = <0 0xe0005000 0 0x1000>;
-       };
-
-       soc: soc8548@e0000000 {
-               ranges = <0 0x0 0xe0000000 0x100000>;
-
-               i2c@3000 {
-                       eeprom@50 {
-                               compatible = "atmel,24c64";
-                               reg = <0x50>;
-                       };
-
-                       eeprom@56 {
-                               compatible = "atmel,24c64";
-                               reg = <0x56>;
-                       };
-
-                       eeprom@57 {
-                               compatible = "atmel,24c64";
-                               reg = <0x57>;
-                       };
-               };
-
-               i2c@3100 {
-                       eeprom@50 {
-                               compatible = "atmel,24c64";
-                               reg = <0x50>;
-                       };
-               };
-
-               enet0: ethernet@24000 {
-                       tbi-handle = <&tbi0>;
-                       phy-handle = <&phy0>;
-               };
-
-               mdio@24520 {
-                       phy0: ethernet-phy@0 {
-                               interrupts = <5 1 0 0>;
-                               reg = <0x0>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupts = <5 1 0 0>;
-                               reg = <0x1>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy2: ethernet-phy@2 {
-                               interrupts = <5 1 0 0>;
-                               reg = <0x2>;
-                               device_type = "ethernet-phy";
-                       };
-                       phy3: ethernet-phy@3 {
-                               interrupts = <5 1 0 0>;
-                               reg = <0x3>;
-                               device_type = "ethernet-phy";
-                       };
-                       tbi0: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               enet1: ethernet@25000 {
-                       tbi-handle = <&tbi1>;
-                       phy-handle = <&phy1>;
-               };
-
-               mdio@25520 {
-                       tbi1: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               enet2: ethernet@26000 {
-                       tbi-handle = <&tbi2>;
-                       phy-handle = <&phy2>;
-               };
-
-               mdio@26520 {
-                       tbi2: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-
-               enet3: ethernet@27000 {
-                       tbi-handle = <&tbi3>;
-                       phy-handle = <&phy3>;
-               };
-
-               mdio@27520 {
-                       tbi3: tbi-phy@11 {
-                               reg = <0x11>;
-                               device_type = "tbi-phy";
-                       };
-               };
-       };
-
-       pci0: pci@e0008000 {
-               reg = <0 0xe0008000 0 0x1000>;
-               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000
-                         0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>;
-               clock-frequency = <66666666>;
-               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-               interrupt-map = <
-                       /* IDSEL 0x4 (PCIX Slot 2) */
-                       0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                       /* IDSEL 0x5 (PCIX Slot 3) */
-                       0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-                       0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
-                       0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
-                       0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
-
-                       /* IDSEL 0x6 (PCIX Slot 4) */
-                       0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-                       0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-                       0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-                       0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-                       /* IDSEL 0x8 (PCIX Slot 5) */
-                       0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                       /* IDSEL 0xC (Tsi310 bridge) */
-                       0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                       /* IDSEL 0x14 (Slot 2) */
-                       0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                       /* IDSEL 0x15 (Slot 3) */
-                       0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-                       0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
-                       0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
-                       0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
-
-                       /* IDSEL 0x16 (Slot 4) */
-                       0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-                       0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-                       0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-                       0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-                       /* IDSEL 0x18 (Slot 5) */
-                       0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                       /* IDSEL 0x1C (Tsi310 bridge PCI primary) */
-                       0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                       0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
-
-               pci_bridge@1c {
-                       interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-                       interrupt-map = <
-
-                               /* IDSEL 0x00 (PrPMC Site) */
-                               0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                               0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                               0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                               0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                               /* IDSEL 0x04 (VIA chip) */
-                               0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
-                               0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                               0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                               0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
-
-                               /* IDSEL 0x05 (8139) */
-                               0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
-
-                               /* IDSEL 0x06 (Slot 6) */
-                               0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
-                               0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
-                               0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
-                               0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
-
-                               /* IDESL 0x07 (Slot 7) */
-                               0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0
-                               0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0
-                               0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0
-                               0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>;
-
-                       reg = <0xe000 0x0 0x0 0x0 0x0>;
-                       #interrupt-cells = <1>;
-                       #size-cells = <2>;
-                       #address-cells = <3>;
-                       ranges = <0x2000000 0x0 0x80000000
-                                 0x2000000 0x0 0x80000000
-                                 0x0 0x20000000
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x80000>;
-                       clock-frequency = <33333333>;
-
-                       isa@4 {
-                               device_type = "isa";
-                               #interrupt-cells = <2>;
-                               #size-cells = <1>;
-                               #address-cells = <2>;
-                               reg = <0x2000 0x0 0x0 0x0 0x0>;
-                               ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>;
-                               interrupt-parent = <&i8259>;
-
-                               i8259: interrupt-controller@20 {
-                                       interrupt-controller;
-                                       device_type = "interrupt-controller";
-                                       reg = <0x1 0x20 0x2
-                                              0x1 0xa0 0x2
-                                              0x1 0x4d0 0x2>;
-                                       #address-cells = <0>;
-                                       #interrupt-cells = <2>;
-                                       compatible = "chrp,iic";
-                                       interrupts = <0 1 0 0>;
-                                       interrupt-parent = <&mpic>;
-                               };
-
-                               rtc@70 {
-                                       compatible = "pnpPNP,b00";
-                                       reg = <0x1 0x70 0x2>;
-                               };
-                       };
-               };
-       };
-
-       pci1: pci@e0009000 {
-               reg = <0 0xe0009000 0 0x1000>;
-               ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000
-                         0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>;
-               clock-frequency = <66666666>;
-               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-               interrupt-map = <
-
-                       /* IDSEL 0x15 */
-                       0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
-                       0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
-                       0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
-                       0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
-       };
-
-       pci2: pcie@e000a000 {
-               reg = <0 0xe000a000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xa0000000
-                                 0x2000000 0x0 0xa0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-};
-
-/include/ "fsl/mpc8548si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dtsi b/arch/powerpc/boot/dts/mpc8548cds.dtsi
new file mode 100644 (file)
index 0000000..c61f525
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * MPC8548CDS Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&board_lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x01000000>;
+               bank-width = <2>;
+               device-width = <2>;
+
+               partition@0 {
+                       reg = <0x0 0x0b00000>;
+                       label = "ramdisk-nor";
+               };
+
+               partition@300000 {
+                       reg = <0x0b00000 0x0400000>;
+                       label = "kernel-nor";
+               };
+
+               partition@700000 {
+                       reg = <0x0f00000 0x060000>;
+                       label = "dtb-nor";
+               };
+
+               partition@760000 {
+                       reg = <0x0f60000 0x020000>;
+                       label = "env-nor";
+                       read-only;
+               };
+
+               partition@780000 {
+                       reg = <0x0f80000 0x080000>;
+                       label = "u-boot-nor";
+                       read-only;
+               };
+       };
+
+       board-control@1,0 {
+               compatible = "fsl,mpc8548cds-fpga";
+               reg = <0x1 0x0 0x1000>;
+       };
+};
+
+&board_soc {
+       i2c@3000 {
+               eeprom@50 {
+                       compatible = "atmel,24c64";
+                       reg = <0x50>;
+               };
+
+               eeprom@56 {
+                       compatible = "atmel,24c64";
+                       reg = <0x56>;
+               };
+
+               eeprom@57 {
+                       compatible = "atmel,24c64";
+                       reg = <0x57>;
+               };
+       };
+
+       i2c@3100 {
+               eeprom@50 {
+                       compatible = "atmel,24c64";
+                       reg = <0x50>;
+               };
+       };
+
+       enet0: ethernet@24000 {
+               tbi-handle = <&tbi0>;
+               phy-handle = <&phy0>;
+       };
+
+       mdio@24520 {
+               phy0: ethernet-phy@0 {
+                       interrupts = <5 1 0 0>;
+                       reg = <0x0>;
+                       device_type = "ethernet-phy";
+               };
+               phy1: ethernet-phy@1 {
+                       interrupts = <5 1 0 0>;
+                       reg = <0x1>;
+                       device_type = "ethernet-phy";
+               };
+               phy2: ethernet-phy@2 {
+                       interrupts = <5 1 0 0>;
+                       reg = <0x2>;
+                       device_type = "ethernet-phy";
+               };
+               phy3: ethernet-phy@3 {
+                       interrupts = <5 1 0 0>;
+                       reg = <0x3>;
+                       device_type = "ethernet-phy";
+               };
+               tbi0: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet1: ethernet@25000 {
+               tbi-handle = <&tbi1>;
+               phy-handle = <&phy1>;
+       };
+
+       mdio@25520 {
+               tbi1: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet2: ethernet@26000 {
+               tbi-handle = <&tbi2>;
+               phy-handle = <&phy2>;
+       };
+
+       mdio@26520 {
+               tbi2: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet3: ethernet@27000 {
+               tbi-handle = <&tbi3>;
+               phy-handle = <&phy3>;
+       };
+
+       mdio@27520 {
+               tbi3: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+};
+
+&board_pci0 {
+       interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+       interrupt-map = <
+               /* IDSEL 0x4 (PCIX Slot 2) */
+               0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+               /* IDSEL 0x5 (PCIX Slot 3) */
+               0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+               0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
+               0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
+               0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
+
+               /* IDSEL 0x6 (PCIX Slot 4) */
+               0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+               0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+               0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+               0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+               /* IDSEL 0x8 (PCIX Slot 5) */
+               0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+               /* IDSEL 0xC (Tsi310 bridge) */
+               0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+               /* IDSEL 0x14 (Slot 2) */
+               0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+               /* IDSEL 0x15 (Slot 3) */
+               0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+               0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0
+               0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0
+               0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0
+
+               /* IDSEL 0x16 (Slot 4) */
+               0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+               0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+               0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+               0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+               /* IDSEL 0x18 (Slot 5) */
+               0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+               /* IDSEL 0x1C (Tsi310 bridge PCI primary) */
+               0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+               0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+               0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+               0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+
+       pci_bridge@1c {
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+
+                       /* IDSEL 0x00 (PrPMC Site) */
+                       0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+                       0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+                       0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+                       0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+                       /* IDSEL 0x04 (VIA chip) */
+                       0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0
+                       0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+                       0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+                       0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0
+
+                       /* IDSEL 0x05 (8139) */
+                       0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0
+
+                       /* IDSEL 0x06 (Slot 6) */
+                       0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0
+                       0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0
+                       0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0
+                       0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0
+
+                       /* IDESL 0x07 (Slot 7) */
+                       0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0
+                       0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0
+                       0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0
+                       0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>;
+
+               reg = <0xe000 0x0 0x0 0x0 0x0>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               ranges = <0x2000000 0x0 0x80000000
+                         0x2000000 0x0 0x80000000
+                         0x0 0x20000000
+                         0x1000000 0x0 0x0
+                         0x1000000 0x0 0x0
+                         0x0 0x80000>;
+               clock-frequency = <33333333>;
+
+               isa@4 {
+                       device_type = "isa";
+                       #interrupt-cells = <2>;
+                       #size-cells = <1>;
+                       #address-cells = <2>;
+                       reg = <0x2000 0x0 0x0 0x0 0x0>;
+                       ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>;
+                       interrupt-parent = <&i8259>;
+
+                       i8259: interrupt-controller@20 {
+                               interrupt-controller;
+                               device_type = "interrupt-controller";
+                               reg = <0x1 0x20 0x2
+                                      0x1 0xa0 0x2
+                                      0x1 0x4d0 0x2>;
+                               #address-cells = <0>;
+                               #interrupt-cells = <2>;
+                               compatible = "chrp,iic";
+                               interrupts = <0 1 0 0>;
+                               interrupt-parent = <&mpic>;
+                       };
+
+                       rtc@70 {
+                               compatible = "pnpPNP,b00";
+                               reg = <0x1 0x70 0x2>;
+                       };
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/arch/powerpc/boot/dts/mpc8548cds_32b.dts
new file mode 100644 (file)
index 0000000..6fd6316
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * MPC8548 CDS Device Tree Source (32-bit address map)
+ *
+ * Copyright 2006, 2008, 2011-2012 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/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+       model = "MPC8548CDS";
+       compatible = "MPC8548CDS", "MPC85xxCDS";
+
+       memory {
+               device_type = "memory";
+               reg = <0 0 0x0 0x8000000>;      // 128M at 0x0
+       };
+
+       board_lbc: lbc: localbus@e0005000 {
+               reg = <0 0xe0005000 0 0x1000>;
+
+               ranges = <0x0 0x0 0x0 0xff000000 0x01000000
+                         0x1 0x0 0x0 0xf8004000 0x00001000>;
+
+       };
+
+       board_soc: soc: soc8548@e0000000 {
+               ranges = <0 0x0 0xe0000000 0x100000>;
+       };
+
+       board_pci0: pci0: pci@e0008000 {
+               reg = <0 0xe0008000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000
+                         0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>;
+               clock-frequency = <66666666>;
+       };
+
+       pci1: pci@e0009000 {
+               reg = <0 0xe0009000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000
+                         0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>;
+               clock-frequency = <66666666>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+
+                       /* IDSEL 0x15 */
+                       0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
+                       0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+                       0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+                       0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+       };
+
+       pci2: pcie@e000a000 {
+               reg = <0 0xe000a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       rio: rapidio@e00c0000 {
+               reg = <0x0 0xe00c0000 0x0 0x20000>;
+               port1 {
+                       ranges = <0x0 0x0 0x0 0xc0000000 0x0 0x20000000>;
+               };
+       };
+};
+
+/*
+ * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings
+ * for interrupt-map & interrupt-map-mask.
+ */
+
+/include/ "fsl/mpc8548si-post.dtsi"
+/include/ "mpc8548cds.dtsi"
diff --git a/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/arch/powerpc/boot/dts/mpc8548cds_36b.dts
new file mode 100644 (file)
index 0000000..10e551b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * MPC8548 CDS Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 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/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+       model = "MPC8548CDS";
+       compatible = "MPC8548CDS", "MPC85xxCDS";
+
+       memory {
+               device_type = "memory";
+               reg = <0 0 0x0 0x8000000>;      // 128M at 0x0
+       };
+
+       board_lbc: lbc: localbus@fe0005000 {
+               reg = <0xf 0xe0005000 0 0x1000>;
+
+               ranges = <0x0 0x0 0xf 0xff000000 0x01000000
+                         0x1 0x0 0xf 0xf8004000 0x00001000>;
+
+       };
+
+       board_soc: soc: soc8548@fe0000000 {
+               ranges = <0 0xf 0xe0000000 0x100000>;
+       };
+
+       board_pci0: pci0: pci@fe0008000 {
+               reg = <0xf 0xe0008000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x10000000
+                         0x1000000 0x0 0x00000000 0xf 0xe2000000 0x0 0x800000>;
+               clock-frequency = <66666666>;
+       };
+
+       pci1: pci@fe0009000 {
+               reg = <0xf 0xe0009000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000
+                         0x1000000 0x0 0x00000000 0xf 0xe2800000 0x0 0x800000>;
+               clock-frequency = <66666666>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+
+                       /* IDSEL 0x15 */
+                       0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0
+                       0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0
+                       0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0
+                       0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>;
+       };
+
+       pci2: pcie@fe000a000 {
+               reg = <0xf 0xe000a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xe3000000 0x0 0x100000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       rio: rapidio@fe00c0000 {
+               reg = <0xf 0xe00c0000 0x0 0x20000>;
+               port1 {
+                       ranges = <0x0 0x0 0xc 0x40000000 0x0 0x20000000>;
+               };
+       };
+};
+
+/*
+ * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings
+ * for interrupt-map & interrupt-map-mask.
+ */
+
+/include/ "fsl/mpc8548si-post.dtsi"
+/include/ "mpc8548cds.dtsi"
index c3d4fac..1417894 100644 (file)
                bank-width = <2>;
                device-width = <1>;
 
-               ramdisk@0 {
+               partition@0 {
                        reg = <0x0 0x03000000>;
-                       read-only;
+                       label = "ramdisk-nor";
                };
 
-               diagnostic@3000000 {
+               partition@3000000 {
                        reg = <0x03000000 0x00e00000>;
+                       label = "diagnostic-nor";
                        read-only;
                };
 
-               dink@3e00000 {
+               partition@3e00000 {
                        reg = <0x03e00000 0x00200000>;
+                       label = "dink-nor";
                        read-only;
                };
 
-               kernel@4000000 {
+               partition@4000000 {
                        reg = <0x04000000 0x00400000>;
-                       read-only;
+                       label = "kernel-nor";
                };
 
-               jffs2@4400000 {
+               partition@4400000 {
                        reg = <0x04400000 0x03b00000>;
+                       label = "fs-nor";
+               };
+
+               partition@7f00000 {
+                       reg = <0x07f00000 0x00060000>;
+                       label = "dtb-nor";
                };
 
-               dtb@7f00000 {
-                       reg = <0x07f00000 0x00080000>;
+               partition@7f60000 {
+                       reg = <0x07f60000 0x00020000>;
+                       label = "env-nor";
                        read-only;
                };
 
-               u-boot@7f80000 {
+               partition@7f80000 {
                        reg = <0x07f80000 0x00080000>;
+                       label = "u-boot-nor";
                        read-only;
                };
        };
                             "fsl,elbc-fcm-nand";
                reg = <0x2 0x0 0x40000>;
 
-               u-boot@0 {
+               partition@0 {
                        reg = <0x0 0x02000000>;
+                       label = "u-boot-nand";
                        read-only;
                };
 
-               jffs2@2000000 {
+               partition@2000000 {
                        reg = <0x02000000 0x10000000>;
+                       label = "fs-nand";
                };
 
-               ramdisk@12000000 {
+               partition@12000000 {
                        reg = <0x12000000 0x08000000>;
-                       read-only;
+                       label = "ramdisk-nand";
                };
 
-               kernel@1a000000 {
+               partition@1a000000 {
                        reg = <0x1a000000 0x04000000>;
+                       label = "kernel-nand";
                };
 
-               dtb@1e000000 {
+               partition@1e000000 {
                        reg = <0x1e000000 0x01000000>;
-                       read-only;
+                       label = "dtb-nand";
                };
 
-               empty@1f000000 {
+               partition@1f000000 {
                        reg = <0x1f000000 0x21000000>;
+                       label = "empty-nand";
                };
        };
 
index d4c4a77..4977614 100644 (file)
                        #size-cells = <1>;
                        compatible = "spansion,s25sl12801";
                        reg = <0>;
-                       spi-max-frequency = <50000000>;
+                       spi-max-frequency = <40000000>;
 
                        partition@0 {
                                /* 1MB for u-boot Bootloader Image */
                };
 
                tbi-phy@3 {
-                       device-type = "tbi-phy";
+                       device_type = "tbi-phy";
                        reg = <0x3>;
                };
        };
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi
new file mode 100644 (file)
index 0000000..c952cd3
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * P1020 RDB-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x1000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 256KB for Vitesse 7385 Switch firmware */
+                       reg = <0x0 0x00040000>;
+                       label = "NOR Vitesse-7385 Firmware";
+                       read-only;
+               };
+
+               partition@40000 {
+                       /* 256KB for DTB Image */
+                       reg = <0x00040000 0x00040000>;
+                       label = "NOR DTB Image";
+               };
+
+               partition@80000 {
+                       /* 3.5 MB for Linux Kernel Image */
+                       reg = <0x00080000 0x00380000>;
+                       label = "NOR Linux Kernel Image";
+               };
+
+               partition@400000 {
+                       /* 11MB for JFFS2 based Root file System */
+                       reg = <0x00400000 0x00b00000>;
+                       label = "NOR JFFS2 Root File System";
+               };
+
+               partition@f00000 {
+                       /* This location must not be altered  */
+                       /* 512KB for u-boot Bootloader Image */
+                       /* 512KB for u-boot Environment Variables */
+                       reg = <0x00f00000 0x00100000>;
+                       label = "NOR U-Boot Image";
+                       read-only;
+               };
+       };
+
+       nand@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,p1020-fcm-nand",
+                            "fsl,elbc-fcm-nand";
+               reg = <0x1 0x0 0x40000>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 1MB for u-boot Bootloader Image */
+                       reg = <0x0 0x00100000>;
+                       label = "NAND U-Boot Image";
+                       read-only;
+               };
+
+               partition@100000 {
+                       /* 1MB for DTB Image */
+                       reg = <0x00100000 0x00100000>;
+                       label = "NAND DTB Image";
+               };
+
+               partition@200000 {
+                       /* 4MB for Linux Kernel Image */
+                       reg = <0x00200000 0x00400000>;
+                       label = "NAND Linux Kernel Image";
+               };
+
+               partition@600000 {
+                       /* 4MB for Compressed Root file System Image */
+                       reg = <0x00600000 0x00400000>;
+                       label = "NAND Compressed RFS Image";
+               };
+
+               partition@a00000 {
+                       /* 7MB for JFFS2 based Root file System */
+                       reg = <0x00a00000 0x00700000>;
+                       label = "NAND JFFS2 Root File System";
+               };
+
+               partition@1100000 {
+                       /* 15MB for JFFS2 based Root file System */
+                       reg = <0x01100000 0x00f00000>;
+                       label = "NAND Writable User area";
+               };
+       };
+
+       L2switch@2,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "vitesse-7385";
+               reg = <0x2 0x0 0x20000>;
+       };
+
+       cpld@3,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cpld";
+               reg = <0x3 0x0 0x20000>;
+               read-only;
+       };
+};
+
+&soc {
+       i2c@3000 {
+               rtc@68 {
+                       compatible = "pericom,pt7c4338";
+                       reg = <0x68>;
+               };
+       };
+
+       spi@7000 {
+               flash@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "spansion,s25sl12801";
+                       reg = <0>;
+                       spi-max-frequency = <40000000>; /* input clock */
+
+                       partition@u-boot {
+                               /* 512KB for u-boot Bootloader Image */
+                               reg = <0x0 0x00080000>;
+                               label = "u-boot";
+                               read-only;
+                       };
+
+                       partition@dtb {
+                               /* 512KB for DTB Image*/
+                               reg = <0x00080000 0x00080000>;
+                               label = "dtb";
+                       };
+
+                       partition@kernel {
+                               /* 4MB for Linux Kernel Image */
+                               reg = <0x00100000 0x00400000>;
+                               label = "kernel";
+                       };
+
+                       partition@fs {
+                               /* 4MB for Compressed RFS Image */
+                               reg = <0x00500000 0x00400000>;
+                               label = "file system";
+                       };
+
+                       partition@jffs-fs {
+                               /* 7MB for JFFS2 based RFS */
+                               reg = <0x00900000 0x00700000>;
+                               label = "file system jffs2";
+                       };
+               };
+       };
+
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       /* USB2 is shared with localbus, so it must be disabled
+          by default. We can't put 'status = "disabled";' here
+          since U-Boot doesn't clear the status property when
+          it enables USB2. OTOH, U-Boot does create a new node
+          when there isn't any. So, just comment it out.
+       usb@23000 {
+               phy_type = "ulpi";
+       };
+       */
+
+       mdio@24000 {
+               phy0: ethernet-phy@0 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <3 1>;
+                       reg = <0x0>;
+               };
+
+               phy1: ethernet-phy@1 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <2 1>;
+                       reg = <0x1>;
+               };
+
+               tbi0: tbi-phy@11 {
+                       device_type = "tbi-phy";
+                       reg = <0x11>;
+               };
+       };
+
+       mdio@25000 {
+               tbi1: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet0: ethernet@b0000 {
+               fixed-link = <1 1 1000 0 0>;
+               phy-connection-type = "rgmii-id";
+
+       };
+
+       enet1: ethernet@b1000 {
+               phy-handle = <&phy0>;
+               tbi-handle = <&tbi1>;
+               phy-connection-type = "sgmii";
+       };
+
+       enet2: ethernet@b2000 {
+               phy-handle = <&phy1>;
+               phy-connection-type = "rgmii-id";
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts
new file mode 100644 (file)
index 0000000..4de69b7
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * P1020 RDB-PC Device Tree Source (32-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+       model = "fsl,P1020RDB-PC";
+       compatible = "fsl,P1020RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@ffe05000 {
+               reg = <0 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+               ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+                         0x1 0x0 0x0 0xff800000 0x00040000
+                         0x2 0x0 0x0 0xffb00000 0x00020000
+                         0x3 0x0 0x0 0xffa00000 0x00020000>;
+       };
+
+       soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               reg = <0 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0x80000000
+                                 0x2000000 0x0 0x80000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "p1020rdb-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts
new file mode 100644 (file)
index 0000000..5237da7
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * P1020 RDB-PC Device Tree Source (36-bit address map)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+       model = "fsl,P1020RDB-PC";
+       compatible = "fsl,P1020RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@fffe05000 {
+               reg = <0xf 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+               ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+                         0x1 0x0 0xf 0xff800000 0x00040000
+                         0x2 0x0 0xf 0xffb00000 0x00040000
+                         0x3 0x0 0xf 0xffa00000 0x00020000>;
+       };
+
+       soc: soc@fffe00000 {
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@fffe09000 {
+               reg = <0xf 0xffe09000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xc0000000
+                                 0x2000000 0x0 0xc0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@fffe0a000 {
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0x80000000
+                                 0x2000000 0x0 0x80000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "p1020rdb-pc.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts
new file mode 100644 (file)
index 0000000..f411515
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * P1020 RDB-PC  Core0 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb,
+ * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi.
+ *
+ * Please note to add "-b 0" for core0's dts compiling.
+ *
+ * Copyright 2012 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/ "p1020rdb-pc_32b.dts"
+
+/ {
+       model = "fsl,P1020RDB-PC";
+       compatible = "fsl,P1020RDB-PC";
+
+       aliases {
+               ethernet1 = &enet1;
+               ethernet2 = &enet2;
+               serial0 = &serial0;
+               pci0 = &pci0;
+               pci1 = &pci1;
+       };
+
+       cpus {
+               PowerPC,P1020@1 {
+                       status = "disabled";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+       };
+
+       localbus@ffe05000 {
+               status = "disabled";
+       };
+
+       soc@ffe00000 {
+               serial1: serial@4600 {
+                       status = "disabled";
+               };
+
+               enet0: ethernet@b0000 {
+                       status = "disabled";
+               };
+
+               mpic: pic@40000 {
+                       protected-sources = <
+                       42 29 30 34     /* serial1, enet0-queue-group0 */
+                       17 18 24 45     /* enet0-queue-group1, crypto */
+                       >;
+                       pic-no-reset;
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts
new file mode 100644 (file)
index 0000000..a91335a
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * P1020 RDB-PC Core1 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts allows core1 to have l2, eth0, crypto.
+ *
+ * Please note to add "-b 1" for core1's dts compiling.
+ *
+ * Copyright 2012 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/ "p1020rdb-pc_32b.dts"
+
+/ {
+       model = "fsl,P1020RDB-PC";
+       compatible = "fsl,P1020RDB-PC";
+
+       aliases {
+               ethernet0 = &enet0;
+               serial0 = &serial1;
+               };
+
+       cpus {
+               PowerPC,P1020@0 {
+                       status = "disabled";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+       };
+
+       localbus@ffe05000 {
+               status = "disabled";
+       };
+
+       soc@ffe00000 {
+               ecm-law@0 {
+                       status = "disabled";
+               };
+
+               ecm@1000 {
+                       status = "disabled";
+               };
+
+               memory-controller@2000 {
+                       status = "disabled";
+               };
+
+               i2c@3000 {
+                       status = "disabled";
+               };
+
+               i2c@3100 {
+                       status = "disabled";
+               };
+
+               serial0: serial@4500 {
+                       status = "disabled";
+               };
+
+               spi@7000 {
+                       status = "disabled";
+               };
+
+               gpio: gpio-controller@f000 {
+                       status = "disabled";
+               };
+
+               dma@21300 {
+                       status = "disabled";
+               };
+
+               mdio@24000 {
+                       status = "disabled";
+               };
+
+               mdio@25000 {
+                       status = "disabled";
+               };
+
+               enet1: ethernet@b1000 {
+                       status = "disabled";
+               };
+
+               enet2: ethernet@b2000 {
+                       status = "disabled";
+               };
+
+               usb@22000 {
+                       status = "disabled";
+               };
+
+               sdhci@2e000 {
+                       status = "disabled";
+               };
+
+               mpic: pic@40000 {
+                       protected-sources = <
+                       16              /* ecm, mem, L2, pci0, pci1 */
+                       43 42 59        /* i2c, serial0, spi */
+                       47 63 62        /* gpio, tdm */
+                       20 21 22 23     /* dma */
+                       03 02           /* mdio */
+                       35 36 40        /* enet1-queue-group0 */
+                       51 52 67        /* enet1-queue-group1 */
+                       31 32 33        /* enet2-queue-group0 */
+                       25 26 27        /* enet2-queue-group1 */
+                       28 72 58        /* usb, sdhci, crypto */
+                       0xb0 0xb1 0xb2  /* message */
+                       0xb3 0xb4 0xb5
+                       0xb6 0xb7
+                       0xe0 0xe1 0xe2  /* msi */
+                       0xe3 0xe4 0xe5
+                       0xe6 0xe7               /* sdhci, crypto , pci */
+                       >;
+                       pic-no-reset;
+               };
+
+               msi@41600 {
+                       status = "disabled";
+               };
+
+               global-utilities@e0000 {        //global utilities block
+                       status = "disabled";
+               };
+       };
+
+       pci0: pcie@ffe09000 {
+               status = "disabled";
+       };
+
+       pci1: pcie@ffe0a000 {
+               status = "disabled";
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1021rdb.dts b/arch/powerpc/boot/dts/p1021rdb.dts
new file mode 100644 (file)
index 0000000..90b6b4c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * P1021 RDB Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+       model = "fsl,P1021RDB";
+       compatible = "fsl,P1021RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@ffe05000 {
+               reg = <0 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+               ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+                         0x1 0x0 0x0 0xff800000 0x00040000
+                         0x2 0x0 0x0 0xffb00000 0x00020000>;
+       };
+
+       soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               reg = <0 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0x80000000
+                                 0x2000000 0x0 0x80000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       qe: qe@ffe80000 {
+                ranges = <0x0 0x0 0xffe80000 0x40000>;
+                reg = <0 0xffe80000 0 0x480>;
+                brg-frequency = <0>;
+                bus-frequency = <0>;
+        };
+};
+
+/include/ "p1021rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1021rdb.dtsi b/arch/powerpc/boot/dts/p1021rdb.dtsi
new file mode 100644 (file)
index 0000000..b973461
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * P1021 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x1000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 256KB for Vitesse 7385 Switch firmware */
+                       reg = <0x0 0x00040000>;
+                       label = "NOR Vitesse-7385 Firmware";
+                       read-only;
+               };
+
+               partition@40000 {
+                       /* 256KB for DTB Image */
+                       reg = <0x00040000 0x00040000>;
+                       label = "NOR DTB Image";
+               };
+
+               partition@80000 {
+                       /* 3.5 MB for Linux Kernel Image */
+                       reg = <0x00080000 0x00380000>;
+                       label = "NOR Linux Kernel Image";
+               };
+
+               partition@400000 {
+                       /* 11MB for JFFS2 based Root file System */
+                       reg = <0x00400000 0x00b00000>;
+                       label = "NOR JFFS2 Root File System";
+               };
+
+               partition@f00000 {
+                       /* This location must not be altered  */
+                       /* 512KB for u-boot Bootloader Image */
+                       /* 512KB for u-boot Environment Variables */
+                       reg = <0x00f00000 0x00100000>;
+                       label = "NOR U-Boot Image";
+               };
+       };
+
+       nand@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,p1021-fcm-nand",
+                            "fsl,elbc-fcm-nand";
+               reg = <0x1 0x0 0x40000>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 1MB for u-boot Bootloader Image */
+                       reg = <0x0 0x00100000>;
+                       label = "NAND U-Boot Image";
+                       read-only;
+               };
+
+               partition@100000 {
+                       /* 1MB for DTB Image */
+                       reg = <0x00100000 0x00100000>;
+                       label = "NAND DTB Image";
+               };
+
+               partition@200000 {
+                       /* 4MB for Linux Kernel Image */
+                       reg = <0x00200000 0x00400000>;
+                       label = "NAND Linux Kernel Image";
+               };
+
+               partition@600000 {
+                       /* 4MB for Compressed Root file System Image */
+                       reg = <0x00600000 0x00400000>;
+                       label = "NAND Compressed RFS Image";
+               };
+
+               partition@a00000 {
+                       /* 7MB for JFFS2 based Root file System */
+                       reg = <0x00a00000 0x00700000>;
+                       label = "NAND JFFS2 Root File System";
+               };
+
+               partition@1100000 {
+                       /* 15MB for User Writable Area  */
+                       reg = <0x01100000 0x00f00000>;
+                       label = "NAND Writable User area";
+               };
+       };
+
+       L2switch@2,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "vitesse-7385";
+               reg = <0x2 0x0 0x20000>;
+       };
+};
+
+&soc {
+       i2c@3000 {
+               rtc@68 {
+                       compatible = "pericom,pt7c4338";
+                       reg = <0x68>;
+               };
+       };
+
+       spi@7000 {
+               flash@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "spansion,s25sl12801";
+                       reg = <0>;
+                       spi-max-frequency = <40000000>; /* input clock */
+
+                       partition@u-boot {
+                               /* 512KB for u-boot Bootloader Image */
+                               reg = <0x0 0x00080000>;
+                               label = "SPI Flash U-Boot Image";
+                               read-only;
+                       };
+
+                       partition@dtb {
+                               /* 512KB for DTB Image */
+                               reg = <0x00080000 0x00080000>;
+                               label = "SPI Flash DTB Image";
+                       };
+
+                       partition@kernel {
+                               /* 4MB for Linux Kernel Image */
+                               reg = <0x00100000 0x00400000>;
+                               label = "SPI Flash Linux Kernel Image";
+                       };
+
+                       partition@fs {
+                               /* 4MB for Compressed RFS Image */
+                               reg = <0x00500000 0x00400000>;
+                               label = "SPI Flash Compressed RFSImage";
+                       };
+
+                       partition@jffs-fs {
+                               /* 7MB for JFFS2 based RFS */
+                               reg = <0x00900000 0x00700000>;
+                               label = "SPI Flash JFFS2 RFS";
+                       };
+               };
+       };
+
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       mdio@24000 {
+               phy0: ethernet-phy@0 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <3 1 0 0>;
+                       reg = <0x0>;
+               };
+
+               phy1: ethernet-phy@1 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <2 1 0 0>;
+                       reg = <0x1>;
+               };
+
+               tbi0: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@25000 {
+               tbi1: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@26000 {
+               tbi2: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet0: ethernet@b0000 {
+               fixed-link = <1 1 1000 0 0>;
+               phy-connection-type = "rgmii-id";
+
+       };
+
+       enet1: ethernet@b1000 {
+               phy-handle = <&phy0>;
+               tbi-handle = <&tbi1>;
+               phy-connection-type = "sgmii";
+       };
+
+       enet2: ethernet@b2000 {
+               phy-handle = <&phy1>;
+               tbi-handle = <&tbi2>;
+               phy-connection-type = "rgmii-id";
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1021rdb_36b.dts b/arch/powerpc/boot/dts/p1021rdb_36b.dts
new file mode 100644 (file)
index 0000000..ea6d8b5
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * P1021 RDB Device Tree Source (36-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+       model = "fsl,P1021RDB";
+       compatible = "fsl,P1021RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@fffe05000 {
+               reg = <0xf 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes and Vitesse 5 port L2 switch */
+               ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+                         0x1 0x0 0xf 0xff800000 0x00040000
+                         0x2 0x0 0xf 0xffb00000 0x00020000>;
+       };
+
+       soc: soc@fffe00000 {
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@fffe09000 {
+               ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+               reg = <0xf 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@fffe0a000 {
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xc0000000
+                                 0x2000000 0x0 0xc0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       qe: qe@fffe80000 {
+                ranges = <0x0 0xf 0xffe80000 0x40000>;
+                reg = <0xf 0xffe80000 0 0x480>;
+                brg-frequency = <0>;
+                bus-frequency = <0>;
+        };
+};
+
+/include/ "p1021rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
deleted file mode 100644 (file)
index ef95717..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * P1022 DS 36Bit Physical Address Map Device Tree Source
- *
- * Copyright 2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-/include/ "fsl/p1022si-pre.dtsi"
-/ {
-       model = "fsl,P1022DS";
-       compatible = "fsl,P1022DS";
-
-       memory {
-               device_type = "memory";
-       };
-
-       lbc: localbus@fffe05000 {
-               reg = <0xf 0xffe05000 0 0x1000>;
-               ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
-                         0x1 0x0 0xf 0xe0000000 0x08000000
-                         0x2 0x0 0xf 0xff800000 0x00040000
-                         0x3 0x0 0xf 0xffdf0000 0x00008000>;
-
-               /*
-                * This node is used to access the pixis via "indirect" mode,
-                * which is done by writing the pixis register index to chip
-                * select 0 and the value to/from chip select 1.  Indirect
-                * mode is the only way to access the pixis when DIU video
-                * is enabled.  Note that this assumes that the first column
-                * of the 'ranges' property above is the chip select number.
-                */
-               board-control@0,0 {
-                       compatible = "fsl,p1022ds-indirect-pixis";
-                       reg = <0x0 0x0 1        /* CS0 */
-                              0x1 0x0 1>;      /* CS1 */
-               };
-
-               nor@0,0 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "cfi-flash";
-                       reg = <0x0 0x0 0x8000000>;
-                       bank-width = <2>;
-                       device-width = <1>;
-
-                       partition@0 {
-                               reg = <0x0 0x03000000>;
-                               label = "ramdisk-nor";
-                               read-only;
-                       };
-
-                       partition@3000000 {
-                               reg = <0x03000000 0x00e00000>;
-                               label = "diagnostic-nor";
-                               read-only;
-                       };
-
-                       partition@3e00000 {
-                               reg = <0x03e00000 0x00200000>;
-                               label = "dink-nor";
-                               read-only;
-                       };
-
-                       partition@4000000 {
-                               reg = <0x04000000 0x00400000>;
-                               label = "kernel-nor";
-                               read-only;
-                       };
-
-                       partition@4400000 {
-                               reg = <0x04400000 0x03b00000>;
-                               label = "jffs2-nor";
-                       };
-
-                       partition@7f00000 {
-                               reg = <0x07f00000 0x00080000>;
-                               label = "dtb-nor";
-                               read-only;
-                       };
-
-                       partition@7f80000 {
-                               reg = <0x07f80000 0x00080000>;
-                               label = "u-boot-nor";
-                               read-only;
-                       };
-               };
-
-               nand@2,0 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "fsl,elbc-fcm-nand";
-                       reg = <0x2 0x0 0x40000>;
-
-                       partition@0 {
-                               reg = <0x0 0x02000000>;
-                               label = "u-boot-nand";
-                               read-only;
-                       };
-
-                       partition@2000000 {
-                               reg = <0x02000000 0x10000000>;
-                               label = "jffs2-nand";
-                       };
-
-                       partition@12000000 {
-                               reg = <0x12000000 0x10000000>;
-                               label = "ramdisk-nand";
-                               read-only;
-                       };
-
-                       partition@22000000 {
-                               reg = <0x22000000 0x04000000>;
-                               label = "kernel-nand";
-                       };
-
-                       partition@26000000 {
-                               reg = <0x26000000 0x01000000>;
-                               label = "dtb-nand";
-                               read-only;
-                       };
-
-                       partition@27000000 {
-                               reg = <0x27000000 0x19000000>;
-                               label = "reserved-nand";
-                       };
-               };
-
-               board-control@3,0 {
-                       compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
-                       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 0 0>;
-               };
-       };
-
-       soc: soc@fffe00000 {
-               ranges = <0x0 0xf 0xffe00000 0x100000>;
-
-               i2c@3100 {
-                       wm8776:codec@1a {
-                               compatible = "wlf,wm8776";
-                               reg = <0x1a>;
-                               /*
-                                * clock-frequency will be set by U-Boot if
-                                * the clock is enabled.
-                                */
-                       };
-               };
-
-               spi@7000 {
-                       flash@0 {
-                               #address-cells = <1>;
-                               #size-cells = <1>;
-                               compatible = "spansion,s25sl12801";
-                               reg = <0>;
-                               spi-max-frequency = <40000000>; /* input clock */
-
-                               partition@0 {
-                                       label = "u-boot-spi";
-                                       reg = <0x00000000 0x00100000>;
-                                       read-only;
-                               };
-                               partition@100000 {
-                                       label = "kernel-spi";
-                                       reg = <0x00100000 0x00500000>;
-                                       read-only;
-                               };
-                               partition@600000 {
-                                       label = "dtb-spi";
-                                       reg = <0x00600000 0x00100000>;
-                                       read-only;
-                               };
-                               partition@700000 {
-                                       label = "file system-spi";
-                                       reg = <0x00700000 0x00900000>;
-                               };
-                       };
-               };
-
-               ssi@15000 {
-                       fsl,mode = "i2s-slave";
-                       codec-handle = <&wm8776>;
-                       fsl,ssi-asynchronous;
-               };
-
-               usb@22000 {
-                       phy_type = "ulpi";
-               };
-
-               usb@23000 {
-                       status = "disabled";
-               };
-
-               mdio@24000 {
-                       phy0: ethernet-phy@0 {
-                               interrupts = <3 1 0 0>;
-                               reg = <0x1>;
-                       };
-                       phy1: ethernet-phy@1 {
-                               interrupts = <9 1 0 0>;
-                               reg = <0x2>;
-                       };
-                       tbi-phy@2 {
-                               device_type = "tbi-phy";
-                               reg = <0x2>;
-                       };
-               };
-
-               ethernet@b0000 {
-                       phy-handle = <&phy0>;
-                       phy-connection-type = "rgmii-id";
-               };
-
-               ethernet@b1000 {
-                       phy-handle = <&phy1>;
-                       phy-connection-type = "rgmii-id";
-               };
-       };
-
-       pci0: pcie@fffe09000 {
-               reg = <0xf 0xffe09000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xe0000000
-                                 0x2000000 0x0 0xe0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-
-       pci1: pcie@fffe0a000 {
-               reg = <0xf 0xffe0a000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
-               pcie@0 {
-                       reg = <0x0 0x0 0x0 0x0 0x0>;
-                       ranges = <0x2000000 0x0 0xe0000000
-                                 0x2000000 0x0 0xe0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-
-       pci2: pcie@fffe0b000 {
-               reg = <0xf 0xffe0b000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xe0000000
-                                 0x2000000 0x0 0xe0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-};
-
-/include/ "fsl/p1022si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi
new file mode 100644 (file)
index 0000000..7cdb505
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * P1022 DS Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&board_lbc {
+       /*
+        * This node is used to access the pixis via "indirect" mode,
+        * which is done by writing the pixis register index to chip
+        * select 0 and the value to/from chip select 1.  Indirect
+        * mode is the only way to access the pixis when DIU video
+        * is enabled.  Note that this assumes that the first column
+        * of the 'ranges' property above is the chip select number.
+        */
+       board-control@0,0 {
+               compatible = "fsl,p1022ds-indirect-pixis";
+               reg = <0x0 0x0 1        /* CS0 */
+                      0x1 0x0 1>;      /* CS1 */
+               interrupt-parent = <&mpic>;
+               interrupts = <8 0 0 0>;
+       };
+
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x8000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       reg = <0x0 0x03000000>;
+                       label = "ramdisk-nor";
+                       read-only;
+               };
+
+               partition@3000000 {
+                       reg = <0x03000000 0x00e00000>;
+                       label = "diagnostic-nor";
+                       read-only;
+               };
+
+               partition@3e00000 {
+                       reg = <0x03e00000 0x00200000>;
+                       label = "dink-nor";
+                       read-only;
+               };
+
+               partition@4000000 {
+                       reg = <0x04000000 0x00400000>;
+                       label = "kernel-nor";
+                       read-only;
+               };
+
+               partition@4400000 {
+                       reg = <0x04400000 0x03b00000>;
+                       label = "jffs2-nor";
+               };
+
+               partition@7f00000 {
+                       reg = <0x07f00000 0x00080000>;
+                       label = "dtb-nor";
+                       read-only;
+               };
+
+               partition@7f80000 {
+                       reg = <0x07f80000 0x00080000>;
+                       label = "u-boot-nor";
+                       read-only;
+               };
+       };
+
+       nand@2,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,elbc-fcm-nand";
+               reg = <0x2 0x0 0x40000>;
+
+               partition@0 {
+                       reg = <0x0 0x02000000>;
+                       label = "u-boot-nand";
+                       read-only;
+               };
+
+               partition@2000000 {
+                       reg = <0x02000000 0x10000000>;
+                       label = "jffs2-nand";
+               };
+
+               partition@12000000 {
+                       reg = <0x12000000 0x10000000>;
+                       label = "ramdisk-nand";
+                       read-only;
+               };
+
+               partition@22000000 {
+                       reg = <0x22000000 0x04000000>;
+                       label = "kernel-nand";
+               };
+
+               partition@26000000 {
+                       reg = <0x26000000 0x01000000>;
+                       label = "dtb-nand";
+                       read-only;
+               };
+
+               partition@27000000 {
+                       reg = <0x27000000 0x19000000>;
+                       label = "reserved-nand";
+               };
+       };
+
+       board-control@3,0 {
+               compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
+               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 0 0 0>;
+       };
+};
+
+&board_soc {
+       i2c@3100 {
+               wm8776:codec@1a {
+                       compatible = "wlf,wm8776";
+                       reg = <0x1a>;
+                       /*
+                        * clock-frequency will be set by U-Boot if
+                        * the clock is enabled.
+                        */
+               };
+       };
+
+       spi@7000 {
+               flash@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "spansion,s25sl12801";
+                       reg = <0>;
+                       spi-max-frequency = <40000000>; /* input clock */
+
+                       partition@0 {
+                               label = "u-boot-spi";
+                               reg = <0x00000000 0x00100000>;
+                               read-only;
+                       };
+                       partition@100000 {
+                               label = "kernel-spi";
+                               reg = <0x00100000 0x00500000>;
+                               read-only;
+                       };
+                       partition@600000 {
+                               label = "dtb-spi";
+                               reg = <0x00600000 0x00100000>;
+                               read-only;
+                       };
+                       partition@700000 {
+                               label = "file system-spi";
+                               reg = <0x00700000 0x00900000>;
+                       };
+               };
+       };
+
+       ssi@15000 {
+               fsl,mode = "i2s-slave";
+               codec-handle = <&wm8776>;
+               fsl,ssi-asynchronous;
+       };
+
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       usb@23000 {
+               status = "disabled";
+       };
+
+       mdio@24000 {
+               phy0: ethernet-phy@0 {
+                       interrupts = <3 1 0 0>;
+                       reg = <0x1>;
+               };
+               phy1: ethernet-phy@1 {
+                       interrupts = <9 1 0 0>;
+                       reg = <0x2>;
+               };
+               tbi-phy@2 {
+                       device_type = "tbi-phy";
+                       reg = <0x2>;
+               };
+       };
+
+       ethernet@b0000 {
+               phy-handle = <&phy0>;
+               phy-connection-type = "rgmii-id";
+       };
+
+       ethernet@b1000 {
+               phy-handle = <&phy1>;
+               phy-connection-type = "rgmii-id";
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts
new file mode 100644 (file)
index 0000000..d96cae0
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * P1022 DS 32-bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+       model = "fsl,P1022DS";
+       compatible = "fsl,P1022DS";
+
+       memory {
+               device_type = "memory";
+       };
+
+       board_lbc: lbc: localbus@ffe05000 {
+               ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+                         0x1 0x0 0x0 0xe0000000 0x08000000
+                         0x2 0x0 0x0 0xff800000 0x00040000
+                         0x3 0x0 0x0 0xffdf0000 0x00008000>;
+               reg = <0x0 0xffe05000 0 0x1000>;
+       };
+
+       board_soc: soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0x0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+               reg = <0 0xffe0a000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci2: pcie@ffe0b000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               reg = <0 0xffe0b000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "fsl/p1022si-post.dtsi"
+/include/ "p1022ds.dtsi"
diff --git a/arch/powerpc/boot/dts/p1022ds_36b.dts b/arch/powerpc/boot/dts/p1022ds_36b.dts
new file mode 100644 (file)
index 0000000..f7aacce
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * P1022 DS 36-bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+       model = "fsl,P1022DS";
+       compatible = "fsl,P1022DS";
+
+       memory {
+               device_type = "memory";
+       };
+
+       board_lbc: lbc: localbus@fffe05000 {
+               ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
+                         0x1 0x0 0xf 0xe0000000 0x08000000
+                         0x2 0x0 0xf 0xff800000 0x00040000
+                         0x3 0x0 0xf 0xffdf0000 0x00008000>;
+               reg = <0xf 0xffe05000 0 0x1000>;
+       };
+
+       board_soc: soc: soc@fffe00000 {
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@fffe09000 {
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+               reg = <0xf 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@fffe0a000 {
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci2: pcie@fffe0b000 {
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+               reg = <0xf 0xffe0b000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "fsl/p1022si-post.dtsi"
+/include/ "p1022ds.dtsi"
diff --git a/arch/powerpc/boot/dts/p1025rdb.dtsi b/arch/powerpc/boot/dts/p1025rdb.dtsi
new file mode 100644 (file)
index 0000000..cf3676f
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * P1025 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x1000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 256KB for Vitesse 7385 Switch firmware */
+                       reg = <0x0 0x00040000>;
+                       label = "NOR Vitesse-7385 Firmware";
+                       read-only;
+               };
+
+               partition@40000 {
+                       /* 256KB for DTB Image */
+                       reg = <0x00040000 0x00040000>;
+                       label = "NOR DTB Image";
+               };
+
+               partition@80000 {
+                       /* 3.5 MB for Linux Kernel Image */
+                       reg = <0x00080000 0x00380000>;
+                       label = "NOR Linux Kernel Image";
+               };
+
+               partition@400000 {
+                       /* 11MB for JFFS2 based Root file System */
+                       reg = <0x00400000 0x00b00000>;
+                       label = "NOR JFFS2 Root File System";
+               };
+
+               partition@f00000 {
+                       /* This location must not be altered  */
+                       /* 512KB for u-boot Bootloader Image */
+                       /* 512KB for u-boot Environment Variables */
+                       reg = <0x00f00000 0x00100000>;
+                       label = "NOR U-Boot Image";
+                       read-only;
+               };
+       };
+
+       nand@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,p1025-fcm-nand",
+                            "fsl,elbc-fcm-nand";
+               reg = <0x1 0x0 0x40000>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 1MB for u-boot Bootloader Image */
+                       reg = <0x0 0x00100000>;
+                       label = "NAND U-Boot Image";
+                       read-only;
+               };
+
+               partition@100000 {
+                       /* 1MB for DTB Image */
+                       reg = <0x00100000 0x00100000>;
+                       label = "NAND DTB Image";
+               };
+
+               partition@200000 {
+                       /* 4MB for Linux Kernel Image */
+                       reg = <0x00200000 0x00400000>;
+                       label = "NAND Linux Kernel Image";
+               };
+
+               partition@600000 {
+                       /* 4MB for Compressed Root file System Image */
+                       reg = <0x00600000 0x00400000>;
+                       label = "NAND Compressed RFS Image";
+               };
+
+               partition@a00000 {
+                       /* 7MB for JFFS2 based Root file System */
+                       reg = <0x00a00000 0x00700000>;
+                       label = "NAND JFFS2 Root File System";
+               };
+
+               partition@1100000 {
+                       /* 15MB for JFFS2 based Root file System */
+                       reg = <0x01100000 0x00f00000>;
+                       label = "NAND Writable User area";
+               };
+       };
+
+};
+
+&soc {
+       i2c@3000 {
+               rtc@68 {
+                       compatible = "dallas,ds1339";
+                       reg = <0x68>;
+               };
+       };
+
+       spi@7000 {
+               flash@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "spansion,s25sl12801";
+                       reg = <0>;
+                       spi-max-frequency = <40000000>; /* input clock */
+
+                       partition@u-boot {
+                               /* 512KB for u-boot Bootloader Image */
+                               reg = <0x0 0x00080000>;
+                               label = "u-boot";
+                               read-only;
+                       };
+
+                       partition@dtb {
+                               /* 512KB for DTB Image */
+                               reg = <0x00080000 0x00080000>;
+                               label = "dtb";
+                       };
+
+                       partition@kernel {
+                               /* 4MB for Linux Kernel Image */
+                               reg = <0x00100000 0x00400000>;
+                               label = "kernel";
+                       };
+
+                       partition@fs {
+                               /* 4MB for Compressed RFS Image */
+                               reg = <0x00500000 0x00400000>;
+                               label = "file system";
+                       };
+
+                       partition@jffs-fs {
+                               /* 7MB for JFFS2 based RFS */
+                               reg = <0x00900000 0x00700000>;
+                               label = "file system jffs2";
+                       };
+               };
+       };
+
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       /* USB2 is shared with localbus, so it must be disabled
+          by default. We can't put 'status = "disabled";' here
+          since U-Boot doesn't clear the status property when
+          it enables USB2. OTOH, U-Boot does create a new node
+          when there isn't any. So, just comment it out.
+       usb@23000 {
+               phy_type = "ulpi";
+       };
+       */
+
+       mdio@24000 {
+               phy0: ethernet-phy@0 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <3 1>;
+                       reg = <0x0>;
+               };
+
+               phy1: ethernet-phy@1 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <2 1>;
+                       reg = <0x1>;
+               };
+
+               tbi0: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@25000 {
+               tbi1: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@26000 {
+               tbi2: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet0: ethernet@b0000 {
+               fixed-link = <1 1 1000 0 0>;
+               phy-connection-type = "rgmii-id";
+
+       };
+
+       enet1: ethernet@b1000 {
+               phy-handle = <&phy0>;
+               tbi-handle = <&tbi1>;
+               phy-connection-type = "sgmii";
+       };
+
+       enet2: ethernet@b2000 {
+               phy-handle = <&phy1>;
+               phy-connection-type = "rgmii-id";
+       };
+
+       par_io@e0100 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0xe0100 0x60>;
+               ranges = <0x0 0xe0100 0x60>;
+               device_type = "par_io";
+               num-ports = <3>;
+               pio1: ucc_pin@01 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+                               0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+                               0x0  0x17 0x2  0x0  0x2  0x0    /* CLK12 */
+                               0x0  0x18 0x2  0x0  0x1  0x0    /* CLK9 */
+                               0x0  0x7  0x1  0x0  0x2  0x0    /* ENET1_TXD0_SER1_TXD0 */
+                               0x0  0x9  0x1  0x0  0x2  0x0    /* ENET1_TXD1_SER1_TXD1 */
+                               0x0  0xb  0x1  0x0  0x2  0x0    /* ENET1_TXD2_SER1_TXD2 */
+                               0x0  0xc  0x1  0x0  0x2  0x0    /* ENET1_TXD3_SER1_TXD3 */
+                               0x0  0x6  0x2  0x0  0x2  0x0    /* ENET1_RXD0_SER1_RXD0 */
+                               0x0  0xa  0x2  0x0  0x2  0x0    /* ENET1_RXD1_SER1_RXD1 */
+                               0x0  0xe  0x2  0x0  0x2  0x0    /* ENET1_RXD2_SER1_RXD2 */
+                               0x0  0xf  0x2  0x0  0x2  0x0    /* ENET1_RXD3_SER1_RXD3 */
+                               0x0  0x5  0x1  0x0  0x2  0x0    /* ENET1_TX_EN_SER1_RTS_B */
+                               0x0  0xd  0x1  0x0  0x2  0x0    /* ENET1_TX_ER */
+                               0x0  0x4  0x2  0x0  0x2  0x0    /* ENET1_RX_DV_SER1_CTS_B */
+                               0x0  0x8  0x2  0x0  0x2  0x0    /* ENET1_RX_ER_SER1_CD_B */
+                               0x0  0x11 0x2  0x0  0x2  0x0    /* ENET1_CRS */
+                               0x0  0x10 0x2  0x0  0x2  0x0>;    /* ENET1_COL */
+               };
+
+               pio2: ucc_pin@02 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+                               0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+                               0x1  0xb  0x2  0x0  0x1  0x0    /* CLK13 */
+                               0x1  0x7  0x1  0x0  0x2  0x0    /* ENET5_TXD0_SER5_TXD0 */
+                               0x1  0xa  0x1  0x0  0x2  0x0    /* ENET5_TXD1_SER5_TXD1 */
+                               0x1  0x6  0x2  0x0  0x2  0x0    /* ENET5_RXD0_SER5_RXD0 */
+                               0x1  0x9  0x2  0x0  0x2  0x0    /* ENET5_RXD1_SER5_RXD1 */
+                               0x1  0x5  0x1  0x0  0x2  0x0    /* ENET5_TX_EN_SER5_RTS_B */
+                               0x1  0x4  0x2  0x0  0x2  0x0    /* ENET5_RX_DV_SER5_CTS_B */
+                               0x1  0x8  0x2  0x0  0x2  0x0>;    /* ENET5_RX_ER_SER5_CD_B */
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1025rdb_32b.dts b/arch/powerpc/boot/dts/p1025rdb_32b.dts
new file mode 100644 (file)
index 0000000..ac5729c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * P1025 RDB Device Tree Source (32-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+       model = "fsl,P1025RDB";
+       compatible = "fsl,P1025RDB";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@ffe05000 {
+               reg = <0 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes */
+               ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+                         0x1 0x0 0x0 0xff800000 0x00040000>;
+       };
+
+       soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               reg = <0 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       qe: qe@ffe80000 {
+               ranges = <0x0 0x0 0xffe80000 0x40000>;
+               reg = <0 0xffe80000 0 0x480>;
+               brg-frequency = <0>;
+               bus-frequency = <0>;
+               status = "disabled"; /* no firmware loaded */
+
+               enet3: ucc@2000 {
+                       device_type = "network";
+                       compatible = "ucc_geth";
+                       rx-clock-name = "clk12";
+                       tx-clock-name = "clk9";
+                       pio-handle = <&pio1>;
+                       phy-handle = <&qe_phy0>;
+                       phy-connection-type = "mii";
+               };
+
+               mdio@2120 {
+                       qe_phy0: ethernet-phy@0 {
+                               interrupt-parent = <&mpic>;
+                               interrupts = <4 1 0 0>;
+                               reg = <0x6>;
+                               device_type = "ethernet-phy";
+                       };
+                       qe_phy1: ethernet-phy@03 {
+                               interrupt-parent = <&mpic>;
+                               interrupts = <5 1 0 0>;
+                               reg = <0x3>;
+                               device_type = "ethernet-phy";
+                       };
+                       tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
+               enet4: ucc@2400 {
+                       device_type = "network";
+                       compatible = "ucc_geth";
+                       rx-clock-name = "none";
+                       tx-clock-name = "clk13";
+                       pio-handle = <&pio2>;
+                       phy-handle = <&qe_phy1>;
+                       phy-connection-type = "rmii";
+               };
+       };
+};
+
+/include/ "p1025rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1025rdb_36b.dts b/arch/powerpc/boot/dts/p1025rdb_36b.dts
new file mode 100644 (file)
index 0000000..4ce4bfa
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * P1025 RDB Device Tree Source (36-bit address map)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p1021si-pre.dtsi"
+/ {
+       model = "fsl,P1025RDB";
+       compatible = "fsl,P1025RDB";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@fffe05000 {
+               reg = <0xf 0xffe05000 0 0x1000>;
+
+               /* NOR, NAND Flashes */
+               ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+                         0x1 0x0 0xf 0xff800000 0x00040000>;
+       };
+
+       soc: soc@fffe00000 {
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@fffe09000 {
+               reg = <0xf 0xffe09000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xe 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@fffe0a000 {
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "p1025rdb.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi
new file mode 100644 (file)
index 0000000..c21d1c7
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * P2020 RDB-PC Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x1000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 256KB for Vitesse 7385 Switch firmware */
+                       reg = <0x0 0x00040000>;
+                       label = "NOR Vitesse-7385 Firmware";
+                       read-only;
+               };
+
+               partition@40000 {
+                       /* 256KB for DTB Image */
+                       reg = <0x00040000 0x00040000>;
+                       label = "NOR DTB Image";
+               };
+
+               partition@80000 {
+                       /* 3.5 MB for Linux Kernel Image */
+                       reg = <0x00080000 0x00380000>;
+                       label = "NOR Linux Kernel Image";
+               };
+
+               partition@400000 {
+                       /* 11MB for JFFS2 based Root file System */
+                       reg = <0x00400000 0x00b00000>;
+                       label = "NOR JFFS2 Root File System";
+               };
+
+               partition@f00000 {
+                       /* This location must not be altered  */
+                       /* 512KB for u-boot Bootloader Image */
+                       /* 512KB for u-boot Environment Variables */
+                       reg = <0x00f00000 0x00100000>;
+                       label = "NOR U-Boot Image";
+                       read-only;
+               };
+       };
+
+       nand@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,p2020-fcm-nand",
+                                "fsl,elbc-fcm-nand";
+               reg = <0x1 0x0 0x40000>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 1MB for u-boot Bootloader Image */
+                       reg = <0x0 0x00100000>;
+                       label = "NAND U-Boot Image";
+                       read-only;
+               };
+
+               partition@100000 {
+                       /* 1MB for DTB Image */
+                       reg = <0x00100000 0x00100000>;
+                       label = "NAND DTB Image";
+               };
+
+               partition@200000 {
+                       /* 4MB for Linux Kernel Image */
+                       reg = <0x00200000 0x00400000>;
+                       label = "NAND Linux Kernel Image";
+               };
+
+               partition@600000 {
+                       /* 4MB for Compressed Root file System Image */
+                       reg = <0x00600000 0x00400000>;
+                       label = "NAND Compressed RFS Image";
+               };
+
+               partition@a00000 {
+                       /* 7MB for JFFS2 based Root file System */
+                       reg = <0x00a00000 0x00700000>;
+                       label = "NAND JFFS2 Root File System";
+               };
+
+               partition@1100000 {
+                       /* 15MB for JFFS2 based Root file System */
+                       reg = <0x01100000 0x00f00000>;
+                       label = "NAND Writable User area";
+               };
+       };
+
+       L2switch@2,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "vitesse-7385";
+               reg = <0x2 0x0 0x20000>;
+       };
+
+       cpld@3,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cpld";
+               reg = <0x3 0x0 0x20000>;
+               read-only;
+       };
+};
+
+&soc {
+       i2c@3000 {
+               rtc@68 {
+                       compatible = "pericom,pt7c4338";
+                       reg = <0x68>;
+               };
+       };
+
+       spi@7000 {
+               flash@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "spansion,m25p80";
+                       reg = <0>;
+                       spi-max-frequency = <40000000>;
+
+                       partition@0 {
+                               /* 512KB for u-boot Bootloader Image */
+                               reg = <0x0 0x00080000>;
+                               label = "SPI U-Boot Image";
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               /* 512KB for DTB Image */
+                               reg = <0x00080000 0x00080000>;
+                               label = "SPI DTB Image";
+                       };
+
+                       partition@100000 {
+                               /* 4MB for Linux Kernel Image */
+                               reg = <0x00100000 0x00400000>;
+                               label = "SPI Linux Kernel Image";
+                       };
+
+                       partition@500000 {
+                               /* 4MB for Compressed RFS Image */
+                               reg = <0x00500000 0x00400000>;
+                               label = "SPI Compressed RFS Image";
+                       };
+
+                       partition@900000 {
+                               /* 7MB for JFFS2 based RFS */
+                               reg = <0x00900000 0x00700000>;
+                               label = "SPI JFFS2 RFS";
+                       };
+               };
+       };
+
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       mdio@24520 {
+               phy0: ethernet-phy@0 {
+                       interrupts = <3 1 0 0>;
+                       reg = <0x0>;
+                       };
+               phy1: ethernet-phy@1 {
+                       interrupts = <2 1 0 0>;
+                       reg = <0x1>;
+                       };
+       };
+
+       mdio@25520 {
+               tbi0: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@26520 {
+               status = "disabled";
+       };
+
+       ptp_clock@24e00 {
+               fsl,tclk-period = <5>;
+               fsl,tmr-prsc = <200>;
+               fsl,tmr-add = <0xCCCCCCCD>;
+               fsl,tmr-fiper1 = <0x3B9AC9FB>;
+               fsl,tmr-fiper2 = <0x0001869B>;
+               fsl,max-adj = <249999999>;
+       };
+
+       enet0: ethernet@24000 {
+               fixed-link = <1 1 1000 0 0>;
+               phy-connection-type = "rgmii-id";
+       };
+
+       enet1: ethernet@25000 {
+               tbi-handle = <&tbi0>;
+               phy-handle = <&phy0>;
+               phy-connection-type = "sgmii";
+       };
+
+       enet2: ethernet@26000 {
+               phy-handle = <&phy1>;
+               phy-connection-type = "rgmii-id";
+       };
+};
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts
new file mode 100644 (file)
index 0000000..852e5b2
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * P2020 RDB-PC 32Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+       model = "fsl,P2020RDB";
+       compatible = "fsl,P2020RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@ffe05000 {
+               reg = <0 0xffe05000 0 0x1000>;
+
+               /* NOR and NAND Flashes */
+               ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+                         0x1 0x0 0x0 0xff800000 0x00040000
+                         0x2 0x0 0x0 0xffb00000 0x00020000
+                         0x3 0x0 0x0 0xffa00000 0x00020000>;
+       };
+
+       soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe08000 {
+               reg = <0 0xffe08000 0 0x1000>;
+               status = "disabled";
+       };
+
+       pci1: pcie@ffe09000 {
+               reg = <0 0xffe09000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci2: pcie@ffe0a000 {
+               reg = <0 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "p2020rdb-pc.dtsi"
+/include/ "fsl/p2020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts
new file mode 100644 (file)
index 0000000..b5a56ca
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * P2020 RDB-PC 36Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
+ */
+
+/include/ "fsl/p2020si-pre.dtsi"
+
+/ {
+       model = "fsl,P2020RDB";
+       compatible = "fsl,P2020RDB-PC";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@fffe05000 {
+               reg = <0xf 0xffe05000 0 0x1000>;
+
+               /* NOR and NAND Flashes */
+               ranges = <0x0 0x0 0xf 0xef000000 0x01000000
+                         0x1 0x0 0xf 0xff800000 0x00040000
+                         0x2 0x0 0xf 0xffb00000 0x00020000
+                         0x3 0x0 0xf 0xffa00000 0x00020000>;
+       };
+
+       soc: soc@fffe00000 {
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@fffe08000 {
+               reg = <0xf 0xffe08000 0 0x1000>;
+               status = "disabled";
+       };
+
+       pci1: pcie@fffe09000 {
+               reg = <0xf 0xffe09000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci2: pcie@fffe0a000 {
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "p2020rdb-pc.dtsi"
+/include/ "fsl/p2020si-post.dtsi"
index eb8a6aa..153bc76 100644 (file)
@@ -34,7 +34,7 @@
 
                /* NOR and NAND Flashes */
                ranges = <0x0 0x0 0x0 0xef000000 0x01000000
-                         0x1 0x0 0x0 0xffa00000 0x00040000
+                         0x1 0x0 0x0 0xff800000 0x00040000
                          0x2 0x0 0x0 0xffb00000 0x00020000>;
 
                nor@0,0 {
                                #size-cells = <1>;
                                compatible = "spansion,s25sl12801";
                                reg = <0>;
-                               spi-max-frequency = <50000000>;
+                               spi-max-frequency = <40000000>;
 
                                partition@0 {
                                        /* 512KB for u-boot Bootloader Image */
index f090e6d..6761c74 100755 (executable)
@@ -144,6 +144,7 @@ tmp=$tmpdir/zImage.$$.o
 ksection=.kernel:vmlinux.strip
 isection=.kernel:initrd
 link_address='0x400000'
+make_space=y
 
 case "$platform" in
 pseries)
@@ -210,6 +211,7 @@ ps3)
     ksection=.kernel:vmlinux.bin
     isection=.kernel:initrd
     link_address=''
+    make_space=n
     pie=
     ;;
 ep88xc|ep405|ep8248e)
@@ -278,17 +280,19 @@ else
     rm -f $vmz.$$
 fi
 
-# Round the size to next higher MB limit
-round_size=$(((strip_size + 0xfffff) & 0xfff00000))
+if [ "$make_space" = "y" ]; then
+       # Round the size to next higher MB limit
+       round_size=$(((strip_size + 0xfffff) & 0xfff00000))
 
-round_size=0x$(printf "%x" $round_size)
-link_addr=$(printf "%d" $link_address)
+       round_size=0x$(printf "%x" $round_size)
+       link_addr=$(printf "%d" $link_address)
 
-if [ $link_addr -lt $strip_size ]; then
-    echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \
-               "overlaps the address of the wrapper($link_address)"
-    echo "INFO: Fixing the link_address of wrapper to ($round_size)"
-    link_address=$round_size
+       if [ $link_addr -lt $strip_size ]; then
+           echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \
+                       "overlaps the address of the wrapper($link_address)"
+           echo "INFO: Fixing the link_address of wrapper to ($round_size)"
+           link_address=$round_size
+       fi
 fi
 
 vmz="$vmz$gzip"
diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig
new file mode 100644 (file)
index 0000000..f8c51a4
--- /dev/null
@@ -0,0 +1,257 @@
+CONFIG_PPC_85xx=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_GE_IMP3A=y
+CONFIG_QUICC_ENGINE=y
+CONFIG_QE_GPIO=y
+CONFIG_CPM2=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_HZ_1000=y
+CONFIG_PREEMPT=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_MATH_EMULATION=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_FORCE_MAX_ZONEORDER=17
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_MSI=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_LOAD_CIS is not set
+CONFIG_YENTA=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NET_PKTGEN=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSL_ELBC=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_MISC_DEVICES=y
+CONFIG_DS1682=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_SIL24=y
+# CONFIG_ATA_SFF is not set
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_FS_ENET=y
+CONFIG_UCC_GETH=y
+CONFIG_GIANFAR=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+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_MANY_PORTS=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_QE=m
+CONFIG_NVRAM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_CPM=m
+CONFIG_I2C_MPC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_LM92=y
+CONFIG_WATCHDOG=y
+CONFIG_GEF_WDT=y
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_FSL=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_STORAGE=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_MPC85XX=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_DRV_RX8581=y
+CONFIG_DMADEVICES=y
+CONFIG_FSL_DMA=y
+# CONFIG_NET_DMA is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_NTFS_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_LIBCRC32C=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TALITOS=y
index d41857a..da731c2 100644 (file)
@@ -131,6 +131,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
index 38303ec..2149360 100644 (file)
@@ -132,6 +132,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
index 9853397..af2e8e1 100644 (file)
@@ -183,6 +183,8 @@ CONFIG_NVRAM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MPC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GE_FPGA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM92=y
 CONFIG_WATCHDOG=y
diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
deleted file mode 100644 (file)
index 27c46d6..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-CONFIG_PPC64=y
-CONFIG_SMP=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_PPC_PSERIES is not set
-CONFIG_LPARCFG=y
-CONFIG_PPC_ISERIES=y
-CONFIG_VIODASD=y
-CONFIG_VIOCD=m
-CONFIG_VIOTAPE=m
-# CONFIG_PPC_PMAC is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IRQ_ALL_CPUS=y
-# CONFIG_MIGRATION is not set
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_XFRM_SUB_POLICY=y
-CONFIG_NET_KEY=m
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_NET_IPIP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_MODE_BEET=m
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
-CONFIG_NETFILTER_NETLINK_LOG=m
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_EVENTS=y
-# CONFIG_NF_CT_PROTO_SCTP is not set
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TPROXY=m
-CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_OWNER=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_RATEEST=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=y
-CONFIG_SCSI_SAS_LIBSAS=m
-CONFIG_SCSI_IBMVSCSI=m
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-CONFIG_MD_RAID10=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-CONFIG_E100=y
-CONFIG_ACENIC=m
-CONFIG_E1000=m
-CONFIG_ISERIES_VETH=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL_TRAP=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_SERIAL_ICOM=m
-# CONFIG_HW_RANDOM is not set
-CONFIG_GEN_RTC=y
-CONFIG_RAW_DRIVER=y
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT2_FS_XIP=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_EXT4_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_JFS_FS=m
-CONFIG_JFS_POSIX_ACL=y
-CONFIG_JFS_SECURITY=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_GFS2_FS=m
-CONFIG_AUTOFS_FS=m
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_CIFS=m
-CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DLM=m
-CONFIG_CRC_T10DIF=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-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
-CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
index 2a1320f..6640a35 100644 (file)
@@ -1,8 +1,8 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
@@ -13,15 +13,12 @@ CONFIG_PPC_EFIKA=y
 CONFIG_PPC_LITE5200=y
 CONFIG_PPC_MEDIA5200=y
 CONFIG_PPC_MPC5200_BUGFIX=y
-CONFIG_PPC_MPC5200_GPIO=y
 CONFIG_PPC_MPC5200_LPBFIFO=m
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_BESTCOMM=y
 CONFIG_SIMPLE_GPIO=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -36,23 +33,20 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_CONCAT=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_RAM=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_PLATRAM=y
 CONFIG_MTD_UBI=m
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_MISC_DEVICES=y
 CONFIG_EEPROM_AT24=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -61,11 +55,10 @@ CONFIG_ATA=y
 CONFIG_PATA_MPC52xx=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_NETDEVICES=y
-CONFIG_LXT_PHY=y
-CONFIG_NET_ETHERNET=y
 CONFIG_FEC_MPC52xx=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_AMD_PHY=y
+CONFIG_LXT_PHY=y
+CONFIG_FIXED_PHY=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
@@ -80,11 +73,17 @@ CONFIG_SPI_GPIO=m
 CONFIG_SPI_MPC52xx=m
 CONFIG_SPI_MPC52xx_PSC=m
 CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_SENSORS_LM80=y
+CONFIG_SENSORS_LM87=m
 CONFIG_WATCHDOG=y
+CONFIG_MFD_SM501=m
 CONFIG_DRM=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
 CONFIG_FB_RADEON=y
+CONFIG_FB_SM501=m
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
@@ -124,10 +123,11 @@ CONFIG_USB_STORAGE=y
 CONFIG_NEW_LEDS=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_DS1374=y
+CONFIG_RTC_DRV_PCF8563=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_PROC_KCORE=y
@@ -145,5 +145,4 @@ CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index f37a2ab..5fb0c8a 100644 (file)
@@ -1,4 +1,5 @@
 CONFIG_PPC_85xx=y
+CONFIG_PHYS_64BIT=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
index abdcd31..fb51bc9 100644 (file)
@@ -1,4 +1,5 @@
 CONFIG_PPC_85xx=y
+CONFIG_PHYS_64BIT=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=8
 CONFIG_EXPERIMENTAL=y
index 5ab0b71..9d92ba0 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
-#include <asm/firmware.h>
 
 struct mschunks_map {
         unsigned long num_chunks;
@@ -46,30 +45,12 @@ static inline unsigned long addr_to_chunk(unsigned long addr)
 
 static inline unsigned long phys_to_abs(unsigned long pa)
 {
-       unsigned long chunk;
-
-       /* This is a no-op on non-iSeries */
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return pa;
-
-       chunk = addr_to_chunk(pa);
-
-       if (chunk < mschunks_map.num_chunks)
-               chunk = mschunks_map.mapping[chunk];
-
-       return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK);
+       return pa;
 }
 
 /* Convenience macros */
 #define virt_to_abs(va) phys_to_abs(__pa(va))
 #define abs_to_virt(aa) __va(aa)
 
-/*
- * Converts Virtual Address to Real Address for
- * Legacy iSeries Hypervisor calls
- */
-#define iseries_hv_addr(virtaddr)      \
-       (0x8000000000000000UL | virt_to_abs(virtaddr))
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_ABS_ADDR_H */
index 02e41b5..14174e8 100644 (file)
@@ -212,6 +212,36 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
        return t;
 }
 
+/**
+ * atomic_inc_not_zero - increment unless the number is zero
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+static __inline__ int atomic_inc_not_zero(atomic_t *v)
+{
+       int t1, t2;
+
+       __asm__ __volatile__ (
+       PPC_ATOMIC_ENTRY_BARRIER
+"1:    lwarx   %0,0,%2         # atomic_inc_not_zero\n\
+       cmpwi   0,%0,0\n\
+       beq-    2f\n\
+       addic   %1,%0,1\n"
+       PPC405_ERR77(0,%2)
+"      stwcx.  %1,0,%2\n\
+       bne-    1b\n"
+       PPC_ATOMIC_EXIT_BARRIER
+       "\n\
+2:"
+       : "=&r" (t1), "=&r" (t2)
+       : "r" (&v->counter)
+       : "cc", "xer", "memory");
+
+       return t1;
+}
+#define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
 
 #define atomic_sub_and_test(a, v)      (atomic_sub_return((a), (v)) == 0)
 #define atomic_dec_and_test(v)         (atomic_dec_return((v)) == 0)
@@ -467,7 +497,34 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
        return t != u;
 }
 
-#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+/**
+ * atomic_inc64_not_zero - increment unless the number is zero
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically increments @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
+{
+       long t1, t2;
+
+       __asm__ __volatile__ (
+       PPC_ATOMIC_ENTRY_BARRIER
+"1:    ldarx   %0,0,%2         # atomic64_inc_not_zero\n\
+       cmpdi   0,%0,0\n\
+       beq-    2f\n\
+       addic   %1,%0,1\n\
+       stdcx.  %1,0,%2\n\
+       bne-    1b\n"
+       PPC_ATOMIC_EXIT_BARRIER
+       "\n\
+2:"
+       : "=&r" (t1), "=&r" (t2)
+       : "r" (&v->counter)
+       : "cc", "xer", "memory");
+
+       return t1;
+}
 
 #endif /* __powerpc64__ */
 
index ad55a1c..b9219e9 100644 (file)
@@ -390,6 +390,10 @@ extern const char *powerpc_base_platform;
            CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
            CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
            CPU_FTR_DEBUG_LVL_EXC)
+#define CPU_FTRS_E6500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
+           CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
+           CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+           CPU_FTR_DEBUG_LVL_EXC)
 #define CPU_FTRS_GENERIC_32    (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
 
 /* 64-bit CPUs */
@@ -442,7 +446,7 @@ extern const char *powerpc_base_platform;
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_POSSIBLE      (CPU_FTRS_E5500 | CPU_FTRS_A2)
+#define CPU_FTRS_POSSIBLE      (CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2)
 #else
 #define CPU_FTRS_POSSIBLE      \
            (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |        \
@@ -483,7 +487,7 @@ enum {
 #endif
 #ifdef CONFIG_E500
            CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC |
-           CPU_FTRS_E5500 |
+           CPU_FTRS_E5500 | CPU_FTRS_E6500 |
 #endif
            0,
 };
@@ -491,7 +495,7 @@ enum {
 
 #ifdef __powerpc64__
 #ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_ALWAYS                (CPU_FTRS_E5500 & CPU_FTRS_A2)
+#define CPU_FTRS_ALWAYS                (CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2)
 #else
 #define CPU_FTRS_ALWAYS                \
            (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &        \
@@ -528,7 +532,7 @@ enum {
 #endif
 #ifdef CONFIG_E500
            CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC &
-           CPU_FTRS_E5500 &
+           CPU_FTRS_E5500 & CPU_FTRS_E6500 &
 #endif
            CPU_FTRS_POSSIBLE,
 };
index d57c08a..63d5ca4 100644 (file)
@@ -31,6 +31,9 @@ struct dev_archdata {
 #ifdef CONFIG_SWIOTLB
        dma_addr_t              max_direct_dma_addr;
 #endif
+#ifdef CONFIG_EEH
+       struct eeh_dev          *edev;
+#endif
 };
 
 struct pdev_archdata {
index a7e06e2..adadb99 100644 (file)
@@ -34,8 +34,6 @@
 /* Doesn't really apply... */
 #define MAX_DMA_ADDRESS                (~0UL)
 
-#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)
-
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
 #define dma_outb       outb_p
 #else
@@ -354,7 +352,5 @@ extern int isa_dma_bridge_buggy;
 #define isa_dma_bridge_buggy   (0)
 #endif
 
-#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DMA_H */
index 66ea9b8..d60f998 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * eeh.h
  * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
+ * Copyright 2001-2012 IBM 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
@@ -31,44 +31,105 @@ struct device_node;
 
 #ifdef CONFIG_EEH
 
-extern int eeh_subsystem_enabled;
+/*
+ * The struct is used to trace EEH state for the associated
+ * PCI device node or PCI device. In future, it might
+ * represent PE as well so that the EEH device to form
+ * another tree except the currently existing tree of PCI
+ * buses and PCI devices
+ */
+#define EEH_MODE_SUPPORTED     (1<<0)  /* EEH supported on the device  */
+#define EEH_MODE_NOCHECK       (1<<1)  /* EEH check should be skipped  */
+#define EEH_MODE_ISOLATED      (1<<2)  /* The device has been isolated */
+#define EEH_MODE_RECOVERING    (1<<3)  /* Recovering the device        */
+#define EEH_MODE_IRQ_DISABLED  (1<<4)  /* Interrupt disabled           */
+
+struct eeh_dev {
+       int mode;                       /* EEH mode                     */
+       int class_code;                 /* Class code of the device     */
+       int config_addr;                /* Config address               */
+       int pe_config_addr;             /* PE config address            */
+       int check_count;                /* Times of ignored error       */
+       int freeze_count;               /* Times of froze up            */
+       int false_positives;            /* Times of reported #ff's      */
+       u32 config_space[16];           /* Saved PCI config space       */
+       struct pci_controller *phb;     /* Associated PHB               */
+       struct device_node *dn;         /* Associated device node       */
+       struct pci_dev *pdev;           /* Associated PCI device        */
+};
+
+static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
+{
+       return edev->dn;
+}
+
+static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
+{
+       return edev->pdev;
+}
 
-/* Values for eeh_mode bits in device_node */
-#define EEH_MODE_SUPPORTED     (1<<0)
-#define EEH_MODE_NOCHECK       (1<<1)
-#define EEH_MODE_ISOLATED      (1<<2)
-#define EEH_MODE_RECOVERING    (1<<3)
-#define EEH_MODE_IRQ_DISABLED  (1<<4)
+/*
+ * The struct is used to trace the registered EEH operation
+ * callback functions. Actually, those operation callback
+ * functions are heavily platform dependent. That means the
+ * platform should register its own EEH operation callback
+ * functions before any EEH further operations.
+ */
+#define EEH_OPT_DISABLE                0       /* EEH disable  */
+#define EEH_OPT_ENABLE         1       /* EEH enable   */
+#define EEH_OPT_THAW_MMIO      2       /* MMIO enable  */
+#define EEH_OPT_THAW_DMA       3       /* DMA enable   */
+#define EEH_STATE_UNAVAILABLE  (1 << 0)        /* State unavailable    */
+#define EEH_STATE_NOT_SUPPORT  (1 << 1)        /* EEH not supported    */
+#define EEH_STATE_RESET_ACTIVE (1 << 2)        /* Active reset         */
+#define EEH_STATE_MMIO_ACTIVE  (1 << 3)        /* Active MMIO          */
+#define EEH_STATE_DMA_ACTIVE   (1 << 4)        /* Active DMA           */
+#define EEH_STATE_MMIO_ENABLED (1 << 5)        /* MMIO enabled         */
+#define EEH_STATE_DMA_ENABLED  (1 << 6)        /* DMA enabled          */
+#define EEH_RESET_DEACTIVATE   0       /* Deactivate the PE reset      */
+#define EEH_RESET_HOT          1       /* Hot reset                    */
+#define EEH_RESET_FUNDAMENTAL  3       /* Fundamental reset            */
+#define EEH_LOG_TEMP           1       /* EEH temporary error log      */
+#define EEH_LOG_PERM           2       /* EEH permanent error log      */
+
+struct eeh_ops {
+       char *name;
+       int (*init)(void);
+       int (*set_option)(struct device_node *dn, int option);
+       int (*get_pe_addr)(struct device_node *dn);
+       int (*get_state)(struct device_node *dn, int *state);
+       int (*reset)(struct device_node *dn, int option);
+       int (*wait_state)(struct device_node *dn, int max_wait);
+       int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len);
+       int (*configure_bridge)(struct device_node *dn);
+       int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
+       int (*write_config)(struct device_node *dn, int where, int size, u32 val);
+};
+
+extern struct eeh_ops *eeh_ops;
+extern int eeh_subsystem_enabled;
 
-/* Max number of EEH freezes allowed before we consider the device
- * to be permanently disabled. */
+/*
+ * Max number of EEH freezes allowed before we consider the device
+ * to be permanently disabled.
+ */
 #define EEH_MAX_ALLOWED_FREEZES 5
 
+void * __devinit eeh_dev_init(struct device_node *dn, void *data);
+void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
+void __init eeh_dev_phb_init(void);
 void __init eeh_init(void);
+#ifdef CONFIG_PPC_PSERIES
+int __init eeh_pseries_init(void);
+#endif
+int __init eeh_ops_register(struct eeh_ops *ops);
+int __exit eeh_ops_unregister(const char *name);
 unsigned long eeh_check_failure(const volatile void __iomem *token,
                                unsigned long val);
 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev);
 void __init pci_addr_cache_build(void);
-
-/**
- * eeh_add_device_early
- * eeh_add_device_late
- *
- * Perform eeh initialization for devices added after boot.
- * Call eeh_add_device_early before doing any i/o to the
- * device (including config space i/o).  Call eeh_add_device_late
- * to finish the eeh setup for this device.
- */
 void eeh_add_device_tree_early(struct device_node *);
 void eeh_add_device_tree_late(struct pci_bus *);
-
-/**
- * eeh_remove_device_recursive - undo EEH for device & children.
- * @dev: pci device to be removed
- *
- * As above, this removes the device; it also removes child
- * pci devices as well.
- */
 void eeh_remove_bus_device(struct pci_dev *);
 
 /**
@@ -87,8 +148,25 @@ void eeh_remove_bus_device(struct pci_dev *);
 #define EEH_IO_ERROR_VALUE(size)       (~0U >> ((4 - (size)) * 8))
 
 #else /* !CONFIG_EEH */
+
+static inline void *eeh_dev_init(struct device_node *dn, void *data)
+{
+       return NULL;
+}
+
+static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { }
+
+static inline void eeh_dev_phb_init(void) { }
+
 static inline void eeh_init(void) { }
 
+#ifdef CONFIG_PPC_PSERIES
+static inline int eeh_pseries_init(void)
+{
+       return 0;
+}
+#endif /* CONFIG_PPC_PSERIES */
+
 static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
 {
        return val;
index cc3cb04..c68b012 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *     eeh_event.h
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 #define ASM_POWERPC_EEH_EVENT_H
 #ifdef __KERNEL__
 
-/** EEH event -- structure holding pci controller data that describes
- *  a change in the isolation status of a PCI slot.  A pointer
- *  to this struct is passed as the data pointer in a notify callback.
+/*
+ * structure holding pci controller data that describes a
+ * change in the isolation status of a PCI slot.  A pointer
+ * to this struct is passed as the data pointer in a notify
+ * callback.
  */
 struct eeh_event {
-       struct list_head     list;
-       struct device_node      *dn;   /* struct device node */
-       struct pci_dev       *dev;  /* affected device */
+       struct list_head        list;   /* to form event queue  */
+       struct eeh_dev          *edev;  /* EEH device           */
 };
 
-/**
- * eeh_send_failure_event - generate a PCI error event
- * @dev pci device
- *
- * This routine builds a PCI error event which will be delivered
- * to all listeners on the eeh_notifier_chain.
- *
- * This routine can be called within an interrupt context;
- * the actual event will be delivered in a normal context
- * (from a workqueue).
- */
-int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev);
-
-/* Main recovery function */
-struct pci_dn * handle_eeh_events (struct eeh_event *);
+int eeh_send_failure_event(struct eeh_dev *edev);
+struct eeh_dev *handle_eeh_events(struct eeh_event *);
 
 #endif /* __KERNEL__ */
 #endif /* ASM_POWERPC_EEH_EVENT_H */
index 8057f4f..548da3a 100644 (file)
@@ -232,23 +232,30 @@ label##_hv:                                               \
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,    \
                                 EXC_HV, KVMTEST, vec)
 
-#define __SOFTEN_TEST(h)                                               \
+/* This associate vector numbers with bits in paca->irq_happened */
+#define SOFTEN_VALUE_0x500     PACA_IRQ_EE
+#define SOFTEN_VALUE_0x502     PACA_IRQ_EE
+#define SOFTEN_VALUE_0x900     PACA_IRQ_DEC
+#define SOFTEN_VALUE_0x982     PACA_IRQ_DEC
+
+#define __SOFTEN_TEST(h, vec)                                          \
        lbz     r10,PACASOFTIRQEN(r13);                                 \
        cmpwi   r10,0;                                                  \
+       li      r10,SOFTEN_VALUE_##vec;                                 \
        beq     masked_##h##interrupt
-#define _SOFTEN_TEST(h)        __SOFTEN_TEST(h)
+#define _SOFTEN_TEST(h, vec)   __SOFTEN_TEST(h, vec)
 
 #define SOFTEN_TEST_PR(vec)                                            \
        KVMTEST_PR(vec);                                                \
-       _SOFTEN_TEST(EXC_STD)
+       _SOFTEN_TEST(EXC_STD, vec)
 
 #define SOFTEN_TEST_HV(vec)                                            \
        KVMTEST(vec);                                                   \
-       _SOFTEN_TEST(EXC_HV)
+       _SOFTEN_TEST(EXC_HV, vec)
 
 #define SOFTEN_TEST_HV_201(vec)                                                \
        KVMTEST(vec);                                                   \
-       _SOFTEN_TEST(EXC_STD)
+       _SOFTEN_TEST(EXC_STD, vec)
 
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)             \
        HMT_MEDIUM;                                                     \
@@ -272,73 +279,55 @@ label##_hv:                                                               \
        _MASKABLE_EXCEPTION_PSERIES(vec, label,                         \
                                    EXC_HV, SOFTEN_TEST_HV)
 
-#ifdef CONFIG_PPC_ISERIES
-#define DISABLE_INTS                           \
-       li      r11,0;                          \
-       stb     r11,PACASOFTIRQEN(r13);         \
-BEGIN_FW_FTR_SECTION;                          \
-       stb     r11,PACAHARDIRQEN(r13);         \
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);  \
-       TRACE_DISABLE_INTS;                     \
-BEGIN_FW_FTR_SECTION;                          \
-       mfmsr   r10;                            \
-       ori     r10,r10,MSR_EE;                 \
-       mtmsrd  r10,1;                          \
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#else
-#define DISABLE_INTS                           \
-       li      r11,0;                          \
-       stb     r11,PACASOFTIRQEN(r13);         \
-       stb     r11,PACAHARDIRQEN(r13);         \
-       TRACE_DISABLE_INTS
-#endif /* CONFIG_PPC_ISERIES */
+/*
+ * Our exception common code can be passed various "additions"
+ * to specify the behaviour of interrupts, whether to kick the
+ * runlatch, etc...
+ */
+
+/* Exception addition: Hard disable interrupts */
+#define DISABLE_INTS   SOFT_DISABLE_INTS(r10,r11)
 
+/* Exception addition: Keep interrupt state */
 #define ENABLE_INTS                            \
+       ld      r11,PACAKMSR(r13);              \
        ld      r12,_MSR(r1);                   \
-       mfmsr   r11;                            \
        rlwimi  r11,r12,0,MSR_EE;               \
        mtmsrd  r11,1
 
-#define STD_EXCEPTION_COMMON(trap, label, hdlr)                \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       DISABLE_INTS;                                   \
-       bl      .save_nvgprs;                           \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except
+#define ADD_NVGPRS                             \
+       bl      .save_nvgprs
+
+#define RUNLATCH_ON                            \
+BEGIN_FTR_SECTION                              \
+       clrrdi  r3,r1,THREAD_SHIFT;             \
+       ld      r4,TI_LOCAL_FLAGS(r3);          \
+       andi.   r0,r4,_TLF_RUNLATCH;            \
+       beql    ppc64_runlatch_on_trampoline;   \
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
+
+#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions)    \
+       .align  7;                                              \
+       .globl label##_common;                                  \
+label##_common:                                                        \
+       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);              \
+       additions;                                              \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       bl      hdlr;                                           \
+       b       ret
+
+#define STD_EXCEPTION_COMMON(trap, label, hdlr)                        \
+       EXCEPTION_COMMON(trap, label, hdlr, ret_from_except,    \
+                        ADD_NVGPRS;DISABLE_INTS)
 
 /*
  * Like STD_EXCEPTION_COMMON, but for exceptions that can occur
- * in the idle task and therefore need the special idle handling.
+ * in the idle task and therefore need the special idle handling
+ * (finish nap and runlatch)
  */
-#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr)   \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       FINISH_NAP;                                     \
-       DISABLE_INTS;                                   \
-       bl      .save_nvgprs;                           \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except
-
-#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr)   \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       FINISH_NAP;                                     \
-       DISABLE_INTS;                                   \
-BEGIN_FTR_SECTION                                      \
-       bl      .ppc64_runlatch_on;                     \
-END_FTR_SECTION_IFSET(CPU_FTR_CTRL)                    \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except_lite
+#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr)            \
+       EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \
+                        FINISH_NAP;RUNLATCH_ON;DISABLE_INTS)
 
 /*
  * When the idle code in power4_idle puts the CPU into NAP mode,
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
new file mode 100644 (file)
index 0000000..88dbf96
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Firmware Assisted dump header file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __PPC64_FA_DUMP_H__
+#define __PPC64_FA_DUMP_H__
+
+#ifdef CONFIG_FA_DUMP
+
+/*
+ * The RMA region will be saved for later dumping when kernel crashes.
+ * RMA is Real Mode Area, the first block of logical memory address owned
+ * by logical partition, containing the storage that may be accessed with
+ * translate off.
+ */
+#define RMA_START      0x0
+#define RMA_END                (ppc64_rma_size)
+
+/*
+ * On some Power systems where RMO is 128MB, it still requires minimum of
+ * 256MB for kernel to boot successfully. When kdump infrastructure is
+ * configured to save vmcore over network, we run into OOM issue while
+ * loading modules related to network setup. Hence we need aditional 64M
+ * of memory to avoid OOM issue.
+ */
+#define MIN_BOOT_MEM   (((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \
+                       + (0x1UL << 26))
+
+#define memblock_num_regions(memblock_type)    (memblock.memblock_type.cnt)
+
+#ifndef ELF_CORE_EFLAGS
+#define ELF_CORE_EFLAGS 0
+#endif
+
+/* Firmware provided dump sections */
+#define FADUMP_CPU_STATE_DATA  0x0001
+#define FADUMP_HPTE_REGION     0x0002
+#define FADUMP_REAL_MODE_REGION        0x0011
+
+/* Dump request flag */
+#define FADUMP_REQUEST_FLAG    0x00000001
+
+/* FAD commands */
+#define FADUMP_REGISTER                1
+#define FADUMP_UNREGISTER      2
+#define FADUMP_INVALIDATE      3
+
+/* Dump status flag */
+#define FADUMP_ERROR_FLAG      0x2000
+
+#define FADUMP_CPU_ID_MASK     ((1UL << 32) - 1)
+
+#define CPU_UNKNOWN            (~((u32)0))
+
+/* Utility macros */
+#define SKIP_TO_NEXT_CPU(reg_entry)                    \
+({                                                     \
+       while (reg_entry->reg_id != REG_ID("CPUEND"))   \
+               reg_entry++;                            \
+       reg_entry++;                                    \
+})
+
+/* Kernel Dump section info */
+struct fadump_section {
+       u32     request_flag;
+       u16     source_data_type;
+       u16     error_flags;
+       u64     source_address;
+       u64     source_len;
+       u64     bytes_dumped;
+       u64     destination_address;
+};
+
+/* ibm,configure-kernel-dump header. */
+struct fadump_section_header {
+       u32     dump_format_version;
+       u16     dump_num_sections;
+       u16     dump_status_flag;
+       u32     offset_first_dump_section;
+
+       /* Fields for disk dump option. */
+       u32     dd_block_size;
+       u64     dd_block_offset;
+       u64     dd_num_blocks;
+       u32     dd_offset_disk_path;
+
+       /* Maximum time allowed to prevent an automatic dump-reboot. */
+       u32     max_time_auto;
+};
+
+/*
+ * Firmware Assisted dump memory structure. This structure is required for
+ * registering future kernel dump with power firmware through rtas call.
+ *
+ * No disk dump option. Hence disk dump path string section is not included.
+ */
+struct fadump_mem_struct {
+       struct fadump_section_header    header;
+
+       /* Kernel dump sections */
+       struct fadump_section           cpu_state_data;
+       struct fadump_section           hpte_region;
+       struct fadump_section           rmr_region;
+};
+
+/* Firmware-assisted dump configuration details. */
+struct fw_dump {
+       unsigned long   cpu_state_data_size;
+       unsigned long   hpte_region_size;
+       unsigned long   boot_memory_size;
+       unsigned long   reserve_dump_area_start;
+       unsigned long   reserve_dump_area_size;
+       /* cmd line option during boot */
+       unsigned long   reserve_bootvar;
+
+       unsigned long   fadumphdr_addr;
+       unsigned long   cpu_notes_buf;
+       unsigned long   cpu_notes_buf_size;
+
+       int             ibm_configure_kernel_dump;
+
+       unsigned long   fadump_enabled:1;
+       unsigned long   fadump_supported:1;
+       unsigned long   dump_active:1;
+       unsigned long   dump_registered:1;
+};
+
+/*
+ * Copy the ascii values for first 8 characters from a string into u64
+ * variable at their respective indexes.
+ * e.g.
+ *  The string "FADMPINF" will be converted into 0x4641444d50494e46
+ */
+static inline u64 str_to_u64(const char *str)
+{
+       u64 val = 0;
+       int i;
+
+       for (i = 0; i < sizeof(val); i++)
+               val = (*str) ? (val << 8) | *str++ : val << 8;
+       return val;
+}
+#define STR_TO_HEX(x)  str_to_u64(x)
+#define REG_ID(x)      str_to_u64(x)
+
+#define FADUMP_CRASH_INFO_MAGIC                STR_TO_HEX("FADMPINF")
+#define REGSAVE_AREA_MAGIC             STR_TO_HEX("REGSAVE")
+
+/* The firmware-assisted dump format.
+ *
+ * The register save area is an area in the partition's memory used to preserve
+ * the register contents (CPU state data) for the active CPUs during a firmware
+ * assisted dump. The dump format contains register save area header followed
+ * by register entries. Each list of registers for a CPU starts with
+ * "CPUSTRT" and ends with "CPUEND".
+ */
+
+/* Register save area header. */
+struct fadump_reg_save_area_header {
+       u64             magic_number;
+       u32             version;
+       u32             num_cpu_offset;
+};
+
+/* Register entry. */
+struct fadump_reg_entry {
+       u64             reg_id;
+       u64             reg_value;
+};
+
+/* fadump crash info structure */
+struct fadump_crash_info_header {
+       u64             magic_number;
+       u64             elfcorehdr_addr;
+       u32             crashing_cpu;
+       struct pt_regs  regs;
+       struct cpumask  cpu_online_mask;
+};
+
+/* Crash memory ranges */
+#define INIT_CRASHMEM_RANGES   (INIT_MEMBLOCK_REGIONS + 2)
+
+struct fad_crash_memory_ranges {
+       unsigned long long      base;
+       unsigned long long      size;
+};
+
+extern int early_init_dt_scan_fw_dump(unsigned long node,
+               const char *uname, int depth, void *data);
+extern int fadump_reserve_mem(void);
+extern int setup_fadump(void);
+extern int is_fadump_active(void);
+extern void crash_fadump(struct pt_regs *, const char *);
+extern void fadump_cleanup(void);
+
+extern void vmcore_cleanup(void);
+#else  /* CONFIG_FA_DUMP */
+static inline int is_fadump_active(void) { return 0; }
+static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
+#endif
+#endif
index 14db29b..ad0b751 100644 (file)
@@ -41,7 +41,6 @@
 #define FW_FEATURE_XDABR       ASM_CONST(0x0000000000040000)
 #define FW_FEATURE_MULTITCE    ASM_CONST(0x0000000000080000)
 #define FW_FEATURE_SPLPAR      ASM_CONST(0x0000000000100000)
-#define FW_FEATURE_ISERIES     ASM_CONST(0x0000000000200000)
 #define FW_FEATURE_LPAR                ASM_CONST(0x0000000000400000)
 #define FW_FEATURE_PS3_LV1     ASM_CONST(0x0000000000800000)
 #define FW_FEATURE_BEAT                ASM_CONST(0x0000000001000000)
@@ -65,8 +64,6 @@ enum {
                FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
                FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
        FW_FEATURE_PSERIES_ALWAYS = 0,
-       FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
-       FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
        FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
        FW_FEATURE_POWERNV_ALWAYS = 0,
        FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1,
@@ -79,9 +76,6 @@ enum {
 #ifdef CONFIG_PPC_PSERIES
                FW_FEATURE_PSERIES_POSSIBLE |
 #endif
-#ifdef CONFIG_PPC_ISERIES
-               FW_FEATURE_ISERIES_POSSIBLE |
-#endif
 #ifdef CONFIG_PPC_POWERNV
                FW_FEATURE_POWERNV_POSSIBLE |
 #endif
@@ -99,9 +93,6 @@ enum {
 #ifdef CONFIG_PPC_PSERIES
                FW_FEATURE_PSERIES_ALWAYS &
 #endif
-#ifdef CONFIG_PPC_ISERIES
-               FW_FEATURE_ISERIES_ALWAYS &
-#endif
 #ifdef CONFIG_PPC_POWERNV
                FW_FEATURE_POWERNV_ALWAYS &
 #endif
index bebd124..ce04530 100644 (file)
@@ -4,7 +4,7 @@
  * Authors: Jeff Brown
  *          Timur Tabi <timur@freescale.com>
  *
- * Copyright 2004,2007 Freescale Semiconductor, Inc
+ * Copyright 2004,2007,2012 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
@@ -114,6 +114,10 @@ struct ccsr_guts_86xx {
        __be32  srds2cr1;       /* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+
+/* Alternate function signal multiplex control */
+#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
+
 #ifdef CONFIG_PPC_86xx
 
 #define CCSR_GUTS_DMACR_DEV_SSI        0       /* DMA controller/channel set to SSI */
index bb712c9..51010bf 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 
+#ifdef CONFIG_PPC64
+
+/*
+ * PACA flags in paca->irq_happened.
+ *
+ * This bits are set when interrupts occur while soft-disabled
+ * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS
+ * is set whenever we manually hard disable.
+ */
+#define PACA_IRQ_HARD_DIS      0x01
+#define PACA_IRQ_DBELL         0x02
+#define PACA_IRQ_EE            0x04
+#define PACA_IRQ_DEC           0x08 /* Or FIT */
+#define PACA_IRQ_EE_EDGE       0x10 /* BookE only */
+
+#endif /* CONFIG_PPC64 */
+
+#ifndef __ASSEMBLY__
+
+extern void __replay_interrupt(unsigned int vector);
+
 extern void timer_interrupt(struct pt_regs *);
 
 #ifdef CONFIG_PPC64
@@ -42,7 +63,6 @@ static inline unsigned long arch_local_irq_disable(void)
 }
 
 extern void arch_local_irq_restore(unsigned long);
-extern void iseries_handle_interrupts(void);
 
 static inline void arch_local_irq_enable(void)
 {
@@ -68,16 +88,33 @@ static inline bool arch_irqs_disabled(void)
 #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)
+#define __hard_irq_enable()    __mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
+#define __hard_irq_disable()   __mtmsrd(local_paca->kernel_msr, 1)
 #endif
 
-#define  hard_irq_disable()                    \
-       do {                                    \
-               __hard_irq_disable();           \
-               get_paca()->soft_enabled = 0;   \
-               get_paca()->hard_enabled = 0;   \
-       } while(0)
+static inline void hard_irq_disable(void)
+{
+       __hard_irq_disable();
+       get_paca()->soft_enabled = 0;
+       get_paca()->irq_happened |= PACA_IRQ_HARD_DIS;
+}
+
+/*
+ * This is called by asynchronous interrupts to conditionally
+ * re-enable hard interrupts when soft-disabled after having
+ * cleared the source of the interrupt
+ */
+static inline void may_hard_irq_enable(void)
+{
+       get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
+       if (!(get_paca()->irq_happened & PACA_IRQ_EE))
+               __hard_irq_enable();
+}
+
+static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
+{
+       return !regs->softe;
+}
 
 #else /* CONFIG_PPC64 */
 
@@ -139,6 +176,13 @@ static inline bool arch_irqs_disabled(void)
 
 #define hard_irq_disable()             arch_local_irq_disable()
 
+static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
+{
+       return !(regs->msr & MSR_EE);
+}
+
+static inline void may_hard_irq_enable(void) { }
+
 #endif /* CONFIG_PPC64 */
 
 #define ARCH_IRQ_INIT_FLAGS    IRQ_NOREQUEST
@@ -149,5 +193,6 @@ static inline bool arch_irqs_disabled(void)
  */
 struct irq_chip;
 
+#endif  /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HW_IRQ_H */
index b0b06d8..6f9b6e2 100644 (file)
 #define TRACE_ENABLE_INTS      TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
 #define TRACE_DISABLE_INTS     TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
 
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)         \
-       cmpdi   en,0;                                   \
-       bne     95f;                                    \
-       stb     en,PACASOFTIRQEN(r13);                  \
-       TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)    \
-       b       skip;                                   \
-95:    TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)     \
-       li      en,1;
-#define TRACE_AND_RESTORE_IRQ(en)              \
-       TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f);  \
-       stb     en,PACASOFTIRQEN(r13);          \
-96:
+/*
+ * This is used by assembly code to soft-disable interrupts
+ */
+#define SOFT_DISABLE_INTS(__rA, __rB)          \
+       lbz     __rA,PACASOFTIRQEN(r13);        \
+       lbz     __rB,PACAIRQHAPPENED(r13);      \
+       cmpwi   cr0,__rA,0;                     \
+       li      __rA,0;                         \
+       ori     __rB,__rB,PACA_IRQ_HARD_DIS;    \
+       stb     __rB,PACAIRQHAPPENED(r13);      \
+       beq     44f;                            \
+       stb     __rA,PACASOFTIRQEN(r13);        \
+       TRACE_DISABLE_INTS;                     \
+44:
+
 #else
 #define TRACE_ENABLE_INTS
 #define TRACE_DISABLE_INTS
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)
-#define TRACE_AND_RESTORE_IRQ(en)              \
-       stb     en,PACASOFTIRQEN(r13)
+
+#define SOFT_DISABLE_INTS(__rA, __rB)          \
+       lbz     __rA,PACAIRQHAPPENED(r13);      \
+       li      __rB,0;                         \
+       ori     __rA,__rA,PACA_IRQ_HARD_DIS;    \
+       stb     __rB,PACASOFTIRQEN(r13);        \
+       stb     __rA,PACAIRQHAPPENED(r13)
 #endif
 #endif
 
diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h
deleted file mode 100644 (file)
index c0cce67..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright Â© 2008  Stephen Rothwell IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_ALPACA_H
-#define _ASM_POWERPC_ISERIES_ALPACA_H
-
-/*
- * This is the part of the paca that the iSeries hypervisor
- * needs to be statically initialised. Immediately after boot
- * we switch to the normal Linux paca.
- */
-struct alpaca {
-       struct lppaca *lppaca_ptr;      /* Pointer to LpPaca for PLIC */
-       const void *reg_save_ptr;       /* Pointer to LpRegSave for PLIC */
-};
-
-#endif /* _ASM_POWERPC_ISERIES_ALPACA_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call.h b/arch/powerpc/include/asm/iseries/hv_call.h
deleted file mode 100644 (file)
index 162d653..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/paca.h>
-
-/* Type of yield for HvCallBaseYieldProcessor */
-#define HvCall_YieldTimed      0       /* Yield until specified time (tb) */
-#define HvCall_YieldToActive   1       /* Yield until all active procs have run */
-#define HvCall_YieldToProc     2       /* Yield until the specified processor has run */
-
-/* interrupt masks for setEnabledInterrupts */
-#define HvCall_MaskIPI         0x00000001
-#define HvCall_MaskLpEvent     0x00000002
-#define HvCall_MaskLpProd      0x00000004
-#define HvCall_MaskTimeout     0x00000008
-
-/* Log buffer formats */
-#define HvCall_LogBuffer_ASCII          0
-#define HvCall_LogBuffer_EBCDIC         1
-
-#define HvCallBaseAckDeferredInts                      HvCallBase +  0
-#define HvCallBaseCpmPowerOff                          HvCallBase +  1
-#define HvCallBaseGetHwPatch                           HvCallBase +  2
-#define HvCallBaseReIplSpAttn                          HvCallBase +  3
-#define HvCallBaseSetASR                               HvCallBase +  4
-#define HvCallBaseSetASRAndRfi                         HvCallBase +  5
-#define HvCallBaseSetIMR                               HvCallBase +  6
-#define HvCallBaseSendIPI                              HvCallBase +  7
-#define HvCallBaseTerminateMachine                     HvCallBase +  8
-#define HvCallBaseTerminateMachineSrc                  HvCallBase +  9
-#define HvCallBaseProcessPlicInterrupts                        HvCallBase + 10
-#define HvCallBaseIsPrimaryCpmOrMsdIpl                 HvCallBase + 11
-#define HvCallBaseSetVirtualSIT                                HvCallBase + 12
-#define HvCallBaseVaryOffThisProcessor                 HvCallBase + 13
-#define HvCallBaseVaryOffMemoryChunk                   HvCallBase + 14
-#define HvCallBaseVaryOffInteractivePercentage         HvCallBase + 15
-#define HvCallBaseSendLpProd                           HvCallBase + 16
-#define HvCallBaseSetEnabledInterrupts                 HvCallBase + 17
-#define HvCallBaseYieldProcessor                       HvCallBase + 18
-#define HvCallBaseVaryOffSharedProcUnits               HvCallBase + 19
-#define HvCallBaseSetVirtualDecr                       HvCallBase + 20
-#define HvCallBaseClearLogBuffer                       HvCallBase + 21
-#define HvCallBaseGetLogBufferCodePage                 HvCallBase + 22
-#define HvCallBaseGetLogBufferFormat                   HvCallBase + 23
-#define HvCallBaseGetLogBufferLength                   HvCallBase + 24
-#define HvCallBaseReadLogBuffer                                HvCallBase + 25
-#define HvCallBaseSetLogBufferFormatAndCodePage                HvCallBase + 26
-#define HvCallBaseWriteLogBuffer                       HvCallBase + 27
-#define HvCallBaseRouter28                             HvCallBase + 28
-#define HvCallBaseRouter29                             HvCallBase + 29
-#define HvCallBaseRouter30                             HvCallBase + 30
-#define HvCallBaseSetDebugBus                          HvCallBase + 31
-
-#define HvCallCcSetDABR                                        HvCallCc + 7
-
-static inline void HvCall_setVirtualDecr(void)
-{
-       /*
-        * Ignore any error return codes - most likely means that the
-        * target value for the LP has been increased and this vary off
-        * would bring us below the new target.
-        */
-       HvCall0(HvCallBaseSetVirtualDecr);
-}
-
-static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
-{
-       HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm);
-}
-
-static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts)
-{
-       HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts);
-}
-
-static inline void HvCall_setLogBufferFormatAndCodepage(int format,
-               u32 codePage)
-{
-       HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage);
-}
-
-extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
-
-static inline void HvCall_sendIPI(struct paca_struct *targetPaca)
-{
-       HvCall1(HvCallBaseSendIPI, targetPaca->paca_index);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_event.h b/arch/powerpc/include/asm/iseries/hv_call_event.h
deleted file mode 100644 (file)
index cc029d3..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H
-
-#include <linux/types.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/abs_addr.h>
-
-struct HvLpEvent;
-
-typedef u8 HvLpEvent_Type;
-typedef u8 HvLpEvent_AckInd;
-typedef u8 HvLpEvent_AckType;
-
-typedef u8 HvLpDma_Direction;
-typedef u8 HvLpDma_AddressType;
-
-typedef u64 HvLpEvent_Rc;
-typedef u64 HvLpDma_Rc;
-
-#define HvCallEventAckLpEvent                          HvCallEvent +  0
-#define HvCallEventCancelLpEvent                       HvCallEvent +  1
-#define HvCallEventCloseLpEventPath                    HvCallEvent +  2
-#define HvCallEventDmaBufList                          HvCallEvent +  3
-#define HvCallEventDmaSingle                           HvCallEvent +  4
-#define HvCallEventDmaToSp                             HvCallEvent +  5
-#define HvCallEventGetOverflowLpEvents                 HvCallEvent +  6
-#define HvCallEventGetSourceLpInstanceId               HvCallEvent +  7
-#define HvCallEventGetTargetLpInstanceId               HvCallEvent +  8
-#define HvCallEventOpenLpEventPath                     HvCallEvent +  9
-#define HvCallEventSetLpEventStack                     HvCallEvent + 10
-#define HvCallEventSignalLpEvent                       HvCallEvent + 11
-#define HvCallEventSignalLpEventParms                  HvCallEvent + 12
-#define HvCallEventSetInterLpQueueIndex                        HvCallEvent + 13
-#define HvCallEventSetLpEventQueueInterruptProc                HvCallEvent + 14
-#define HvCallEventRouter15                            HvCallEvent + 15
-
-static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex)
-{
-       HvCall1(HvCallEventGetOverflowLpEvents, queueIndex);
-}
-
-static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex)
-{
-       HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex);
-}
-
-static inline void HvCallEvent_setLpEventStack(u8 queueIndex,
-               char *eventStackAddr, u32 eventStackSize)
-{
-       HvCall3(HvCallEventSetLpEventStack, queueIndex,
-                       virt_to_abs(eventStackAddr), eventStackSize);
-}
-
-static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex,
-               u16 lpLogicalProcIndex)
-{
-       HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex,
-                       lpLogicalProcIndex);
-}
-
-static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event)
-{
-       return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp,
-               HvLpEvent_Type type, u16 subtype, HvLpEvent_AckInd ackInd,
-               HvLpEvent_AckType ackType, HvLpInstanceId sourceInstanceId,
-               HvLpInstanceId targetInstanceId, u64 correlationToken,
-               u64 eventData1, u64 eventData2, u64 eventData3,
-               u64 eventData4, u64 eventData5)
-{
-       /* Pack the misc bits into a single Dword to pass to PLIC */
-       union {
-               struct {
-                       u8              ack_and_target;
-                       u8              type;
-                       u16             subtype;
-                       HvLpInstanceId  src_inst;
-                       HvLpInstanceId  target_inst;
-               } parms;
-               u64             dword;
-       } packed;
-
-       packed.parms.ack_and_target = (ackType << 7) | (ackInd << 6) | targetLp;
-       packed.parms.type = type;
-       packed.parms.subtype = subtype;
-       packed.parms.src_inst = sourceInstanceId;
-       packed.parms.target_inst = targetInstanceId;
-
-       return HvCall7(HvCallEventSignalLpEventParms, packed.dword,
-                       correlationToken, eventData1, eventData2,
-                       eventData3, eventData4, eventData5);
-}
-
-extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag);
-extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle);
-extern dma_addr_t iseries_hv_map(void *vaddr, size_t size,
-                       enum dma_data_direction direction);
-extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction);
-
-static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event)
-{
-       return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event)
-{
-       return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event));
-}
-
-static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId(
-               HvLpIndex targetLp, HvLpEvent_Type type)
-{
-       return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type);
-}
-
-static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId(
-               HvLpIndex targetLp, HvLpEvent_Type type)
-{
-       return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type);
-}
-
-static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp,
-               HvLpEvent_Type type)
-{
-       HvCall2(HvCallEventOpenLpEventPath, targetLp, type);
-}
-
-static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp,
-               HvLpEvent_Type type)
-{
-       HvCall2(HvCallEventCloseLpEventPath, targetLp, type);
-}
-
-static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type,
-               HvLpIndex remoteLp, HvLpDma_Direction direction,
-               HvLpInstanceId localInstanceId,
-               HvLpInstanceId remoteInstanceId,
-               HvLpDma_AddressType localAddressType,
-               HvLpDma_AddressType remoteAddressType,
-               /* Do these need to be converted to absolute addresses? */
-               u64 localBufList, u64 remoteBufList, u32 transferLength)
-{
-       /* Pack the misc bits into a single Dword to pass to PLIC */
-       union {
-               struct {
-                       u8              flags;
-                       HvLpIndex       remote;
-                       u8              type;
-                       u8              reserved;
-                       HvLpInstanceId  local_inst;
-                       HvLpInstanceId  remote_inst;
-               } parms;
-               u64             dword;
-       } packed;
-
-       packed.parms.flags = (direction << 7) |
-               (localAddressType << 6) | (remoteAddressType << 5);
-       packed.parms.remote = remoteLp;
-       packed.parms.type = type;
-       packed.parms.reserved = 0;
-       packed.parms.local_inst = localInstanceId;
-       packed.parms.remote_inst = remoteInstanceId;
-
-       return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList,
-                       remoteBufList, transferLength);
-}
-
-static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote,
-               u32 length, HvLpDma_Direction dir)
-{
-       return HvCall4(HvCallEventDmaToSp, virt_to_abs(local), remote,
-                       length, dir);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_sc.h b/arch/powerpc/include/asm/iseries/hv_call_sc.h
deleted file mode 100644 (file)
index f5d2109..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_SC_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_SC_H
-
-#include <linux/types.h>
-
-#define HvCallBase             0x8000000000000000ul
-#define HvCallCc               0x8001000000000000ul
-#define HvCallCfg              0x8002000000000000ul
-#define HvCallEvent            0x8003000000000000ul
-#define HvCallHpt              0x8004000000000000ul
-#define HvCallPci              0x8005000000000000ul
-#define HvCallSm               0x8007000000000000ul
-#define HvCallXm               0x8009000000000000ul
-
-extern u64 HvCall0(u64);
-extern u64 HvCall1(u64, u64);
-extern u64 HvCall2(u64, u64, u64);
-extern u64 HvCall3(u64, u64, u64, u64);
-extern u64 HvCall4(u64, u64, u64, u64, u64);
-extern u64 HvCall5(u64, u64, u64, u64, u64, u64);
-extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64);
-extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64);
-
-extern u64 HvCall0Ret16(u64, void *);
-extern u64 HvCall1Ret16(u64, void *, u64);
-extern u64 HvCall2Ret16(u64, void *, u64, u64);
-extern u64 HvCall3Ret16(u64, void *, u64, u64, u64);
-extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64);
-extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64);
-extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64);
-extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64);
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_SC_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_call_xm.h b/arch/powerpc/include/asm/iseries/hv_call_xm.h
deleted file mode 100644 (file)
index 392ac3f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from SLIC.
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_CALL_XM_H
-#define _ASM_POWERPC_ISERIES_HV_CALL_XM_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-#define HvCallXmGetTceTableParms       HvCallXm +  0
-#define HvCallXmTestBus                        HvCallXm +  1
-#define HvCallXmConnectBusUnit         HvCallXm +  2
-#define HvCallXmLoadTod                        HvCallXm +  8
-#define HvCallXmTestBusUnit            HvCallXm +  9
-#define HvCallXmSetTce                 HvCallXm + 11
-#define HvCallXmSetTces                        HvCallXm + 13
-
-static inline void HvCallXm_getTceTableParms(u64 cb)
-{
-       HvCall1(HvCallXmGetTceTableParms, cb);
-}
-
-static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
-{
-       return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce);
-}
-
-static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset,
-               u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4)
-{
-       return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces,
-                            tce1, tce2, tce3, tce4);
-}
-
-static inline u64 HvCallXm_testBus(u16 busNumber)
-{
-       return HvCall1(HvCallXmTestBus, busNumber);
-}
-
-static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber,
-               u8 deviceId)
-{
-       return HvCall2(HvCallXmTestBusUnit, busNumber,
-                       (subBusNumber << 8) | deviceId);
-}
-
-static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber,
-               u8 deviceId, u64 interruptToken)
-{
-       return HvCall5(HvCallXmConnectBusUnit, busNumber,
-                       (subBusNumber << 8) | deviceId, interruptToken, 0,
-                       0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */);
-}
-
-static inline u64 HvCallXm_loadTod(void)
-{
-       return HvCall0(HvCallXmLoadTod);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_CALL_XM_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_config.h b/arch/powerpc/include/asm/iseries/hv_lp_config.h
deleted file mode 100644 (file)
index a006fd1..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H
-#define _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H
-
-/*
- * This file contains the interface to the LPAR configuration data
- * to determine which resources should be allocated to each partition.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-enum {
-       HvCallCfg_Cur   = 0,
-       HvCallCfg_Init  = 1,
-       HvCallCfg_Max   = 2,
-       HvCallCfg_Min   = 3
-};
-
-#define HvCallCfgGetSystemPhysicalProcessors           HvCallCfg +  6
-#define HvCallCfgGetPhysicalProcessors                 HvCallCfg +  7
-#define HvCallCfgGetMsChunks                           HvCallCfg +  9
-#define HvCallCfgGetSharedPoolIndex                    HvCallCfg + 20
-#define HvCallCfgGetSharedProcUnits                    HvCallCfg + 21
-#define HvCallCfgGetNumProcsInSharedPool               HvCallCfg + 22
-#define HvCallCfgGetVirtualLanIndexMap                 HvCallCfg + 30
-#define HvCallCfgGetHostingLpIndex                     HvCallCfg + 32
-
-extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
-extern HvLpIndex HvLpConfig_getLpIndex(void);
-extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void);
-
-static inline u64 HvLpConfig_getMsChunks(void)
-{
-       return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(),
-                       HvCallCfg_Cur);
-}
-
-static inline u64 HvLpConfig_getSystemPhysicalProcessors(void)
-{
-       return HvCall0(HvCallCfgGetSystemPhysicalProcessors);
-}
-
-static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
-{
-       return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI);
-}
-
-static inline u64 HvLpConfig_getPhysicalProcessors(void)
-{
-       return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
-                       HvCallCfg_Cur);
-}
-
-static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void)
-{
-       return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex());
-}
-
-static inline u64 HvLpConfig_getSharedProcUnits(void)
-{
-       return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
-                       HvCallCfg_Cur);
-}
-
-static inline u64 HvLpConfig_getMaxSharedProcUnits(void)
-{
-       return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
-                       HvCallCfg_Max);
-}
-
-static inline u64 HvLpConfig_getMaxPhysicalProcessors(void)
-{
-       return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
-                       HvCallCfg_Max);
-}
-
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp(
-               HvLpIndex lp)
-{
-       /*
-        * This is a new function in V5R1 so calls to this on older
-        * hypervisors will return -1
-        */
-       u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp);
-       if (retVal == -1)
-               retVal = 0;
-       return retVal;
-}
-
-static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void)
-{
-       return HvLpConfig_getVirtualLanIndexMapForLp(
-                       HvLpConfig_getLpIndex_outline());
-}
-
-static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1,
-               HvLpIndex lp2)
-{
-       HvLpVirtualLanIndexMap virtualLanIndexMap1 =
-               HvLpConfig_getVirtualLanIndexMapForLp(lp1);
-       HvLpVirtualLanIndexMap virtualLanIndexMap2 =
-               HvLpConfig_getVirtualLanIndexMapForLp(lp2);
-       return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0);
-}
-
-static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp)
-{
-       return HvCall1(HvCallCfgGetHostingLpIndex, lp);
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_event.h b/arch/powerpc/include/asm/iseries/hv_lp_event.h
deleted file mode 100644 (file)
index 8f5da7d..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-/* This file contains the class for HV events in the system. */
-
-#ifndef _ASM_POWERPC_ISERIES_HV_LP_EVENT_H
-#define _ASM_POWERPC_ISERIES_HV_LP_EVENT_H
-
-#include <asm/types.h>
-#include <asm/ptrace.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_event.h>
-
-/*
- * HvLpEvent is the structure for Lp Event messages passed between
- * partitions through PLIC.
- */
-
-struct HvLpEvent {
-       u8      flags;                  /* Event flags                x00-x00 */
-       u8      xType;                  /* Type of message            x01-x01 */
-       u16     xSubtype;               /* Subtype for event          x02-x03 */
-       u8      xSourceLp;              /* Source LP                  x04-x04 */
-       u8      xTargetLp;              /* Target LP                  x05-x05 */
-       u8      xSizeMinus1;            /* Size of Derived class - 1  x06-x06 */
-       u8      xRc;                    /* RC for Ack flows           x07-x07 */
-       u16     xSourceInstanceId;      /* Source sides instance id   x08-x09 */
-       u16     xTargetInstanceId;      /* Target sides instance id   x0A-x0B */
-       union {
-               u32     xSubtypeData;   /* Data usable by the subtype x0C-x0F */
-               u16     xSubtypeDataShort[2];   /* Data as 2 shorts */
-               u8      xSubtypeDataChar[4];    /* Data as 4 chars */
-       } x;
-
-       u64     xCorrelationToken;      /* Unique value for source/type x10-x17 */
-};
-
-typedef void (*LpEventHandler)(struct HvLpEvent *);
-
-/* Register a handler for an event type - returns 0 on success */
-extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType,
-               LpEventHandler hdlr);
-
-/*
- * Unregister a handler for an event type
- *
- * This call will sleep until the handler being removed is guaranteed to
- * be no longer executing on any CPU. Do not call with locks held.
- *
- *  returns 0 on success
- *  Unregister will fail if there are any paths open for the type
- */
-extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType);
-
-/*
- * Open an Lp Event Path for an event type
- * returns 0 on success
- * openPath will fail if there is no handler registered for the event type.
- * The lpIndex specified is the partition index for the target partition
- * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero)
- */
-extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
-
-/*
- * Close an Lp Event Path for a type and partition
- * returns 0 on success
- */
-extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex);
-
-#define HvLpEvent_Type_Hypervisor 0
-#define HvLpEvent_Type_MachineFac 1
-#define HvLpEvent_Type_SessionMgr 2
-#define HvLpEvent_Type_SpdIo      3
-#define HvLpEvent_Type_VirtualBus 4
-#define HvLpEvent_Type_PciIo      5
-#define HvLpEvent_Type_RioIo      6
-#define HvLpEvent_Type_VirtualLan 7
-#define HvLpEvent_Type_VirtualIo  8
-#define HvLpEvent_Type_NumTypes   9
-
-#define HvLpEvent_Rc_Good 0
-#define HvLpEvent_Rc_BufferNotAvailable 1
-#define HvLpEvent_Rc_Cancelled 2
-#define HvLpEvent_Rc_GenericError 3
-#define HvLpEvent_Rc_InvalidAddress 4
-#define HvLpEvent_Rc_InvalidPartition 5
-#define HvLpEvent_Rc_InvalidSize 6
-#define HvLpEvent_Rc_InvalidSubtype 7
-#define HvLpEvent_Rc_InvalidSubtypeData 8
-#define HvLpEvent_Rc_InvalidType 9
-#define HvLpEvent_Rc_PartitionDead 10
-#define HvLpEvent_Rc_PathClosed 11
-#define HvLpEvent_Rc_SubtypeError 12
-
-#define HvLpEvent_Function_Ack 0
-#define HvLpEvent_Function_Int 1
-
-#define HvLpEvent_AckInd_NoAck 0
-#define HvLpEvent_AckInd_DoAck 1
-
-#define HvLpEvent_AckType_ImmediateAck 0
-#define HvLpEvent_AckType_DeferredAck 1
-
-#define HV_LP_EVENT_INT                        0x01
-#define HV_LP_EVENT_DO_ACK             0x02
-#define HV_LP_EVENT_DEFERRED_ACK       0x04
-#define HV_LP_EVENT_VALID              0x80
-
-#define HvLpDma_Direction_LocalToRemote 0
-#define HvLpDma_Direction_RemoteToLocal 1
-
-#define HvLpDma_AddressType_TceIndex 0
-#define HvLpDma_AddressType_RealAddress 1
-
-#define HvLpDma_Rc_Good 0
-#define HvLpDma_Rc_Error 1
-#define HvLpDma_Rc_PartitionDead 2
-#define HvLpDma_Rc_PathClosed 3
-#define HvLpDma_Rc_InvalidAddress 4
-#define HvLpDma_Rc_InvalidLength 5
-
-static inline int hvlpevent_is_valid(struct HvLpEvent *h)
-{
-       return h->flags & HV_LP_EVENT_VALID;
-}
-
-static inline void hvlpevent_invalidate(struct HvLpEvent *h)
-{
-       h->flags &= ~ HV_LP_EVENT_VALID;
-}
-
-static inline int hvlpevent_is_int(struct HvLpEvent *h)
-{
-       return h->flags & HV_LP_EVENT_INT;
-}
-
-static inline int hvlpevent_is_ack(struct HvLpEvent *h)
-{
-       return !hvlpevent_is_int(h);
-}
-
-static inline int hvlpevent_need_ack(struct HvLpEvent *h)
-{
-       return h->flags & HV_LP_EVENT_DO_ACK;
-}
-
-#endif /* _ASM_POWERPC_ISERIES_HV_LP_EVENT_H */
diff --git a/arch/powerpc/include/asm/iseries/hv_types.h b/arch/powerpc/include/asm/iseries/hv_types.h
deleted file mode 100644 (file)
index c3e6d2a..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_HV_TYPES_H
-#define _ASM_POWERPC_ISERIES_HV_TYPES_H
-
-/*
- * General typedefs for the hypervisor.
- */
-
-#include <asm/types.h>
-
-typedef u8     HvLpIndex;
-typedef u16    HvLpInstanceId;
-typedef u64    HvLpTOD;
-typedef u64    HvLpSystemSerialNum;
-typedef u8     HvLpDeviceSerialNum[12];
-typedef u16    HvLpSanHwSet;
-typedef u16    HvLpBus;
-typedef u16    HvLpBoard;
-typedef u16    HvLpCard;
-typedef u8     HvLpDeviceType[4];
-typedef u8     HvLpDeviceModel[3];
-typedef u64    HvIoToken;
-typedef u8     HvLpName[8];
-typedef u32    HvIoId;
-typedef u64    HvRealMemoryIndex;
-typedef u32    HvLpIndexMap;   /* Must hold HVMAXARCHITECTEDLPS bits!!! */
-typedef u16    HvLpVrmIndex;
-typedef u32    HvXmGenerationId;
-typedef u8     HvLpBusPool;
-typedef u8     HvLpSharedPoolIndex;
-typedef u16    HvLpSharedProcUnitsX100;
-typedef u8     HvLpVirtualLanIndex;
-typedef u16    HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */
-typedef u16    HvBusNumber;    /* Hypervisor Bus Number */
-typedef u8     HvSubBusNumber; /* Hypervisor SubBus Number */
-typedef u8     HvAgentId;      /* Hypervisor DevFn */
-
-
-#define HVMAXARCHITECTEDLPS            32
-#define HVMAXARCHITECTEDVIRTUALLANS    16
-#define HVMAXARCHITECTEDVIRTUALDISKS   32
-#define HVMAXARCHITECTEDVIRTUALCDROMS  8
-#define HVMAXARCHITECTEDVIRTUALTAPES   8
-#define HVCHUNKSIZE                    (256 * 1024)
-#define HVPAGESIZE                     (4 * 1024)
-#define HVLPMINMEGSPRIMARY             256
-#define HVLPMINMEGSSECONDARY           64
-#define HVCHUNKSPERMEG                 4
-#define HVPAGESPERMEG                  256
-#define HVPAGESPERCHUNK                        64
-
-#define HvLpIndexInvalid               ((HvLpIndex)0xff)
-
-/*
- * Enums for the sub-components under PLIC
- * Used in HvCall  and HvPrimaryCall
- */
-enum {
-       HvCallCompId = 0,
-       HvCallCpuCtlsCompId = 1,
-       HvCallCfgCompId = 2,
-       HvCallEventCompId = 3,
-       HvCallHptCompId = 4,
-       HvCallPciCompId = 5,
-       HvCallSlmCompId = 6,
-       HvCallSmCompId = 7,
-       HvCallSpdCompId = 8,
-       HvCallXmCompId = 9,
-       HvCallRioCompId = 10,
-       HvCallRsvd3CompId = 11,
-       HvCallRsvd2CompId = 12,
-       HvCallRsvd1CompId = 13,
-       HvCallMaxCompId = 14,
-       HvPrimaryCallCompId = 0,
-       HvPrimaryCallCfgCompId = 1,
-       HvPrimaryCallPciCompId = 2,
-       HvPrimaryCallSmCompId = 3,
-       HvPrimaryCallSpdCompId = 4,
-       HvPrimaryCallXmCompId = 5,
-       HvPrimaryCallRioCompId = 6,
-       HvPrimaryCallRsvd7CompId = 7,
-       HvPrimaryCallRsvd6CompId = 8,
-       HvPrimaryCallRsvd5CompId = 9,
-       HvPrimaryCallRsvd4CompId = 10,
-       HvPrimaryCallRsvd3CompId = 11,
-       HvPrimaryCallRsvd2CompId = 12,
-       HvPrimaryCallRsvd1CompId = 13,
-       HvPrimaryCallMaxCompId = HvCallMaxCompId
-};
-
-struct HvLpBufferList {
-       u64 addr;
-       u64 len;
-};
-
-#endif /* _ASM_POWERPC_ISERIES_HV_TYPES_H */
diff --git a/arch/powerpc/include/asm/iseries/iommu.h b/arch/powerpc/include/asm/iseries/iommu.h
deleted file mode 100644 (file)
index 1b9692c..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _ASM_POWERPC_ISERIES_IOMMU_H
-#define _ASM_POWERPC_ISERIES_IOMMU_H
-
-/*
- * Copyright (C) 2005  Stephen Rothwell, IBM 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; 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
- */
-
-struct pci_dev;
-struct vio_dev;
-struct device_node;
-struct iommu_table;
-
-/* Get table parameters from HV */
-extern void iommu_table_getparms_iSeries(unsigned long busno,
-               unsigned char slotno, unsigned char virtbus,
-               struct iommu_table *tbl);
-
-extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev);
-extern void iommu_vio_init(void);
-
-#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */
diff --git a/arch/powerpc/include/asm/iseries/it_lp_queue.h b/arch/powerpc/include/asm/iseries/it_lp_queue.h
deleted file mode 100644 (file)
index 4282788..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H
-#define _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H
-
-/*
- *     This control block defines the simple LP queue structure that is
- *     shared between the hypervisor (PLIC) and the OS in order to send
- *     events to an LP.
- */
-
-#include <asm/types.h>
-#include <asm/ptrace.h>
-
-#define IT_LP_MAX_QUEUES       8
-
-#define IT_LP_NOT_USED         0       /* Queue will not be used by PLIC */
-#define IT_LP_DEDICATED_IO     1       /* Queue dedicated to IO processor specified */
-#define IT_LP_DEDICATED_LP     2       /* Queue dedicated to LP specified */
-#define IT_LP_SHARED           3       /* Queue shared for both IO and LP */
-
-#define IT_LP_EVENT_STACK_SIZE 4096
-#define IT_LP_EVENT_MAX_SIZE   256
-#define IT_LP_EVENT_ALIGN      64
-
-struct hvlpevent_queue {
-/*
- * The hq_current_event is the pointer to the next event stack entry
- * that will become valid.  The OS must peek at this entry to determine
- * if it is valid.  PLIC will set the valid indicator as the very last
- * store into that entry.
- *
- * When the OS has completed processing of the event then it will mark
- * the event as invalid so that PLIC knows it can store into that event
- * location again.
- *
- * If the event stack fills and there are overflow events, then PLIC
- * will set the hq_overflow_pending flag in which case the OS will
- * have to fetch the additional LP events once they have drained the
- * event stack.
- *
- * The first 16-bytes are known by both the OS and PLIC.  The remainder
- * of the cache line is for use by the OS.
- */
-       u8              hq_overflow_pending;    /* 0x00 Overflow events are pending */
-       u8              hq_status;              /* 0x01 DedicatedIo or DedicatedLp or NotUsed */
-       u16             hq_proc_index;          /* 0x02 Logical Proc Index for correlation */
-       u8              hq_reserved1[12];       /* 0x04 */
-       char            *hq_current_event;      /* 0x10 */
-       char            *hq_last_event;         /* 0x18 */
-       char            *hq_event_stack;        /* 0x20 */
-       u8              hq_index;               /* 0x28 unique sequential index. */
-       u8              hq_reserved2[3];        /* 0x29-2b */
-       spinlock_t      hq_lock;
-};
-
-extern struct hvlpevent_queue hvlpevent_queue;
-
-extern int hvlpevent_is_pending(void);
-extern void process_hvlpevents(void);
-extern void setup_hvlpevent_queue(void);
-
-#endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */
diff --git a/arch/powerpc/include/asm/iseries/lpar_map.h b/arch/powerpc/include/asm/iseries/lpar_map.h
deleted file mode 100644 (file)
index 5e9f3e1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_LPAR_MAP_H
-#define _ASM_POWERPC_ISERIES_LPAR_MAP_H
-
-#ifndef __ASSEMBLY__
-
-#include <asm/types.h>
-
-#endif
-
-/*
- * The iSeries hypervisor will set up mapping for one or more
- * ESID/VSID pairs (in SLB/segment registers) and will set up
- * mappings of one or more ranges of pages to VAs.
- * We will have the hypervisor set up the ESID->VSID mapping
- * for the four kernel segments (C-F).  With shared processors,
- * the hypervisor will clear all segment registers and reload
- * these four whenever the processor is switched from one
- * partition to another.
- */
-
-/* The Vsid and Esid identified below will be used by the hypervisor
- * to set up a memory mapping for part of the load area before giving
- * control to the Linux kernel.  The load area is 64 MB, but this must
- * not attempt to map the whole load area.  The Hashed Page Table may
- * need to be located within the load area (if the total partition size
- * is 64 MB), but cannot be mapped.  Typically, this should specify
- * to map half (32 MB) of the load area.
- *
- * The hypervisor will set up page table entries for the number of
- * pages specified.
- *
- * In 32-bit mode, the hypervisor will load all four of the
- * segment registers (identified by the low-order four bits of the
- * Esid field.  In 64-bit mode, the hypervisor will load one SLB
- * entry to map the Esid to the Vsid.
-*/
-
-#define HvEsidsToMap   2
-#define HvRangesToMap  1
-
-/* Hypervisor initially maps 32MB of the load area */
-#define HvPagesToMap   8192
-
-#ifndef __ASSEMBLY__
-struct LparMap {
-       u64     xNumberEsids;   // Number of ESID/VSID pairs
-       u64     xNumberRanges;  // Number of VA ranges to map
-       u64     xSegmentTableOffs; // Page number within load area of seg table
-       u64     xRsvd[5];
-       struct {
-               u64     xKernelEsid;    // Esid used to map kernel load
-               u64     xKernelVsid;    // Vsid used to map kernel load
-       } xEsids[HvEsidsToMap];
-       struct {
-               u64     xPages;         // Number of pages to be mapped
-               u64     xOffset;        // Offset from start of load area
-               u64     xVPN;           // Virtual Page Number
-       } xRanges[HvRangesToMap];
-};
-
-extern const struct LparMap    xLparMap;
-
-#endif /* __ASSEMBLY__ */
-
-/* the fixed address where the LparMap exists */
-#define LPARMAP_PHYS           0x7000
-
-#endif /* _ASM_POWERPC_ISERIES_LPAR_MAP_H */
diff --git a/arch/powerpc/include/asm/iseries/mf.h b/arch/powerpc/include/asm/iseries/mf.h
deleted file mode 100644 (file)
index eb851a9..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2001  Troy D. Armstrong IBM Corporation
- * Copyright (C) 2004  Stephen Rothwell IBM Corporation
- *
- * This modules exists as an interface between a Linux secondary partition
- * running on an iSeries and the primary partition's Virtual Service
- * Processor (VSP) object.  The VSP has final authority over powering on/off
- * all partitions in the iSeries.  It also provides miscellaneous low-level
- * machine facility type operations.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ASM_POWERPC_ISERIES_MF_H
-#define _ASM_POWERPC_ISERIES_MF_H
-
-#include <linux/types.h>
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_event.h>
-
-struct rtc_time;
-
-typedef void (*MFCompleteHandler)(void *clientToken, int returnCode);
-
-extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
-               unsigned size, unsigned amount, MFCompleteHandler hdlr,
-               void *userToken);
-extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
-               unsigned count, MFCompleteHandler hdlr, void *userToken);
-
-extern void mf_power_off(void);
-extern void mf_reboot(char *cmd);
-
-extern void mf_display_src(u32 word);
-extern void mf_display_progress(u16 value);
-
-extern void mf_init(void);
-
-#endif /* _ASM_POWERPC_ISERIES_MF_H */
diff --git a/arch/powerpc/include/asm/iseries/vio.h b/arch/powerpc/include/asm/iseries/vio.h
deleted file mode 100644 (file)
index f9ac0d0..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/* -*- linux-c -*-
- *
- *  iSeries Virtual I/O Message Path header
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *
- * (C) Copyright 2000 IBM Corporation
- *
- * This header file is used by the iSeries virtual I/O device
- * drivers.  It defines the interfaces to the common functions
- * (implemented in drivers/char/viopath.h) as well as defining
- * common functions and structures.  Currently (at the time I
- * wrote this comment) the iSeries virtual I/O device drivers
- * that use this are
- *   drivers/block/viodasd.c
- *   drivers/char/viocons.c
- *   drivers/char/viotape.c
- *   drivers/cdrom/viocd.c
- *
- * The iSeries virtual ethernet support (veth.c) uses a whole
- * different set of functions.
- *
- * This program is free software;  you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) anyu later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#ifndef _ASM_POWERPC_ISERIES_VIO_H
-#define _ASM_POWERPC_ISERIES_VIO_H
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-
-/*
- * iSeries virtual I/O events use the subtype field in
- * HvLpEvent to figure out what kind of vio event is coming
- * in.  We use a table to route these, and this defines
- * the maximum number of distinct subtypes
- */
-#define VIO_MAX_SUBTYPES 8
-
-#define VIOMAXBLOCKDMA 12
-
-struct open_data {
-       u64     disk_size;
-       u16     max_disk;
-       u16     cylinders;
-       u16     tracks;
-       u16     sectors;
-       u16     bytes_per_sector;
-};
-
-struct rw_data {
-       u64     offset;
-       struct {
-               u32     token;
-               u32     reserved;
-               u64     len;
-       } dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
-       struct HvLpEvent        event;
-       u32                     reserved;
-       u16                     version;
-       u16                     sub_result;
-       u16                     disk;
-       u16                     flags;
-       union {
-               struct open_data        open_data;
-               struct rw_data          rw_data;
-               u64                     changed;
-       } u;
-};
-
-#define vioblockflags_ro   0x0001
-
-enum vioblocksubtype {
-       vioblockopen = 0x0001,
-       vioblockclose = 0x0002,
-       vioblockread = 0x0003,
-       vioblockwrite = 0x0004,
-       vioblockflush = 0x0005,
-       vioblockcheck = 0x0007
-};
-
-struct viocdlpevent {
-       struct HvLpEvent        event;
-       u32                     reserved;
-       u16                     version;
-       u16                     sub_result;
-       u16                     disk;
-       u16                     flags;
-       u32                     token;
-       u64                     offset;         /* On open, max number of disks */
-       u64                     len;            /* On open, size of the disk */
-       u32                     block_size;     /* Only set on open */
-       u32                     media_size;     /* Only set on open */
-};
-
-enum viocdsubtype {
-       viocdopen = 0x0001,
-       viocdclose = 0x0002,
-       viocdread = 0x0003,
-       viocdwrite = 0x0004,
-       viocdlockdoor = 0x0005,
-       viocdgetinfo = 0x0006,
-       viocdcheck = 0x0007
-};
-
-struct viotapelpevent {
-       struct HvLpEvent event;
-       u32 reserved;
-       u16 version;
-       u16 sub_type_result;
-       u16 tape;
-       u16 flags;
-       u32 token;
-       u64 len;
-       union {
-               struct {
-                       u32 tape_op;
-                       u32 count;
-               } op;
-               struct {
-                       u32 type;
-                       u32 resid;
-                       u32 dsreg;
-                       u32 gstat;
-                       u32 erreg;
-                       u32 file_no;
-                       u32 block_no;
-               } get_status;
-               struct {
-                       u32 block_no;
-               } get_pos;
-       } u;
-};
-
-enum viotapesubtype {
-       viotapeopen = 0x0001,
-       viotapeclose = 0x0002,
-       viotaperead = 0x0003,
-       viotapewrite = 0x0004,
-       viotapegetinfo = 0x0005,
-       viotapeop = 0x0006,
-       viotapegetpos = 0x0007,
-       viotapesetpos = 0x0008,
-       viotapegetstatus = 0x0009
-};
-
-/*
- * Each subtype can register a handler to process their events.
- * The handler must have this interface.
- */
-typedef void (vio_event_handler_t) (struct HvLpEvent * event);
-
-extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
-extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
-extern int vio_setHandler(int subtype, vio_event_handler_t * beh);
-extern int vio_clearHandler(int subtype);
-extern int viopath_isactive(HvLpIndex lp);
-extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
-extern HvLpInstanceId viopath_targetinst(HvLpIndex lp);
-extern void vio_set_hostlp(void);
-extern void *vio_get_event_buffer(int subtype);
-extern void vio_free_event_buffer(int subtype, void *buffer);
-
-extern struct vio_dev *vio_create_viodasd(u32 unit);
-
-extern HvLpIndex viopath_hostLp;
-extern HvLpIndex viopath_ourLp;
-
-#define VIOCHAR_MAX_DATA       200
-
-#define VIOMAJOR_SUBTYPE_MASK  0xff00
-#define VIOMINOR_SUBTYPE_MASK  0x00ff
-#define VIOMAJOR_SUBTYPE_SHIFT 8
-
-#define VIOVERSION             0x0101
-
-/*
- * This is the general structure for VIO errors; each module should have
- * a table of them, and each table should be terminated by an entry of
- * { 0, 0, NULL }.  Then, to find a specific error message, a module
- * should pass its local table and the return code.
- */
-struct vio_error_entry {
-       u16 rc;
-       int errno;
-       const char *msg;
-};
-extern const struct vio_error_entry *vio_lookup_rc(
-               const struct vio_error_entry *local_table, u16 rc);
-
-enum viosubtypes {
-       viomajorsubtype_monitor = 0x0100,
-       viomajorsubtype_blockio = 0x0200,
-       viomajorsubtype_chario = 0x0300,
-       viomajorsubtype_config = 0x0400,
-       viomajorsubtype_cdio = 0x0500,
-       viomajorsubtype_tape = 0x0600,
-       viomajorsubtype_scsi = 0x0700
-};
-
-enum vioconfigsubtype {
-       vioconfigget = 0x0001,
-};
-
-enum viorc {
-       viorc_good = 0x0000,
-       viorc_noConnection = 0x0001,
-       viorc_noReceiver = 0x0002,
-       viorc_noBufferAvailable = 0x0003,
-       viorc_invalidMessageType = 0x0004,
-       viorc_invalidRange = 0x0201,
-       viorc_invalidToken = 0x0202,
-       viorc_DMAError = 0x0203,
-       viorc_useError = 0x0204,
-       viorc_releaseError = 0x0205,
-       viorc_invalidDisk = 0x0206,
-       viorc_openRejected = 0x0301
-};
-
-/*
- * The structure of the events that flow between us and OS/400 for chario
- * events.  You can't mess with this unless the OS/400 side changes too.
- */
-struct viocharlpevent {
-       struct HvLpEvent event;
-       u32 reserved;
-       u16 version;
-       u16 subtype_result_code;
-       u8 virtual_device;
-       u8 len;
-       u8 data[VIOCHAR_MAX_DATA];
-};
-
-#define VIOCHAR_WINDOW         10
-
-enum viocharsubtype {
-       viocharopen = 0x0001,
-       viocharclose = 0x0002,
-       viochardata = 0x0003,
-       viocharack = 0x0004,
-       viocharconfig = 0x0005
-};
-
-enum viochar_rc {
-       viochar_rc_ebusy = 1
-};
-
-#endif /* _ASM_POWERPC_ISERIES_VIO_H */
index e0298d2..a76254a 100644 (file)
  * 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 Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
index a5b7c56..c65b929 100644 (file)
@@ -273,7 +273,6 @@ struct mpic
        unsigned int            isu_size;
        unsigned int            isu_shift;
        unsigned int            isu_mask;
-       unsigned int            irq_count;
        /* Number of sources */
        unsigned int            num_sources;
        /* default senses array */
@@ -349,8 +348,6 @@ struct mpic
 #define MPIC_U3_HT_IRQS                        0x00000004
 /* Broken IPI registers (autodetected) */
 #define MPIC_BROKEN_IPI                        0x00000008
-/* MPIC wants a reset */
-#define MPIC_WANTS_RESET               0x00000010
 /* Spurious vector requires EOI */
 #define MPIC_SPV_EOI                   0x00000020
 /* No passthrough disable */
@@ -363,15 +360,11 @@ struct mpic
 #define MPIC_ENABLE_MCK                        0x00000200
 /* Disable bias among target selection, spread interrupts evenly */
 #define MPIC_NO_BIAS                   0x00000400
-/* Ignore NIRQS as reported by FRR */
-#define MPIC_BROKEN_FRR_NIRQS          0x00000800
 /* Destination only supports a single CPU at a time */
 #define MPIC_SINGLE_DEST_CPU           0x00001000
 /* Enable CoreInt delivery of interrupts */
 #define MPIC_ENABLE_COREINT            0x00002000
-/* Disable resetting of the MPIC.
- * NOTE: This flag trumps MPIC_WANTS_RESET.
- */
+/* Do not reset the MPIC during initialization */
 #define MPIC_NO_RESET                  0x00004000
 /* Freescale MPIC (compatible includes "fsl,mpic") */
 #define MPIC_FSL                       0x00008000
diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h
new file mode 100644 (file)
index 0000000..3ec37dc
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2011-2012, Meador Inge, Mentor Graphics 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.
+ *
+ */
+
+#ifndef _ASM_MPIC_MSGR_H
+#define _ASM_MPIC_MSGR_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct mpic_msgr {
+       u32 __iomem *base;
+       u32 __iomem *mer;
+       int irq;
+       unsigned char in_use;
+       raw_spinlock_t lock;
+       int num;
+};
+
+/* Get a message register
+ *
+ * @reg_num:   the MPIC message register to get
+ *
+ * A pointer to the message register is returned.  If
+ * the message register asked for is already in use, then
+ * EBUSY is returned.  If the number given is not associated
+ * with an actual message register, then ENODEV is returned.
+ * Successfully getting the register marks it as in use.
+ */
+extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num);
+
+/* Relinquish a message register
+ *
+ * @msgr:      the message register to return
+ *
+ * Disables the given message register and marks it as free.
+ * After this call has completed successully the message
+ * register is available to be acquired by a call to
+ * mpic_msgr_get.
+ */
+extern void mpic_msgr_put(struct mpic_msgr *msgr);
+
+/* Enable a message register
+ *
+ * @msgr:      the message register to enable
+ *
+ * The given message register is enabled for sending
+ * messages.
+ */
+extern void mpic_msgr_enable(struct mpic_msgr *msgr);
+
+/* Disable a message register
+ *
+ * @msgr:      the message register to disable
+ *
+ * The given message register is disabled for sending
+ * messages.
+ */
+extern void mpic_msgr_disable(struct mpic_msgr *msgr);
+
+/* Write a message to a message register
+ *
+ * @msgr:      the message register to write to
+ * @message:   the message to write
+ *
+ * The given 32-bit message is written to the given message
+ * register.  Writing to an enabled message registers fires
+ * an interrupt.
+ */
+static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message)
+{
+       out_be32(msgr->base, message);
+}
+
+/* Read a message from a message register
+ *
+ * @msgr:      the message register to read from
+ *
+ * Returns the 32-bit value currently in the given message register.
+ * Upon reading the register any interrupts for that register are
+ * cleared.
+ */
+static inline u32 mpic_msgr_read(struct mpic_msgr *msgr)
+{
+       return in_be32(msgr->base);
+}
+
+/* Clear a message register
+ *
+ * @msgr:      the message register to clear
+ *
+ * Clears any interrupts associated with the given message register.
+ */
+static inline void mpic_msgr_clear(struct mpic_msgr *msgr)
+{
+       (void) mpic_msgr_read(msgr);
+}
+
+/* Set the destination CPU for the message register
+ *
+ * @msgr:      the message register whose destination is to be set
+ * @cpu_num:   the Linux CPU number to bind the message register to
+ *
+ * Note that the CPU number given is the CPU number used by the kernel
+ * and *not* the actual hardware CPU number.
+ */
+static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr,
+                                            u32 cpu_num)
+{
+       out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num));
+}
+
+/* Get the IRQ number for the message register
+ * @msgr:      the message register whose IRQ is to be returned
+ *
+ * Returns the IRQ number associated with the given message register.
+ * NO_IRQ is returned if this message register is not capable of
+ * receiving interrupts.  What message register can and cannot receive
+ * interrupts is specified in the device tree for the system.
+ */
+static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr)
+{
+       return msgr->irq;
+}
+
+#endif
index 269c05a..daf813f 100644 (file)
@@ -132,7 +132,7 @@ struct paca_struct {
        u64 saved_msr;                  /* MSR saved here by enter_rtas */
        u16 trap_save;                  /* Used when bad stack is encountered */
        u8 soft_enabled;                /* irq soft-enable flag */
-       u8 hard_enabled;                /* set if irqs are enabled in MSR */
+       u8 irq_happened;                /* irq happened while soft-disabled */
        u8 io_sync;                     /* writel() needs spin_unlock sync */
        u8 irq_work_pending;            /* IRQ_WORK interrupt while soft-disable */
        u8 nap_state_lost;              /* NV GPR values lost in power7_idle */
diff --git a/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h
deleted file mode 100644 (file)
index fa74c6c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Hypervisor-assisted dump
- *
- * Linas Vepstas, Manish Ahuja 2008
- * Copyright 2008 IBM Corp.
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the 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 _PPC64_PHYP_DUMP_H
-#define _PPC64_PHYP_DUMP_H
-
-#ifdef CONFIG_PHYP_DUMP
-
-/* The RMR region will be saved for later dumping
- * whenever the kernel crashes. Set this to 256MB. */
-#define PHYP_DUMP_RMR_START 0x0
-#define PHYP_DUMP_RMR_END   (1UL<<28)
-
-struct phyp_dump {
-       /* Memory that is reserved during very early boot. */
-       unsigned long init_reserve_start;
-       unsigned long init_reserve_size;
-       /* cmd line options during boot */
-       unsigned long reserve_bootvar;
-       unsigned long phyp_dump_at_boot;
-       /* Check status during boot if dump supported, active & present*/
-       unsigned long phyp_dump_configured;
-       unsigned long phyp_dump_is_active;
-       /* store cpu & hpte size */
-       unsigned long cpu_state_size;
-       unsigned long hpte_region_size;
-       /* previous scratch area values */
-       unsigned long reserved_scratch_addr;
-       unsigned long reserved_scratch_size;
-};
-
-extern struct phyp_dump *phyp_dump_info;
-
-int early_init_dt_scan_phyp_dump(unsigned long node,
-               const char *uname, int depth, void *data);
-
-#endif /* CONFIG_PHYP_DUMP */
-#endif /* _PPC64_PHYP_DUMP_H */
index 6d42297..e660b37 100644 (file)
@@ -47,92 +47,21 @@ extern int rtas_setup_phb(struct pci_controller *phb);
 
 extern unsigned long pci_probe_only;
 
-/* ---- EEH internal-use-only related routines ---- */
 #ifdef CONFIG_EEH
 
+void pci_addr_cache_build(void);
 void pci_addr_cache_insert_device(struct pci_dev *dev);
 void pci_addr_cache_remove_device(struct pci_dev *dev);
-void pci_addr_cache_build(void);
-struct pci_dev *pci_get_device_by_addr(unsigned long addr);
-
-/**
- * eeh_slot_error_detail -- record and EEH error condition to the log
- * @pdn:      pci device node
- * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE
- *
- * Obtains the EEH error details from the RTAS subsystem,
- * and then logs these details with the RTAS error log system.
- */
-#define EEH_LOG_TEMP_FAILURE 1
-#define EEH_LOG_PERM_FAILURE 2
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
-
-/**
- * rtas_pci_enable - enable IO transfers for this slot
- * @pdn:       pci device node
- * @function:  either EEH_THAW_MMIO or EEH_THAW_DMA 
- *
- * Enable I/O transfers to this slot 
- */
-#define EEH_THAW_MMIO 2
-#define EEH_THAW_DMA  3
-int rtas_pci_enable(struct pci_dn *pdn, int function);
-
-/**
- * rtas_set_slot_reset -- unfreeze a frozen slot
- * @pdn:       pci device node
- *
- * Clear the EEH-frozen condition on a slot.  This routine
- * does this by asserting the PCI #RST line for 1/8th of
- * a second; this routine will sleep while the adapter is
- * being reset.
- *
- * Returns a non-zero value if the reset failed.
- */
-int rtas_set_slot_reset (struct pci_dn *);
-int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
-
-/** 
- * eeh_restore_bars - Restore device configuration info.
- * @pdn:       pci device node
- *
- * A reset of a PCI device will clear out its config space.
- * This routines will restore the config space for this
- * device, and is children, to values previously obtained
- * from the firmware.
- */
-void eeh_restore_bars(struct pci_dn *);
-
-/**
- * rtas_configure_bridge -- firmware initialization of pci bridge
- * @pdn:       pci device node
- *
- * Ask the firmware to configure all PCI bridges devices
- * located behind the indicated node. Required after a
- * pci device reset. Does essentially the same hing as
- * eeh_restore_bars, but for brdges, and lets firmware 
- * do the work.
- */
-void rtas_configure_bridge(struct pci_dn *);
-
+struct pci_dev *pci_addr_cache_get_device(unsigned long addr);
+void eeh_slot_error_detail(struct eeh_dev *edev, int severity);
+int eeh_pci_enable(struct eeh_dev *edev, int function);
+int eeh_reset_pe(struct eeh_dev *);
+void eeh_restore_bars(struct eeh_dev *);
 int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
-
-/**
- * eeh_mark_slot -- set mode flags for pertition endpoint
- * @pdn:       pci device node
- *
- * mark and clear slots: find "partition endpoint" PE and set or 
- * clear the flags for each subnode of the PE.
- */
-void eeh_mark_slot (struct device_node *dn, int mode_flag);
-void eeh_clear_slot (struct device_node *dn, int mode_flag);
-
-/**
- * find_device_pe -- Find the associated "Partiationable Endpoint" PE
- * @pdn:       pci device node
- */
-struct device_node * find_device_pe(struct device_node *dn);
+void eeh_mark_slot(struct device_node *dn, int mode_flag);
+void eeh_clear_slot(struct device_node *dn, int mode_flag);
+struct device_node *eeh_find_device_pe(struct device_node *dn);
 
 void eeh_sysfs_add_device(struct pci_dev *pdev);
 void eeh_sysfs_remove_device(struct pci_dev *pdev);
index 368f72f..50f73aa 100644 (file)
@@ -60,6 +60,8 @@ BEGIN_FW_FTR_SECTION;                                                 \
        cmpd    cr1,r11,r10;                                            \
        beq+    cr1,33f;                                                \
        bl      .accumulate_stolen_time;                                \
+       ld      r12,_MSR(r1);                                           \
+       andi.   r10,r12,MSR_PR;         /* Restore cr0 (coming from user) */ \
 33:                                                                    \
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 
index 7fdc2c0..b1a215e 100644 (file)
 
 #define proc_trap()    asm volatile("trap")
 
-#ifdef CONFIG_PPC64
-
-extern void ppc64_runlatch_on(void);
-extern void __ppc64_runlatch_off(void);
-
-#define ppc64_runlatch_off()                                   \
-       do {                                                    \
-               if (cpu_has_feature(CPU_FTR_CTRL) &&            \
-                   test_thread_flag(TIF_RUNLATCH))             \
-                       __ppc64_runlatch_off();                 \
-       } while (0)
+#define __get_SP()     ({unsigned long sp; \
+                       asm volatile("mr %0,1": "=r" (sp)); sp;})
 
 extern unsigned long scom970_read(unsigned int address);
 extern void scom970_write(unsigned int address, unsigned long value);
 
-#else
-#define ppc64_runlatch_on()
-#define ppc64_runlatch_off()
-
-#endif /* CONFIG_PPC64 */
-
-#define __get_SP()     ({unsigned long sp; \
-                       asm volatile("mr %0,1": "=r" (sp)); sp;})
-
 struct pt_regs;
 
 extern void ppc_save_regs(struct pt_regs *regs);
index 500fe1d..8a97aa7 100644 (file)
@@ -62,6 +62,7 @@
 #define SPRN_DVC2      0x13F   /* Data Value Compare Register 2 */
 #define SPRN_MAS8      0x155   /* MMU Assist Register 8 */
 #define SPRN_TLB0PS    0x158   /* TLB 0 Page Size Register */
+#define SPRN_TLB1PS    0x159   /* TLB 1 Page Size Register */
 #define SPRN_MAS5_MAS6 0x15c   /* MMU Assist Register 5 || 6 */
 #define SPRN_MAS8_MAS1 0x15d   /* MMU Assist Register 8 || 1 */
 #define SPRN_EPTCFG    0x15e   /* Embedded Page Table Config */
index f9611bd..7124fc0 100644 (file)
@@ -23,7 +23,6 @@
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/hv_call.h>
 #endif
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
@@ -95,12 +94,12 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
  * value.
  */
 
-#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
+#if defined(CONFIG_PPC_SPLPAR)
 /* We only yield to the hypervisor if we are in shared processor mode */
 #define SHARED_PROCESSOR (get_lppaca()->shared_proc)
 extern void __spin_yield(arch_spinlock_t *lock);
 extern void __rw_yield(arch_rwlock_t *lock);
-#else /* SPLPAR || ISERIES */
+#else /* SPLPAR */
 #define __spin_yield(x)        barrier()
 #define __rw_yield(x)  barrier()
 #define SHARED_PROCESSOR       0
index c377457..a02883d 100644 (file)
@@ -550,5 +550,43 @@ extern void reloc_got2(unsigned long);
 
 extern struct dentry *powerpc_debugfs_root;
 
+#ifdef CONFIG_PPC64
+
+extern void __ppc64_runlatch_on(void);
+extern void __ppc64_runlatch_off(void);
+
+/*
+ * We manually hard enable-disable, this is called
+ * in the idle loop and we don't want to mess up
+ * with soft-disable/enable & interrupt replay.
+ */
+#define ppc64_runlatch_off()                                   \
+       do {                                                    \
+               if (cpu_has_feature(CPU_FTR_CTRL) &&            \
+                   test_thread_local_flags(_TLF_RUNLATCH)) {   \
+                       unsigned long msr = mfmsr();            \
+                       __hard_irq_disable();                   \
+                       __ppc64_runlatch_off();                 \
+                       if (msr & MSR_EE)                       \
+                               __hard_irq_enable();            \
+               }                                               \
+       } while (0)
+
+#define ppc64_runlatch_on()                                    \
+       do {                                                    \
+               if (cpu_has_feature(CPU_FTR_CTRL) &&            \
+                   !test_thread_local_flags(_TLF_RUNLATCH)) {  \
+                       unsigned long msr = mfmsr();            \
+                       __hard_irq_disable();                   \
+                       __ppc64_runlatch_on();                  \
+                       if (msr & MSR_EE)                       \
+                               __hard_irq_enable();            \
+               }                                               \
+       } while (0)
+#else
+#define ppc64_runlatch_on()
+#define ppc64_runlatch_off()
+#endif /* CONFIG_PPC64 */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYSTEM_H */
index 9647149..4a741c7 100644 (file)
@@ -110,7 +110,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NOERROR            12      /* Force successful syscall return */
 #define TIF_NOTIFY_RESUME      13      /* callback before returning to user */
 #define TIF_SYSCALL_TRACEPOINT 15      /* syscall tracepoint instrumentation */
-#define TIF_RUNLATCH           16      /* Is the runlatch enabled? */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -141,11 +140,13 @@ static inline struct thread_info *current_thread_info(void)
 #define TLF_SLEEPING           1       /* suspend code enabled SLEEP mode */
 #define TLF_RESTORE_SIGMASK    2       /* Restore signal mask in do_signal */
 #define TLF_LAZY_MMU           3       /* tlb_batch is active */
+#define TLF_RUNLATCH           4       /* Is the runlatch enabled? */
 
 #define _TLF_NAPPING           (1 << TLF_NAPPING)
 #define _TLF_SLEEPING          (1 << TLF_SLEEPING)
 #define _TLF_RESTORE_SIGMASK   (1 << TLF_RESTORE_SIGMASK)
 #define _TLF_LAZY_MMU          (1 << TLF_LAZY_MMU)
+#define _TLF_RUNLATCH          (1 << TLF_RUNLATCH)
 
 #ifndef __ASSEMBLY__
 #define HAVE_SET_RESTORE_SIGMASK       1
@@ -156,6 +157,12 @@ static inline void set_restore_sigmask(void)
        set_bit(TIF_SIGPENDING, &ti->flags);
 }
 
+static inline bool test_thread_local_flags(unsigned int flags)
+{
+       struct thread_info *ti = current_thread_info();
+       return (ti->local_flags & flags) != 0;
+}
+
 #ifdef CONFIG_PPC64
 #define is_32bit_task()        (test_thread_flag(TIF_32BIT))
 #else
index 7eb10fb..2136f58 100644 (file)
 #include <linux/percpu.h>
 
 #include <asm/processor.h>
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/paca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call.h>
-#endif
 
 /* time.c */
 extern unsigned long tb_ticks_per_jiffy;
@@ -166,15 +161,6 @@ static inline void set_dec(int val)
 #else
 #ifndef CONFIG_BOOKE
        --val;
-#endif
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES) &&
-                       get_lppaca()->shared_proc) {
-               get_lppaca()->virtual_decr = val;
-               if (get_dec() > val)
-                       HvCall_setVirtualDecr();
-               return;
-       }
 #endif
        mtspr(SPRN_DEC, val);
 #endif /* not 40x or 8xx_CPU6 */
@@ -217,7 +203,6 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
 #endif
 
 extern void secondary_cpu_time_init(void);
-extern void iSeries_time_init_early(void);
 
 DECLARE_PER_CPU(u64, decrementers_next_tb);
 
index ee728e4..f5808a3 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_IBMVIO)          += vio.o
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)   += smp-tbsync.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+obj-$(CONFIG_FA_DUMP)          += fadump.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)             += idle_e500.o
 endif
@@ -113,15 +114,6 @@ obj-$(CONFIG_PPC_IO_WORKAROUNDS)   += io-workarounds.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
-obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
-
-obj-$(CONFIG_PPC_PERF_CTRS)    += perf_event.o
-obj64-$(CONFIG_PPC_PERF_CTRS)  += power4-pmu.o ppc970-pmu.o power5-pmu.o \
-                                  power5+-pmu.o power6-pmu.o power7-pmu.o
-obj32-$(CONFIG_PPC_PERF_CTRS)  += mpc7450-pmu.o
-
-obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o
-obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
 
 obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
 
index 04caee7..cc492e4 100644 (file)
@@ -46,9 +46,6 @@
 #include <asm/hvcall.h>
 #include <asm/xics.h>
 #endif
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/iseries/alpaca.h>
-#endif
 #ifdef CONFIG_PPC_POWERNV
 #include <asm/opal.h>
 #endif
@@ -147,7 +144,7 @@ int main(void)
        DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
        DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
        DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
-       DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
+       DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened));
        DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
 #ifdef CONFIG_PPC_MM_SLICES
        DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
@@ -384,17 +381,6 @@ int main(void)
        DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-       /* the assembler miscalculates the VSID values */
-       DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET));
-       DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET));
-       DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START));
-       DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START));
-
-       /* alpaca */
-       DEFINE(ALPACA_SIZE, sizeof(struct alpaca));
-#endif
-
        DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
        DEFINE(PTE_SIZE, sizeof(pte_t));
 
index 81db9e2..138ae18 100644 (file)
@@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .platform               = "ppc440",
        },
        { /* 464 in APM821xx */
-               .pvr_mask               = 0xffffff00,
+               .pvr_mask               = 0xfffffff0,
                .pvr_value              = 0x12C41C80,
                .cpu_name               = "APM821XX",
                .cpu_features           = CPU_FTRS_44X,
@@ -2019,6 +2019,24 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_e500mc,
                .platform               = "ppce5500",
        },
+       {       /* e6500 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x80400000,
+               .cpu_name               = "e6500",
+               .cpu_features           = CPU_FTRS_E6500,
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+               .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/e6500",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
+               .cpu_setup              = __setup_cpu_e5500,
+               .cpu_restore            = __restore_cpu_e5500,
+               .machine_check          = machine_check_e500mc,
+               .platform               = "ppce6500",
+       },
 #ifdef CONFIG_PPC32
        {       /* default match */
                .pvr_mask               = 0x00000000,
index 2cc451a..5b25c80 100644 (file)
@@ -37,6 +37,8 @@ void doorbell_exception(struct pt_regs *regs)
 
        irq_enter();
 
+       may_hard_irq_enable();
+
        smp_ipi_demux();
 
        irq_exit();
diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/kernel/e500-pmu.c
deleted file mode 100644 (file)
index cb2e294..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Performance counter support for e500 family processors.
- *
- * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
- * 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/string.h>
-#include <linux/perf_event.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Map of generic hardware event types to hardware events
- * Zero if unsupported
- */
-static int e500_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES] = 1,
-       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
-       [PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
-       [PERF_COUNT_HW_BRANCH_MISSES] = 15,
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int e500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       /*
-        * D-cache misses are not split into read/write/prefetch;
-        * use raw event 41.
-        */
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        27,             0       },
-               [C(OP_WRITE)] = {       28,             0       },
-               [C(OP_PREFETCH)] = {    29,             0       },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        2,              60      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       /*
-        * Assuming LL means L2, it's not a good match for this model.
-        * It allocates only on L1 castout or explicit prefetch, and
-        * does not have separate read/write events (but it does have
-        * separate instruction/data events).
-        */
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       0,              0       },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       /*
-        * There are data/instruction MMU misses, but that's a miss on
-        * the chip's internal level-one TLB which is probably not
-        * what the user wants.  Instead, unified level-two TLB misses
-        * are reported here.
-        */
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        26,             66      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        12,             15      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-};
-
-static int num_events = 128;
-
-/* Upper half of event id is PMLCb, for threshold events */
-static u64 e500_xlate_event(u64 event_id)
-{
-       u32 event_low = (u32)event_id;
-       u64 ret;
-
-       if (event_low >= num_events)
-               return 0;
-
-       ret = FSL_EMB_EVENT_VALID;
-
-       if (event_low >= 76 && event_low <= 81) {
-               ret |= FSL_EMB_EVENT_RESTRICTED;
-               ret |= event_id &
-                      (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH);
-       } else if (event_id &
-                  (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)) {
-               /* Threshold requested on non-threshold event */
-               return 0;
-       }
-
-       return ret;
-}
-
-static struct fsl_emb_pmu e500_pmu = {
-       .name                   = "e500 family",
-       .n_counter              = 4,
-       .n_restricted           = 2,
-       .xlate_event            = e500_xlate_event,
-       .n_generic              = ARRAY_SIZE(e500_generic_events),
-       .generic_events         = e500_generic_events,
-       .cache_events           = &e500_cache_events,
-};
-
-static int init_e500_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type)
-               return -ENODEV;
-
-       if (!strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500mc"))
-               num_events = 256;
-       else if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500"))
-               return -ENODEV;
-
-       return register_fsl_emb_pmu(&e500_pmu);
-}
-
-early_initcall(init_e500_pmu);
index 866462c..f8a7a1a 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/ptrace.h>
 #include <asm/irqflags.h>
 #include <asm/ftrace.h>
+#include <asm/hw_irq.h>
 
 /*
  * System calls.
@@ -115,39 +116,33 @@ BEGIN_FW_FTR_SECTION
 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)
-       REST_4GPRS(3,r1)
-       REST_2GPRS(7,r1)
-       addi    r9,r1,STACK_FRAME_OVERHEAD
-       ld      r12,_MSR(r1)
-#endif /* CONFIG_TRACE_IRQFLAGS */
-       li      r10,1
-       stb     r10,PACASOFTIRQEN(r13)
-       stb     r10,PACAHARDIRQEN(r13)
-       std     r10,SOFTE(r1)
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       /* Hack for handling interrupts when soft-enabling on iSeries */
-       cmpdi   cr1,r0,0x5555           /* syscall 0x5555 */
-       andi.   r10,r12,MSR_PR          /* from kernel */
-       crand   4*cr0+eq,4*cr1+eq,4*cr0+eq
-       bne     2f
-       b       hardware_interrupt_entry
-2:
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
+       /*
+        * A syscall should always be called with interrupts enabled
+        * so we just unconditionally hard-enable here. When some kind
+        * of irq tracing is used, we additionally check that condition
+        * is correct
+        */
+#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_BUG)
+       lbz     r10,PACASOFTIRQEN(r13)
+       xori    r10,r10,1
+1:     tdnei   r10,0
+       EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
+#endif
 
-       /* Hard enable interrupts */
 #ifdef CONFIG_PPC_BOOK3E
        wrteei  1
 #else
-       mfmsr   r11
+       ld      r11,PACAKMSR(r13)
        ori     r11,r11,MSR_EE
        mtmsrd  r11,1
 #endif /* CONFIG_PPC_BOOK3E */
 
+       /* We do need to set SOFTE in the stack frame or the return
+        * from interrupt will be painful
+        */
+       li      r10,1
+       std     r10,SOFTE(r1)
+
 #ifdef SHOW_SYSCALLS
        bl      .do_show_syscall
        REST_GPR(0,r1)
@@ -198,16 +193,14 @@ syscall_exit:
        andi.   r10,r8,MSR_RI
        beq-    unrecov_restore
 #endif
-
-       /* Disable interrupts so current_thread_info()->flags can't change,
+       /*
+        * Disable interrupts so current_thread_info()->flags can't change,
         * and so that we don't get interrupted after loading SRR0/1.
         */
 #ifdef CONFIG_PPC_BOOK3E
        wrteei  0
 #else
-       mfmsr   r10
-       rldicl  r10,r10,48,1
-       rotldi  r10,r10,16
+       ld      r10,PACAKMSR(r13)
        mtmsrd  r10,1
 #endif /* CONFIG_PPC_BOOK3E */
 
@@ -319,7 +312,7 @@ syscall_exit_work:
 #ifdef CONFIG_PPC_BOOK3E
        wrteei  1
 #else
-       mfmsr   r10
+       ld      r10,PACAKMSR(r13)
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1
 #endif /* CONFIG_PPC_BOOK3E */
@@ -565,10 +558,8 @@ _GLOBAL(ret_from_except_lite)
 #ifdef CONFIG_PPC_BOOK3E
        wrteei  0
 #else
-       mfmsr   r10             /* Get current interrupt state */
-       rldicl  r9,r10,48,1     /* clear MSR_EE */
-       rotldi  r9,r9,16
-       mtmsrd  r9,1            /* Update machine state */
+       ld      r10,PACAKMSR(r13) /* Get kernel MSR without EE */
+       mtmsrd  r10,1             /* Update machine state */
 #endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef CONFIG_PREEMPT
@@ -591,25 +582,74 @@ _GLOBAL(ret_from_except_lite)
        ld      r4,TI_FLAGS(r9)
        andi.   r0,r4,_TIF_USER_WORK_MASK
        bne     do_work
-#endif
+#endif /* !CONFIG_PREEMPT */
 
+       .globl  fast_exc_return_irq
+fast_exc_return_irq:
 restore:
-BEGIN_FW_FTR_SECTION
+       /*
+        * This is the main kernel exit path, we first check if we
+        * have to change our interrupt state.
+        */
        ld      r5,SOFTE(r1)
-FW_FTR_SECTION_ELSE
-       b       .Liseries_check_pending_irqs
-ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
-2:
-       TRACE_AND_RESTORE_IRQ(r5);
+       lbz     r6,PACASOFTIRQEN(r13)
+       cmpwi   cr1,r5,0
+       cmpw    cr0,r5,r6
+       beq     cr0,4f
+
+       /* We do, handle disable first, which is easy */
+       bne     cr1,3f;
+       li      r0,0
+       stb     r0,PACASOFTIRQEN(r13);
+       TRACE_DISABLE_INTS
+       b       4f
 
-       /* extract EE bit and use it to restore paca->hard_enabled */
-       ld      r3,_MSR(r1)
-       rldicl  r4,r3,49,63             /* r0 = (r3 >> 15) & 1 */
-       stb     r4,PACAHARDIRQEN(r13)
+3:     /*
+        * We are about to soft-enable interrupts (we are hard disabled
+        * at this point). We check if there's anything that needs to
+        * be replayed first.
+        */
+       lbz     r0,PACAIRQHAPPENED(r13)
+       cmpwi   cr0,r0,0
+       bne-    restore_check_irq_replay
 
+       /*
+        * Get here when nothing happened while soft-disabled, just
+        * soft-enable and move-on. We will hard-enable as a side
+        * effect of rfi
+        */
+restore_no_replay:
+       TRACE_ENABLE_INTS
+       li      r0,1
+       stb     r0,PACASOFTIRQEN(r13);
+
+       /*
+        * Final return path. BookE is handled in a different file
+        */
+4:
 #ifdef CONFIG_PPC_BOOK3E
        b       .exception_return_book3e
 #else
+       /*
+        * 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)
+
+       /*
+        * Some code path such as load_up_fpu or altivec return directly
+        * here. They run entirely hard disabled and do not alter the
+        * interrupt state. They also don't use lwarx/stwcx. and thus
+        * are known not to leave dangling reservations.
+        */
+       .globl  fast_exception_return
+fast_exception_return:
+       ld      r3,_MSR(r1)
        ld      r4,_CTR(r1)
        ld      r0,_LINK(r1)
        mtctr   r4
@@ -622,29 +662,19 @@ 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
         * userspace and we take an exception after restoring r13,
         * we end up corrupting the userspace r13 value.
         */
-       mfmsr   r4
-       andc    r4,r4,r0        /* r0 contains MSR_RI here */
+       ld      r4,PACAKMSR(r13) /* Get kernel MSR without EE */
+       andc    r4,r4,r0         /* r0 contains MSR_RI here */
        mtmsrd  r4,1
 
        /*
         * r13 is our per cpu area, only restore it if we are returning to
-        * userspace
+        * userspace the value stored in the stack frame may belong to
+        * another CPU.
         */
        andi.   r0,r3,MSR_PR
        beq     1f
@@ -669,30 +699,55 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
 
 #endif /* CONFIG_PPC_BOOK3E */
 
-.Liseries_check_pending_irqs:
-#ifdef CONFIG_PPC_ISERIES
-       ld      r5,SOFTE(r1)
-       cmpdi   0,r5,0
-       beq     2b
-       /* Check for pending interrupts (iSeries) */
-       ld      r3,PACALPPACAPTR(r13)
-       ld      r3,LPPACAANYINT(r3)
-       cmpdi   r3,0
-       beq+    2b                      /* skip do_IRQ if no interrupts */
-
-       li      r3,0
-       stb     r3,PACASOFTIRQEN(r13)   /* ensure we are soft-disabled */
-#ifdef CONFIG_TRACE_IRQFLAGS
-       bl      .trace_hardirqs_off
-       mfmsr   r10
-#endif
-       ori     r10,r10,MSR_EE
-       mtmsrd  r10                     /* hard-enable again */
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_IRQ
-       b       .ret_from_except_lite           /* loop back and handle more */
-#endif
+       /*
+        * Something did happen, check if a re-emit is needed
+        * (this also clears paca->irq_happened)
+        */
+restore_check_irq_replay:
+       /* XXX: We could implement a fast path here where we check
+        * for irq_happened being just 0x01, in which case we can
+        * clear it and return. That means that we would potentially
+        * miss a decrementer having wrapped all the way around.
+        *
+        * Still, this might be useful for things like hash_page
+        */
+       bl      .__check_irq_replay
+       cmpwi   cr0,r3,0
+       beq     restore_no_replay
+       /*
+        * We need to re-emit an interrupt. We do so by re-using our
+        * existing exception frame. We first change the trap value,
+        * but we need to ensure we preserve the low nibble of it
+        */
+       ld      r4,_TRAP(r1)
+       clrldi  r4,r4,60
+       or      r4,r4,r3
+       std     r4,_TRAP(r1)
 
+       /*
+        * Then find the right handler and call it. Interrupts are
+        * still soft-disabled and we keep them that way.
+       */
+       cmpwi   cr0,r3,0x500
+       bne     1f
+       addi    r3,r1,STACK_FRAME_OVERHEAD;
+       bl      .do_IRQ
+       b       .ret_from_except
+1:     cmpwi   cr0,r3,0x900
+       bne     1f
+       addi    r3,r1,STACK_FRAME_OVERHEAD;
+       bl      .timer_interrupt
+       b       .ret_from_except
+#ifdef CONFIG_PPC_BOOK3E
+1:     cmpwi   cr0,r3,0x280
+       bne     1f
+       addi    r3,r1,STACK_FRAME_OVERHEAD;
+       bl      .doorbell_exception
+       b       .ret_from_except
+#endif /* CONFIG_PPC_BOOK3E */
+1:     b       .ret_from_except /* What else to do here ? */
 do_work:
 #ifdef CONFIG_PREEMPT
        andi.   r0,r3,MSR_PR    /* Returning to user mode? */
@@ -705,31 +760,22 @@ do_work:
        crandc  eq,cr1*4+eq,eq
        bne     restore
 
-       /* Here we are preempting the current task.
-        *
-        * Ensure interrupts are soft-disabled. We also properly mark
-        * the PACA to reflect the fact that they are hard-disabled
-        * and trace the change
+       /*
+        * Here we are preempting the current task. We want to make
+        * sure we are soft-disabled first
         */
-       li      r0,0
-       stb     r0,PACASOFTIRQEN(r13)
-       stb     r0,PACAHARDIRQEN(r13)
-       TRACE_DISABLE_INTS
-
-       /* Call the scheduler with soft IRQs off */
+       SOFT_DISABLE_INTS(r3,r4)
 1:     bl      .preempt_schedule_irq
 
        /* Hard-disable interrupts again (and update PACA) */
 #ifdef CONFIG_PPC_BOOK3E
        wrteei  0
 #else
-       mfmsr   r10
-       rldicl  r10,r10,48,1
-       rotldi  r10,r10,16
+       ld      r10,PACAKMSR(r13) /* Get kernel MSR without EE */
        mtmsrd  r10,1
 #endif /* CONFIG_PPC_BOOK3E */
-       li      r0,0
-       stb     r0,PACAHARDIRQEN(r13)
+       li      r0,PACA_IRQ_HARD_DIS
+       stb     r0,PACAIRQHAPPENED(r13)
 
        /* Re-test flags and eventually loop */
        clrrdi  r9,r1,THREAD_SHIFT
@@ -751,14 +797,12 @@ user_work:
 
        andi.   r0,r4,_TIF_NEED_RESCHED
        beq     1f
-       li      r5,1
-       TRACE_AND_RESTORE_IRQ(r5);
+       bl      .restore_interrupts
        bl      .schedule
        b       .ret_from_except_lite
 
 1:     bl      .save_nvgprs
-       li      r5,1
-       TRACE_AND_RESTORE_IRQ(r5);
+       bl      .restore_interrupts
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_notify_resume
        b       .ret_from_except
index 429983c..7215cc2 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/ptrace.h>
 #include <asm/ppc-opcode.h>
 #include <asm/mmu.h>
+#include <asm/hw_irq.h>
 
 /* XXX This will ultimately add space for a special exception save
  *     structure used to save things like SRR0/SRR1, SPRGs, MAS, etc...
 #define SPRN_MC_SRR1   SPRN_MCSRR1
 
 #define NORMAL_EXCEPTION_PROLOG(n, addition)                               \
-       EXCEPTION_PROLOG(n, GEN, addition##_GEN)
+       EXCEPTION_PROLOG(n, GEN, addition##_GEN(n))
 
 #define CRIT_EXCEPTION_PROLOG(n, addition)                                 \
-       EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)
+       EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n))
 
 #define DBG_EXCEPTION_PROLOG(n, addition)                                  \
-       EXCEPTION_PROLOG(n, DBG, addition##_DBG)
+       EXCEPTION_PROLOG(n, DBG, addition##_DBG(n))
 
 #define MC_EXCEPTION_PROLOG(n, addition)                                   \
-       EXCEPTION_PROLOG(n, MC, addition##_MC)
+       EXCEPTION_PROLOG(n, MC, addition##_MC(n))
 
 
 /* Variants of the "addition" argument for the prolog
  */
-#define PROLOG_ADDITION_NONE_GEN
-#define PROLOG_ADDITION_NONE_CRIT
-#define PROLOG_ADDITION_NONE_DBG
-#define PROLOG_ADDITION_NONE_MC
+#define PROLOG_ADDITION_NONE_GEN(n)
+#define PROLOG_ADDITION_NONE_CRIT(n)
+#define PROLOG_ADDITION_NONE_DBG(n)
+#define PROLOG_ADDITION_NONE_MC(n)
 
-#define PROLOG_ADDITION_MASKABLE_GEN                                       \
+#define PROLOG_ADDITION_MASKABLE_GEN(n)                                            \
        lbz     r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */      \
        cmpwi   cr0,r11,0;              /* yes -> go out of line */         \
-       beq     masked_interrupt_book3e;
+       beq     masked_interrupt_book3e_##n
 
-#define PROLOG_ADDITION_2REGS_GEN                                          \
+#define PROLOG_ADDITION_2REGS_GEN(n)                                       \
        std     r14,PACA_EXGEN+EX_R14(r13);                                 \
        std     r15,PACA_EXGEN+EX_R15(r13)
 
-#define PROLOG_ADDITION_1REG_GEN                                           \
+#define PROLOG_ADDITION_1REG_GEN(n)                                        \
        std     r14,PACA_EXGEN+EX_R14(r13);
 
-#define PROLOG_ADDITION_2REGS_CRIT                                         \
+#define PROLOG_ADDITION_2REGS_CRIT(n)                                      \
        std     r14,PACA_EXCRIT+EX_R14(r13);                                \
        std     r15,PACA_EXCRIT+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_DBG                                          \
+#define PROLOG_ADDITION_2REGS_DBG(n)                                       \
        std     r14,PACA_EXDBG+EX_R14(r13);                                 \
        std     r15,PACA_EXDBG+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_MC                                           \
+#define PROLOG_ADDITION_2REGS_MC(n)                                        \
        std     r14,PACA_EXMC+EX_R14(r13);                                  \
        std     r15,PACA_EXMC+EX_R15(r13)
 
-#define PROLOG_ADDITION_DOORBELL_GEN                                       \
-       lbz     r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */      \
-       cmpwi   cr0,r11,0;              /* yes -> go out of line */         \
-       beq     masked_doorbell_book3e
-
 
 /* Core exception code for all exceptions except TLB misses.
  * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
  */
 #define EXCEPTION_COMMON(n, excf, ints)                                            \
+exc_##n##_common:                                                          \
        std     r0,GPR0(r1);            /* save r0 in stackframe */         \
        std     r2,GPR2(r1);            /* save r2 in stackframe */         \
        SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe */    \
        std     r0,RESULT(r1);          /* clear regs->result */            \
        ints;
 
-/* Variants for the "ints" argument */
+/* Variants for the "ints" argument. This one does nothing when we want
+ * to keep interrupts in their original state
+ */
 #define INTS_KEEP
-#define INTS_DISABLE_SOFT                                                  \
-       stb     r0,PACASOFTIRQEN(r13);  /* mark interrupts soft-disabled */ \
-       TRACE_DISABLE_INTS;
-#define INTS_DISABLE_HARD                                                  \
-       stb     r0,PACAHARDIRQEN(r13); /* and hard disabled */
-#define INTS_DISABLE_ALL                                                   \
-       INTS_DISABLE_SOFT                                                   \
-       INTS_DISABLE_HARD
-
-/* This is called by exceptions that used INTS_KEEP (that is did not clear
- * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE
- * to it's previous value
+
+/* This second version is meant for exceptions that don't immediately
+ * hard-enable. We set a bit in paca->irq_happened to ensure that
+ * a subsequent call to arch_local_irq_restore() will properly
+ * hard-enable and avoid the fast-path
+ */
+#define INTS_DISABLE   SOFT_DISABLE_INTS(r3,r4)
+
+/* This is called by exceptions that used INTS_KEEP (that did not touch
+ * irq indicators in the PACA). This will restore MSR:EE to it's previous
+ * value
  *
  * XXX In the long run, we may want to open-code it in order to separate the
  *     load from the wrtee, thus limiting the latency caused by the dependency
@@ -238,7 +236,7 @@ exc_##n##_bad_stack:                                                            \
 #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack)                  \
        START_EXCEPTION(label);                                         \
        NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE)      \
-       EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL)         \
+       EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE)             \
        ack(r8);                                                        \
        CHECK_NAPPING();                                                \
        addi    r3,r1,STACK_FRAME_OVERHEAD;                             \
@@ -289,7 +287,7 @@ interrupt_end_book3e:
 /* Critical Input Interrupt */
        START_EXCEPTION(critical_input);
        CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
-//     EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
+//     EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE)
 //     bl      special_reg_save_crit
 //     CHECK_NAPPING();
 //     addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -300,7 +298,7 @@ interrupt_end_book3e:
 /* Machine Check Interrupt */
        START_EXCEPTION(machine_check);
        CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)
-//     EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
+//     EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE)
 //     bl      special_reg_save_mc
 //     addi    r3,r1,STACK_FRAME_OVERHEAD
 //     CHECK_NAPPING();
@@ -313,7 +311,7 @@ interrupt_end_book3e:
        NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS)
        mfspr   r14,SPRN_DEAR
        mfspr   r15,SPRN_ESR
-       EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP)
+       EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE)
        b       storage_fault_common
 
 /* Instruction Storage Interrupt */
@@ -321,7 +319,7 @@ interrupt_end_book3e:
        NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS)
        li      r15,0
        mr      r14,r10
-       EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP)
+       EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE)
        b       storage_fault_common
 
 /* External Input Interrupt */
@@ -339,12 +337,11 @@ interrupt_end_book3e:
        START_EXCEPTION(program);
        NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)
        mfspr   r14,SPRN_ESR
-       EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)
+       EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE)
        std     r14,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r14,PACA_EXGEN+EX_R14(r13)
        bl      .save_nvgprs
-       INTS_RESTORE_HARD
        bl      .program_check_exception
        b       .ret_from_except
 
@@ -353,15 +350,16 @@ interrupt_end_book3e:
        NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE)
        /* we can probably do a shorter exception entry for that one... */
        EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
-       bne     1f                      /* if from user, just load it up */
+       ld      r12,_MSR(r1)
+       andi.   r0,r12,MSR_PR;
+       beq-    1f
+       bl      .load_up_fpu
+       b       fast_exception_return
+1:     INTS_DISABLE
        bl      .save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       INTS_RESTORE_HARD
        bl      .kernel_fp_unavailable_exception
-       BUG_OPCODE
-1:     ld      r12,_MSR(r1)
-       bl      .load_up_fpu
-       b       fast_exception_return
+       b       .ret_from_except
 
 /* Decrementer Interrupt */
        MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC)
@@ -372,7 +370,7 @@ interrupt_end_book3e:
 /* Watchdog Timer Interrupt */
        START_EXCEPTION(watchdog);
        CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
-//     EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
+//     EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE)
 //     bl      special_reg_save_crit
 //     CHECK_NAPPING();
 //     addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -391,10 +389,9 @@ interrupt_end_book3e:
 /* Auxiliary Processor Unavailable Interrupt */
        START_EXCEPTION(ap_unavailable);
        NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE)
-       EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE)
        bl      .save_nvgprs
-       INTS_RESTORE_HARD
+       addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .unknown_exception
        b       .ret_from_except
 
@@ -450,7 +447,7 @@ interrupt_end_book3e:
        mfspr   r15,SPRN_SPRG_CRIT_SCRATCH
        mtspr   SPRN_SPRG_GEN_SCRATCH,r15
        mfspr   r14,SPRN_DBSR
-       EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)
+       EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE)
        std     r14,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
        mr      r4,r14
@@ -465,7 +462,7 @@ kernel_dbg_exc:
 
 /* Debug exception as a debug interrupt*/
        START_EXCEPTION(debug_debug);
-       DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+       DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS)
 
        /*
         * If there is a single step or branch-taken exception in an
@@ -515,7 +512,7 @@ kernel_dbg_exc:
        mfspr   r15,SPRN_SPRG_DBG_SCRATCH
        mtspr   SPRN_SPRG_GEN_SCRATCH,r15
        mfspr   r14,SPRN_DBSR
-       EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)
+       EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE)
        std     r14,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
        mr      r4,r14
@@ -525,21 +522,20 @@ kernel_dbg_exc:
        bl      .DebugException
        b       .ret_from_except
 
-       MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE)
-
-/* Doorbell interrupt */
-       START_EXCEPTION(doorbell)
-       NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL)
-       EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL)
-       CHECK_NAPPING()
+       START_EXCEPTION(perfmon);
+       NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE)
+       EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE)
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .doorbell_exception
+       bl      .performance_monitor_exception
        b       .ret_from_except_lite
 
+/* Doorbell interrupt */
+       MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE)
+
 /* Doorbell critical Interrupt */
        START_EXCEPTION(doorbell_crit);
-       CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
-//     EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
+       CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE)
+//     EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE)
 //     bl      special_reg_save_crit
 //     CHECK_NAPPING();
 //     addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -547,36 +543,114 @@ kernel_dbg_exc:
 //     b       ret_from_crit_except
        b       .
 
+/* Guest Doorbell */
        MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE)
-       MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE)
-       MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE)
-       MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE)
 
+/* Guest Doorbell critical Interrupt */
+       START_EXCEPTION(guest_doorbell_crit);
+       CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE)
+//     EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE)
+//     bl      special_reg_save_crit
+//     CHECK_NAPPING();
+//     addi    r3,r1,STACK_FRAME_OVERHEAD
+//     bl      .guest_doorbell_critical_exception
+//     b       ret_from_crit_except
+       b       .
+
+/* Hypervisor call */
+       START_EXCEPTION(hypercall);
+       NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE)
+       EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .unknown_exception
+       b       .ret_from_except
+
+/* Embedded Hypervisor priviledged  */
+       START_EXCEPTION(ehpriv);
+       NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE)
+       EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .unknown_exception
+       b       .ret_from_except
 
 /*
- * An interrupt came in while soft-disabled; clear EE in SRR1,
- * clear paca->hard_enabled and return.
+ * An interrupt came in while soft-disabled; We mark paca->irq_happened
+ * accordingly and if the interrupt is level sensitive, we hard disable
  */
-masked_doorbell_book3e:
-       mtcr    r10
-       /* Resend the doorbell to fire again when ints enabled */
-       mfspr   r10,SPRN_PIR
-       PPC_MSGSND(r10)
-       b       masked_interrupt_book3e_common
 
-masked_interrupt_book3e:
+masked_interrupt_book3e_0x500:
+       /* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */
+       li      r11,PACA_IRQ_EE
+       b       masked_interrupt_book3e_full_mask
+
+masked_interrupt_book3e_0x900:
+       ACK_DEC(r11);
+       li      r11,PACA_IRQ_DEC
+       b       masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x980:
+       ACK_FIT(r11);
+       li      r11,PACA_IRQ_DEC
+       b       masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x280:
+masked_interrupt_book3e_0x2c0:
+       li      r11,PACA_IRQ_DBELL
+       b       masked_interrupt_book3e_no_mask
+
+masked_interrupt_book3e_no_mask:
+       mtcr    r10
+       lbz     r10,PACAIRQHAPPENED(r13)
+       or      r10,r10,r11
+       stb     r10,PACAIRQHAPPENED(r13)
+       b       1f
+masked_interrupt_book3e_full_mask:
        mtcr    r10
-masked_interrupt_book3e_common:
-       stb     r11,PACAHARDIRQEN(r13)
+       lbz     r10,PACAIRQHAPPENED(r13)
+       or      r10,r10,r11
+       stb     r10,PACAIRQHAPPENED(r13)
        mfspr   r10,SPRN_SRR1
        rldicl  r11,r10,48,1            /* clear MSR_EE */
        rotldi  r10,r11,16
        mtspr   SPRN_SRR1,r10
-       ld      r10,PACA_EXGEN+EX_R10(r13);     /* restore registers */
+1:     ld      r10,PACA_EXGEN+EX_R10(r13);
        ld      r11,PACA_EXGEN+EX_R11(r13);
        mfspr   r13,SPRN_SPRG_GEN_SCRATCH;
        rfi
        b       .
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280
+ * to indicate the kind of interrupt. MSR:EE is already off.
+ * We generate a stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+       /* We are going to jump to the exception common code which
+        * will retrieve various register values from the PACA which
+        * we don't give a damn about.
+        */
+       mflr    r10
+       mfmsr   r11
+       mfcr    r4
+       mtspr   SPRN_SPRG_GEN_SCRATCH,r13;
+       std     r1,PACA_EXGEN+EX_R1(r13);
+       stw     r4,PACA_EXGEN+EX_CR(r13);
+       ori     r11,r11,MSR_EE
+       subi    r1,r1,INT_FRAME_SIZE;
+       cmpwi   cr0,r3,0x500
+       beq     exc_0x500_common
+       cmpwi   cr0,r3,0x900
+       beq     exc_0x900_common
+       cmpwi   cr0,r3,0x280
+       beq     exc_0x280_common
+       blr
+
 
 /*
  * This is called from 0x300 and 0x400 handlers after the prologs with
@@ -591,7 +665,6 @@ storage_fault_common:
        mr      r5,r15
        ld      r14,PACA_EXGEN+EX_R14(r13)
        ld      r15,PACA_EXGEN+EX_R15(r13)
-       INTS_RESTORE_HARD
        bl      .do_page_fault
        cmpdi   r3,0
        bne-    1f
@@ -680,6 +753,8 @@ BAD_STACK_TRAMPOLINE(0x000)
 BAD_STACK_TRAMPOLINE(0x100)
 BAD_STACK_TRAMPOLINE(0x200)
 BAD_STACK_TRAMPOLINE(0x260)
+BAD_STACK_TRAMPOLINE(0x280)
+BAD_STACK_TRAMPOLINE(0x2a0)
 BAD_STACK_TRAMPOLINE(0x2c0)
 BAD_STACK_TRAMPOLINE(0x2e0)
 BAD_STACK_TRAMPOLINE(0x300)
@@ -697,11 +772,10 @@ BAD_STACK_TRAMPOLINE(0xa00)
 BAD_STACK_TRAMPOLINE(0xb00)
 BAD_STACK_TRAMPOLINE(0xc00)
 BAD_STACK_TRAMPOLINE(0xd00)
+BAD_STACK_TRAMPOLINE(0xd08)
 BAD_STACK_TRAMPOLINE(0xe00)
 BAD_STACK_TRAMPOLINE(0xf00)
 BAD_STACK_TRAMPOLINE(0xf20)
-BAD_STACK_TRAMPOLINE(0x2070)
-BAD_STACK_TRAMPOLINE(0x2080)
 
        .globl  bad_stack_book3e
 bad_stack_book3e:
index 15c5a4f..2d0868a 100644 (file)
@@ -12,6 +12,7 @@
  *
  */
 
+#include <asm/hw_irq.h>
 #include <asm/exception-64s.h>
 #include <asm/ptrace.h>
 
@@ -19,7 +20,7 @@
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs
+ * 0x3000 - 0x5fff : interrupt support common interrupt prologs
  * 0x6000 - 0x6fff : Initial (CPU0) segment table
  * 0x7000 - 0x7fff : FWNMI data area
  * 0x8000 -        : Early init and support code
@@ -356,34 +357,60 @@ do_stab_bolted_pSeries:
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
 
 /*
- * An interrupt came in while soft-disabled; clear EE in SRR1,
- * clear paca->hard_enabled and return.
+ * An interrupt came in while soft-disabled. We set paca->irq_happened,
+ * then, if it was a decrementer interrupt, we bump the dec to max and
+ * and return, else we hard disable and return. This is called with
+ * r10 containing the value to OR to the paca field.
  */
-masked_interrupt:
-       stb     r10,PACAHARDIRQEN(r13)
-       mtcrf   0x80,r9
-       ld      r9,PACA_EXGEN+EX_R9(r13)
-       mfspr   r10,SPRN_SRR1
-       rldicl  r10,r10,48,1            /* clear MSR_EE */
-       rotldi  r10,r10,16
-       mtspr   SPRN_SRR1,r10
-       ld      r10,PACA_EXGEN+EX_R10(r13)
-       GET_SCRATCH0(r13)
-       rfid
+#define MASKED_INTERRUPT(_H)                           \
+masked_##_H##interrupt:                                        \
+       std     r11,PACA_EXGEN+EX_R11(r13);             \
+       lbz     r11,PACAIRQHAPPENED(r13);               \
+       or      r11,r11,r10;                            \
+       stb     r11,PACAIRQHAPPENED(r13);               \
+       andi.   r10,r10,PACA_IRQ_DEC;                   \
+       beq     1f;                                     \
+       lis     r10,0x7fff;                             \
+       ori     r10,r10,0xffff;                         \
+       mtspr   SPRN_DEC,r10;                           \
+       b       2f;                                     \
+1:     mfspr   r10,SPRN_##_H##SRR1;                    \
+       rldicl  r10,r10,48,1; /* clear MSR_EE */        \
+       rotldi  r10,r10,16;                             \
+       mtspr   SPRN_##_H##SRR1,r10;                    \
+2:     mtcrf   0x80,r9;                                \
+       ld      r9,PACA_EXGEN+EX_R9(r13);               \
+       ld      r10,PACA_EXGEN+EX_R10(r13);             \
+       ld      r11,PACA_EXGEN+EX_R11(r13);             \
+       GET_SCRATCH0(r13);                              \
+       ##_H##rfid;                                     \
        b       .
+       
+       MASKED_INTERRUPT()
+       MASKED_INTERRUPT(H)
 
-masked_Hinterrupt:
-       stb     r10,PACAHARDIRQEN(r13)
-       mtcrf   0x80,r9
-       ld      r9,PACA_EXGEN+EX_R9(r13)
-       mfspr   r10,SPRN_HSRR1
-       rldicl  r10,r10,48,1            /* clear MSR_EE */
-       rotldi  r10,r10,16
-       mtspr   SPRN_HSRR1,r10
-       ld      r10,PACA_EXGEN+EX_R10(r13)
-       GET_SCRATCH0(r13)
-       hrfid
-       b       .
+/*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains 0x500 or 0x900 to indicate which
+ * kind of interrupt. MSR:EE is already off. We generate a
+ * stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__replay_interrupt)
+       /* We are going to jump to the exception common code which
+        * will retrieve various register values from the PACA which
+        * we don't give a damn about, so we don't bother storing them.
+        */
+       mfmsr   r12
+       mflr    r11
+       mfcr    r9
+       ori     r12,r12,MSR_EE
+       andi.   r3,r3,0x0800
+       bne     decrementer_common
+       b       hardware_interrupt_common
 
 #ifdef CONFIG_PPC_PSERIES
 /*
@@ -458,14 +485,15 @@ machine_check_common:
        bl      .machine_check_exception
        b       .ret_from_except
 
-       STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt)
+       STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
+       STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
        STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception)
        STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
        STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
        STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
         STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
         STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
-       STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception)
+       STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
        STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
 #ifdef CONFIG_ALTIVEC
        STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception)
@@ -482,6 +510,9 @@ machine_check_common:
 system_call_entry:
        b       system_call_common
 
+ppc64_runlatch_on_trampoline:
+       b       .__ppc64_runlatch_on
+
 /*
  * Here we have detected that the kernel stack pointer is bad.
  * R9 contains the saved CR, r13 points to the paca,
@@ -555,6 +586,8 @@ data_access_common:
        mfspr   r10,SPRN_DSISR
        stw     r10,PACA_EXGEN+EX_DSISR(r13)
        EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
+       DISABLE_INTS
+       ld      r12,_MSR(r1)
        ld      r3,PACA_EXGEN+EX_DAR(r13)
        lwz     r4,PACA_EXGEN+EX_DSISR(r13)
        li      r5,0x300
@@ -569,6 +602,7 @@ h_data_storage_common:
         stw     r10,PACA_EXGEN+EX_DSISR(r13)
         EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
         bl      .save_nvgprs
+       DISABLE_INTS
         addi    r3,r1,STACK_FRAME_OVERHEAD
         bl      .unknown_exception
         b       .ret_from_except
@@ -577,6 +611,8 @@ h_data_storage_common:
        .globl instruction_access_common
 instruction_access_common:
        EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
+       DISABLE_INTS
+       ld      r12,_MSR(r1)
        ld      r3,_NIP(r1)
        andis.  r4,r12,0x5820
        li      r5,0x400
@@ -672,12 +708,6 @@ _GLOBAL(slb_miss_realmode)
        ld      r10,PACA_EXSLB+EX_LR(r13)
        ld      r3,PACA_EXSLB+EX_R3(r13)
        lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       ld      r11,PACALPPACAPTR(r13)
-       ld      r11,LPPACASRR0(r11)             /* get SRR0 value */
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
 
        mtlr    r10
 
@@ -690,12 +720,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
        mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
 .machine       pop
 
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       mtspr   SPRN_SRR0,r11
-       mtspr   SPRN_SRR1,r12
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
        ld      r9,PACA_EXSLB+EX_R9(r13)
        ld      r10,PACA_EXSLB+EX_R10(r13)
        ld      r11,PACA_EXSLB+EX_R11(r13)
@@ -704,13 +728,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
        rfid
        b       .       /* prevent speculative execution */
 
-2:
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       b       unrecov_slb
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
-       mfspr   r11,SPRN_SRR0
+2:     mfspr   r11,SPRN_SRR0
        ld      r10,PACAKBASE(r13)
        LOAD_HANDLER(r10,unrecov_slb)
        mtspr   SPRN_SRR0,r10
@@ -727,20 +745,6 @@ unrecov_slb:
        bl      .unrecoverable_exception
        b       1b
 
-       .align  7
-       .globl hardware_interrupt_common
-       .globl hardware_interrupt_entry
-hardware_interrupt_common:
-       EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN)
-       FINISH_NAP
-hardware_interrupt_entry:
-       DISABLE_INTS
-BEGIN_FTR_SECTION
-       bl      .ppc64_runlatch_on
-END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_IRQ
-       b       .ret_from_except_lite
 
 #ifdef CONFIG_PPC_970_NAP
 power4_fixup_nap:
@@ -785,8 +789,8 @@ fp_unavailable_common:
        EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
        bne     1f                      /* if from user, just load it up */
        bl      .save_nvgprs
+       DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       ENABLE_INTS
        bl      .kernel_fp_unavailable_exception
        BUG_OPCODE
 1:     bl      .load_up_fpu
@@ -805,8 +809,8 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        bl      .save_nvgprs
+       DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       ENABLE_INTS
        bl      .altivec_unavailable_exception
        b       .ret_from_except
 
@@ -816,13 +820,14 @@ vsx_unavailable_common:
        EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
 #ifdef CONFIG_VSX
 BEGIN_FTR_SECTION
-       bne     .load_up_vsx
+       beq     1f
+       b       .load_up_vsx
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
        bl      .save_nvgprs
+       DISABLE_INTS
        addi    r3,r1,STACK_FRAME_OVERHEAD
-       ENABLE_INTS
        bl      .vsx_unavailable_exception
        b       .ret_from_except
 
@@ -830,66 +835,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        .globl  __end_handlers
 __end_handlers:
 
-/*
- * Return from an exception with minimal checks.
- * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
- * If interrupts have been enabled, or anything has been
- * done that might have changed the scheduling status of
- * any task or sent any task a signal, you should use
- * ret_from_except or ret_from_except_lite instead of this.
- */
-fast_exc_return_irq:                   /* restores irq state too */
-       ld      r3,SOFTE(r1)
-       TRACE_AND_RESTORE_IRQ(r3);
-       ld      r12,_MSR(r1)
-       rldicl  r4,r12,49,63            /* get MSR_EE to LSB */
-       stb     r4,PACAHARDIRQEN(r13)   /* restore paca->hard_enabled */
-       b       1f
-
-       .globl  fast_exception_return
-fast_exception_return:
-       ld      r12,_MSR(r1)
-1:     ld      r11,_NIP(r1)
-       andi.   r3,r12,MSR_RI           /* check if RI is set */
-       beq-    unrecov_fer
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       andi.   r3,r12,MSR_PR
-       beq     2f
-       ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
-#endif
-
-       ld      r3,_CCR(r1)
-       ld      r4,_LINK(r1)
-       ld      r5,_CTR(r1)
-       ld      r6,_XER(r1)
-       mtcr    r3
-       mtlr    r4
-       mtctr   r5
-       mtxer   r6
-       REST_GPR(0, r1)
-       REST_8GPRS(2, r1)
-
-       mfmsr   r10
-       rldicl  r10,r10,48,1            /* clear EE */
-       rldicr  r10,r10,16,61           /* clear RI (LE is 0 already) */
-       mtmsrd  r10,1
-
-       mtspr   SPRN_SRR1,r12
-       mtspr   SPRN_SRR0,r11
-       REST_4GPRS(10, r1)
-       ld      r1,GPR1(r1)
-       rfid
-       b       .       /* prevent speculative execution */
-
-unrecov_fer:
-       bl      .save_nvgprs
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
-       b       1b
-
-
 /*
  * Hash table stuff
  */
@@ -912,28 +857,6 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
        lwz     r0,TI_PREEMPT(r11)      /* If we're in an "NMI" */
        andis.  r0,r0,NMI_MASK@h        /* (i.e. an irq when soft-disabled) */
        bne     77f                     /* then don't call hash_page now */
-
-       /*
-        * On iSeries, we soft-disable interrupts here, then
-        * hard-enable interrupts so that the hash_page code can spin on
-        * the hash_table_lock without problems on a shared processor.
-        */
-       DISABLE_INTS
-
-       /*
-        * Currently, trace_hardirqs_off() will be called by DISABLE_INTS
-        * and will clobber volatile registers when irq tracing is enabled
-        * so we need to reload them. It may be possible to be smarter here
-        * and move the irq tracing elsewhere but let's keep it simple for
-        * now
-        */
-#ifdef CONFIG_TRACE_IRQFLAGS
-       ld      r3,_DAR(r1)
-       ld      r4,_DSISR(r1)
-       ld      r5,_TRAP(r1)
-       ld      r12,_MSR(r1)
-       clrrdi  r5,r5,4
-#endif /* CONFIG_TRACE_IRQFLAGS */
        /*
         * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
         * accessing a userspace segment (even from the kernel). We assume
@@ -951,62 +874,25 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
         * r4 contains the required access permissions
         * r5 contains the trap number
         *
-        * at return r3 = 0 for success
+        * at return r3 = 0 for success, 1 for page fault, negative for error
         */
        bl      .hash_page              /* build HPTE if possible */
        cmpdi   r3,0                    /* see if hash_page succeeded */
 
-BEGIN_FW_FTR_SECTION
-       /*
-        * If we had interrupts soft-enabled at the point where the
-        * DSI/ISI occurred, and an interrupt came in during hash_page,
-        * handle it now.
-        * We jump to ret_from_except_lite rather than fast_exception_return
-        * because ret_from_except_lite will check for and handle pending
-        * interrupts if necessary.
-        */
-       beq     13f
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-
-BEGIN_FW_FTR_SECTION
-       /*
-        * Here we have interrupts hard-disabled, so it is sufficient
-        * to restore paca->{soft,hard}_enable and get out.
-        */
+       /* Success */
        beq     fast_exc_return_irq     /* Return from exception on success */
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
-
-       /* For a hash failure, we don't bother re-enabling interrupts */
-       ble-    12f
-
-       /*
-        * hash_page couldn't handle it, set soft interrupt enable back
-        * 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      .arch_local_irq_restore
-       b       11f
 
-/* We have a data breakpoint exception - handle it */
-handle_dabr_fault:
-       bl      .save_nvgprs
-       ld      r4,_DAR(r1)
-       ld      r5,_DSISR(r1)
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .do_dabr
-       b       .ret_from_except_lite
+       /* Error */
+       blt-    13f
 
 /* Here we have a page fault that hash_page can't handle. */
 handle_page_fault:
-       ENABLE_INTS
 11:    ld      r4,_DAR(r1)
        ld      r5,_DSISR(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_page_fault
        cmpdi   r3,0
-       beq+    13f
+       beq+    12f
        bl      .save_nvgprs
        mr      r5,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -1014,12 +900,20 @@ handle_page_fault:
        bl      .bad_page_fault
        b       .ret_from_except
 
-13:    b       .ret_from_except_lite
+/* We have a data breakpoint exception - handle it */
+handle_dabr_fault:
+       bl      .save_nvgprs
+       ld      r4,_DAR(r1)
+       ld      r5,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .do_dabr
+12:    b       .ret_from_except_lite
+
 
 /* We have a page fault that hash_page could handle but HV refused
  * the PTE insertion
  */
-12:    bl      .save_nvgprs
+13:    bl      .save_nvgprs
        mr      r5,r3
        addi    r3,r1,STACK_FRAME_OVERHEAD
        ld      r4,_DAR(r1)
@@ -1141,51 +1035,19 @@ _GLOBAL(do_stab_bolted)
        .= 0x7000
        .globl fwnmi_data_area
 fwnmi_data_area:
-#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
-       /* iSeries does not use the FWNMI stuff, so it is safe to put
-        * this here, even if we later allow kernels that will boot on
-        * both pSeries and iSeries */
-#ifdef CONFIG_PPC_ISERIES
-        . = LPARMAP_PHYS
-       .globl xLparMap
-xLparMap:
-       .quad   HvEsidsToMap            /* xNumberEsids */
-       .quad   HvRangesToMap           /* xNumberRanges */
-       .quad   STAB0_PAGE              /* xSegmentTableOffs */
-       .zero   40                      /* xRsvd */
-       /* xEsids (HvEsidsToMap entries of 2 quads) */
-       .quad   PAGE_OFFSET_ESID        /* xKernelEsid */
-       .quad   PAGE_OFFSET_VSID        /* xKernelVsid */
-       .quad   VMALLOC_START_ESID      /* xKernelEsid */
-       .quad   VMALLOC_START_VSID      /* xKernelVsid */
-       /* xRanges (HvRangesToMap entries of 3 quads) */
-       .quad   HvPagesToMap            /* xPages */
-       .quad   0                       /* xOffset */
-       .quad   PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT) /* xVPN */
-
-#endif /* CONFIG_PPC_ISERIES */
-
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
        /* pseries and powernv need to keep the whole page from
         * 0x7000 to 0x8000 free for use by the firmware
         */
         . = 0x8000
 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
-/*
- * Space for CPU0's segment table.
- *
- * On iSeries, the hypervisor must fill in at least one entry before
- * we get control (with relocate on).  The address is given to the hv
- * as a page number (see xLparMap above), so this must be at a
- * fixed address (the linker can't compute (u64)&initial_stab >>
- * PAGE_SHIFT).
- */
-       . = STAB0_OFFSET        /* 0x8000 */
+/* Space for CPU0's segment table */
+       .balign 4096
        .globl initial_stab
 initial_stab:
        .space  4096
+
 #ifdef CONFIG_PPC_POWERNV
 _GLOBAL(opal_mc_secondary_handler)
        HMT_MEDIUM
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
new file mode 100644 (file)
index 0000000..cfe7a38
--- /dev/null
@@ -0,0 +1,1315 @@
+/*
+ * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
+ * dump with assistance from firmware. This approach does not use kexec,
+ * instead firmware assists in booting the kdump kernel while preserving
+ * memory contents. The most of the code implementation has been adapted
+ * from phyp assisted dump implementation written by Linas Vepstas and
+ * Manish Ahuja
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "fadump: " fmt
+
+#include <linux/string.h>
+#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/crash_dump.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/fadump.h>
+
+static struct fw_dump fw_dump;
+static struct fadump_mem_struct fdm;
+static const struct fadump_mem_struct *fdm_active;
+
+static DEFINE_MUTEX(fadump_mutex);
+struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES];
+int crash_mem_ranges;
+
+/* Scan the Firmware Assisted dump configuration details. */
+int __init early_init_dt_scan_fw_dump(unsigned long node,
+                       const char *uname, int depth, void *data)
+{
+       __be32 *sections;
+       int i, num_sections;
+       unsigned long size;
+       const int *token;
+
+       if (depth != 1 || strcmp(uname, "rtas") != 0)
+               return 0;
+
+       /*
+        * Check if Firmware Assisted dump is supported. if yes, check
+        * if dump has been initiated on last reboot.
+        */
+       token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
+       if (!token)
+               return 0;
+
+       fw_dump.fadump_supported = 1;
+       fw_dump.ibm_configure_kernel_dump = *token;
+
+       /*
+        * The 'ibm,kernel-dump' rtas node is present only if there is
+        * dump data waiting for us.
+        */
+       fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL);
+       if (fdm_active)
+               fw_dump.dump_active = 1;
+
+       /* Get the sizes required to store dump data for the firmware provided
+        * dump sections.
+        * For each dump section type supported, a 32bit cell which defines
+        * the ID of a supported section followed by two 32 bit cells which
+        * gives teh size of the section in bytes.
+        */
+       sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
+                                       &size);
+
+       if (!sections)
+               return 0;
+
+       num_sections = size / (3 * sizeof(u32));
+
+       for (i = 0; i < num_sections; i++, sections += 3) {
+               u32 type = (u32)of_read_number(sections, 1);
+
+               switch (type) {
+               case FADUMP_CPU_STATE_DATA:
+                       fw_dump.cpu_state_data_size =
+                                       of_read_ulong(&sections[1], 2);
+                       break;
+               case FADUMP_HPTE_REGION:
+                       fw_dump.hpte_region_size =
+                                       of_read_ulong(&sections[1], 2);
+                       break;
+               }
+       }
+       return 1;
+}
+
+int is_fadump_active(void)
+{
+       return fw_dump.dump_active;
+}
+
+/* Print firmware assisted dump configurations for debugging purpose. */
+static void fadump_show_config(void)
+{
+       pr_debug("Support for firmware-assisted dump (fadump): %s\n",
+                       (fw_dump.fadump_supported ? "present" : "no support"));
+
+       if (!fw_dump.fadump_supported)
+               return;
+
+       pr_debug("Fadump enabled    : %s\n",
+                               (fw_dump.fadump_enabled ? "yes" : "no"));
+       pr_debug("Dump Active       : %s\n",
+                               (fw_dump.dump_active ? "yes" : "no"));
+       pr_debug("Dump section sizes:\n");
+       pr_debug("    CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
+       pr_debug("    HPTE region size   : %lx\n", fw_dump.hpte_region_size);
+       pr_debug("Boot memory size  : %lx\n", fw_dump.boot_memory_size);
+}
+
+static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
+                               unsigned long addr)
+{
+       if (!fdm)
+               return 0;
+
+       memset(fdm, 0, sizeof(struct fadump_mem_struct));
+       addr = addr & PAGE_MASK;
+
+       fdm->header.dump_format_version = 0x00000001;
+       fdm->header.dump_num_sections = 3;
+       fdm->header.dump_status_flag = 0;
+       fdm->header.offset_first_dump_section =
+               (u32)offsetof(struct fadump_mem_struct, cpu_state_data);
+
+       /*
+        * Fields for disk dump option.
+        * We are not using disk dump option, hence set these fields to 0.
+        */
+       fdm->header.dd_block_size = 0;
+       fdm->header.dd_block_offset = 0;
+       fdm->header.dd_num_blocks = 0;
+       fdm->header.dd_offset_disk_path = 0;
+
+       /* set 0 to disable an automatic dump-reboot. */
+       fdm->header.max_time_auto = 0;
+
+       /* Kernel dump sections */
+       /* cpu state data section. */
+       fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG;
+       fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA;
+       fdm->cpu_state_data.source_address = 0;
+       fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size;
+       fdm->cpu_state_data.destination_address = addr;
+       addr += fw_dump.cpu_state_data_size;
+
+       /* hpte region section */
+       fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG;
+       fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION;
+       fdm->hpte_region.source_address = 0;
+       fdm->hpte_region.source_len = fw_dump.hpte_region_size;
+       fdm->hpte_region.destination_address = addr;
+       addr += fw_dump.hpte_region_size;
+
+       /* RMA region section */
+       fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG;
+       fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION;
+       fdm->rmr_region.source_address = RMA_START;
+       fdm->rmr_region.source_len = fw_dump.boot_memory_size;
+       fdm->rmr_region.destination_address = addr;
+       addr += fw_dump.boot_memory_size;
+
+       return addr;
+}
+
+/**
+ * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
+ *
+ * Function to find the largest memory size we need to reserve during early
+ * boot process. This will be the size of the memory that is required for a
+ * kernel to boot successfully.
+ *
+ * This function has been taken from phyp-assisted dump feature implementation.
+ *
+ * returns larger of 256MB or 5% rounded down to multiples of 256MB.
+ *
+ * TODO: Come up with better approach to find out more accurate memory size
+ * that is required for a kernel to boot successfully.
+ *
+ */
+static inline unsigned long fadump_calculate_reserve_size(void)
+{
+       unsigned long size;
+
+       /*
+        * Check if the size is specified through fadump_reserve_mem= cmdline
+        * option. If yes, then use that.
+        */
+       if (fw_dump.reserve_bootvar)
+               return fw_dump.reserve_bootvar;
+
+       /* divide by 20 to get 5% of value */
+       size = memblock_end_of_DRAM() / 20;
+
+       /* round it down in multiples of 256 */
+       size = size & ~0x0FFFFFFFUL;
+
+       /* Truncate to memory_limit. We don't want to over reserve the memory.*/
+       if (memory_limit && size > memory_limit)
+               size = memory_limit;
+
+       return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
+}
+
+/*
+ * Calculate the total memory size required to be reserved for
+ * firmware-assisted dump registration.
+ */
+static unsigned long get_fadump_area_size(void)
+{
+       unsigned long size = 0;
+
+       size += fw_dump.cpu_state_data_size;
+       size += fw_dump.hpte_region_size;
+       size += fw_dump.boot_memory_size;
+       size += sizeof(struct fadump_crash_info_header);
+       size += sizeof(struct elfhdr); /* ELF core header.*/
+       size += sizeof(struct elf_phdr); /* place holder for cpu notes */
+       /* Program headers for crash memory regions. */
+       size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
+
+       size = PAGE_ALIGN(size);
+       return size;
+}
+
+int __init fadump_reserve_mem(void)
+{
+       unsigned long base, size, memory_boundary;
+
+       if (!fw_dump.fadump_enabled)
+               return 0;
+
+       if (!fw_dump.fadump_supported) {
+               printk(KERN_INFO "Firmware-assisted dump is not supported on"
+                               " this hardware\n");
+               fw_dump.fadump_enabled = 0;
+               return 0;
+       }
+       /*
+        * Initialize boot memory size
+        * If dump is active then we have already calculated the size during
+        * first kernel.
+        */
+       if (fdm_active)
+               fw_dump.boot_memory_size = fdm_active->rmr_region.source_len;
+       else
+               fw_dump.boot_memory_size = fadump_calculate_reserve_size();
+
+       /*
+        * Calculate the memory boundary.
+        * If memory_limit is less than actual memory boundary then reserve
+        * the memory for fadump beyond the memory_limit and adjust the
+        * memory_limit accordingly, so that the running kernel can run with
+        * specified memory_limit.
+        */
+       if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
+               size = get_fadump_area_size();
+               if ((memory_limit + size) < memblock_end_of_DRAM())
+                       memory_limit += size;
+               else
+                       memory_limit = memblock_end_of_DRAM();
+               printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
+                               " dump, now %#016llx\n",
+                               (unsigned long long)memory_limit);
+       }
+       if (memory_limit)
+               memory_boundary = memory_limit;
+       else
+               memory_boundary = memblock_end_of_DRAM();
+
+       if (fw_dump.dump_active) {
+               printk(KERN_INFO "Firmware-assisted dump is active.\n");
+               /*
+                * If last boot has crashed then reserve all the memory
+                * above boot_memory_size so that we don't touch it until
+                * dump is written to disk by userspace tool. This memory
+                * will be released for general use once the dump is saved.
+                */
+               base = fw_dump.boot_memory_size;
+               size = memory_boundary - base;
+               memblock_reserve(base, size);
+               printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+                               "for saving crash dump\n",
+                               (unsigned long)(size >> 20),
+                               (unsigned long)(base >> 20));
+
+               fw_dump.fadumphdr_addr =
+                               fdm_active->rmr_region.destination_address +
+                               fdm_active->rmr_region.source_len;
+               pr_debug("fadumphdr_addr = %p\n",
+                               (void *) fw_dump.fadumphdr_addr);
+       } else {
+               /* Reserve the memory at the top of memory. */
+               size = get_fadump_area_size();
+               base = memory_boundary - size;
+               memblock_reserve(base, size);
+               printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+                               "for firmware-assisted dump\n",
+                               (unsigned long)(size >> 20),
+                               (unsigned long)(base >> 20));
+       }
+       fw_dump.reserve_dump_area_start = base;
+       fw_dump.reserve_dump_area_size = size;
+       return 1;
+}
+
+/* Look for fadump= cmdline option. */
+static int __init early_fadump_param(char *p)
+{
+       if (!p)
+               return 1;
+
+       if (strncmp(p, "on", 2) == 0)
+               fw_dump.fadump_enabled = 1;
+       else if (strncmp(p, "off", 3) == 0)
+               fw_dump.fadump_enabled = 0;
+
+       return 0;
+}
+early_param("fadump", early_fadump_param);
+
+/* Look for fadump_reserve_mem= cmdline option */
+static int __init early_fadump_reserve_mem(char *p)
+{
+       if (p)
+               fw_dump.reserve_bootvar = memparse(p, &p);
+       return 0;
+}
+early_param("fadump_reserve_mem", early_fadump_reserve_mem);
+
+static void register_fw_dump(struct fadump_mem_struct *fdm)
+{
+       int rc;
+       unsigned int wait_time;
+
+       pr_debug("Registering for firmware-assisted kernel dump...\n");
+
+       /* TODO: Add upper time limit for the delay */
+       do {
+               rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+                       FADUMP_REGISTER, fdm,
+                       sizeof(struct fadump_mem_struct));
+
+               wait_time = rtas_busy_delay_time(rc);
+               if (wait_time)
+                       mdelay(wait_time);
+
+       } while (wait_time);
+
+       switch (rc) {
+       case -1:
+               printk(KERN_ERR "Failed to register firmware-assisted kernel"
+                       " dump. Hardware Error(%d).\n", rc);
+               break;
+       case -3:
+               printk(KERN_ERR "Failed to register firmware-assisted kernel"
+                       " dump. Parameter Error(%d).\n", rc);
+               break;
+       case -9:
+               printk(KERN_ERR "firmware-assisted kernel dump is already "
+                       " registered.");
+               fw_dump.dump_registered = 1;
+               break;
+       case 0:
+               printk(KERN_INFO "firmware-assisted kernel dump registration"
+                       " is successful\n");
+               fw_dump.dump_registered = 1;
+               break;
+       }
+}
+
+void crash_fadump(struct pt_regs *regs, const char *str)
+{
+       struct fadump_crash_info_header *fdh = NULL;
+
+       if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr)
+               return;
+
+       fdh = __va(fw_dump.fadumphdr_addr);
+       crashing_cpu = smp_processor_id();
+       fdh->crashing_cpu = crashing_cpu;
+       crash_save_vmcoreinfo();
+
+       if (regs)
+               fdh->regs = *regs;
+       else
+               ppc_save_regs(&fdh->regs);
+
+       fdh->cpu_online_mask = *cpu_online_mask;
+
+       /* Call ibm,os-term rtas call to trigger firmware assisted dump */
+       rtas_os_term((char *)str);
+}
+
+#define GPR_MASK       0xffffff0000000000
+static inline int fadump_gpr_index(u64 id)
+{
+       int i = -1;
+       char str[3];
+
+       if ((id & GPR_MASK) == REG_ID("GPR")) {
+               /* get the digits at the end */
+               id &= ~GPR_MASK;
+               id >>= 24;
+               str[2] = '\0';
+               str[1] = id & 0xff;
+               str[0] = (id >> 8) & 0xff;
+               sscanf(str, "%d", &i);
+               if (i > 31)
+                       i = -1;
+       }
+       return i;
+}
+
+static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id,
+                                                               u64 reg_val)
+{
+       int i;
+
+       i = fadump_gpr_index(reg_id);
+       if (i >= 0)
+               regs->gpr[i] = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("NIA"))
+               regs->nip = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("MSR"))
+               regs->msr = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("CTR"))
+               regs->ctr = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("LR"))
+               regs->link = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("XER"))
+               regs->xer = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("CR"))
+               regs->ccr = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("DAR"))
+               regs->dar = (unsigned long)reg_val;
+       else if (reg_id == REG_ID("DSISR"))
+               regs->dsisr = (unsigned long)reg_val;
+}
+
+static struct fadump_reg_entry*
+fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
+{
+       memset(regs, 0, sizeof(struct pt_regs));
+
+       while (reg_entry->reg_id != REG_ID("CPUEND")) {
+               fadump_set_regval(regs, reg_entry->reg_id,
+                                       reg_entry->reg_value);
+               reg_entry++;
+       }
+       reg_entry++;
+       return reg_entry;
+}
+
+static u32 *fadump_append_elf_note(u32 *buf, char *name, unsigned type,
+                                               void *data, size_t data_len)
+{
+       struct elf_note note;
+
+       note.n_namesz = strlen(name) + 1;
+       note.n_descsz = data_len;
+       note.n_type   = type;
+       memcpy(buf, &note, sizeof(note));
+       buf += (sizeof(note) + 3)/4;
+       memcpy(buf, name, note.n_namesz);
+       buf += (note.n_namesz + 3)/4;
+       memcpy(buf, data, note.n_descsz);
+       buf += (note.n_descsz + 3)/4;
+
+       return buf;
+}
+
+static void fadump_final_note(u32 *buf)
+{
+       struct elf_note note;
+
+       note.n_namesz = 0;
+       note.n_descsz = 0;
+       note.n_type   = 0;
+       memcpy(buf, &note, sizeof(note));
+}
+
+static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
+{
+       struct elf_prstatus prstatus;
+
+       memset(&prstatus, 0, sizeof(prstatus));
+       /*
+        * FIXME: How do i get PID? Do I really need it?
+        * prstatus.pr_pid = ????
+        */
+       elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
+       buf = fadump_append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS,
+                               &prstatus, sizeof(prstatus));
+       return buf;
+}
+
+static void fadump_update_elfcore_header(char *bufp)
+{
+       struct elfhdr *elf;
+       struct elf_phdr *phdr;
+
+       elf = (struct elfhdr *)bufp;
+       bufp += sizeof(struct elfhdr);
+
+       /* First note is a place holder for cpu notes info. */
+       phdr = (struct elf_phdr *)bufp;
+
+       if (phdr->p_type == PT_NOTE) {
+               phdr->p_paddr = fw_dump.cpu_notes_buf;
+               phdr->p_offset  = phdr->p_paddr;
+               phdr->p_filesz  = fw_dump.cpu_notes_buf_size;
+               phdr->p_memsz = fw_dump.cpu_notes_buf_size;
+       }
+       return;
+}
+
+static void *fadump_cpu_notes_buf_alloc(unsigned long size)
+{
+       void *vaddr;
+       struct page *page;
+       unsigned long order, count, i;
+
+       order = get_order(size);
+       vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
+       if (!vaddr)
+               return NULL;
+
+       count = 1 << order;
+       page = virt_to_page(vaddr);
+       for (i = 0; i < count; i++)
+               SetPageReserved(page + i);
+       return vaddr;
+}
+
+static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
+{
+       struct page *page;
+       unsigned long order, count, i;
+
+       order = get_order(size);
+       count = 1 << order;
+       page = virt_to_page(vaddr);
+       for (i = 0; i < count; i++)
+               ClearPageReserved(page + i);
+       __free_pages(page, order);
+}
+
+/*
+ * Read CPU state dump data and convert it into ELF notes.
+ * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
+ * used to access the data to allow for additional fields to be added without
+ * affecting compatibility. Each list of registers for a CPU starts with
+ * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes,
+ * 8 Byte ASCII identifier and 8 Byte register value. The register entry
+ * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part
+ * of register value. For more details refer to PAPR document.
+ *
+ * Only for the crashing cpu we ignore the CPU dump data and get exact
+ * state from fadump crash info structure populated by first kernel at the
+ * time of crash.
+ */
+static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
+{
+       struct fadump_reg_save_area_header *reg_header;
+       struct fadump_reg_entry *reg_entry;
+       struct fadump_crash_info_header *fdh = NULL;
+       void *vaddr;
+       unsigned long addr;
+       u32 num_cpus, *note_buf;
+       struct pt_regs regs;
+       int i, rc = 0, cpu = 0;
+
+       if (!fdm->cpu_state_data.bytes_dumped)
+               return -EINVAL;
+
+       addr = fdm->cpu_state_data.destination_address;
+       vaddr = __va(addr);
+
+       reg_header = vaddr;
+       if (reg_header->magic_number != REGSAVE_AREA_MAGIC) {
+               printk(KERN_ERR "Unable to read register save area.\n");
+               return -ENOENT;
+       }
+       pr_debug("--------CPU State Data------------\n");
+       pr_debug("Magic Number: %llx\n", reg_header->magic_number);
+       pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset);
+
+       vaddr += reg_header->num_cpu_offset;
+       num_cpus = *((u32 *)(vaddr));
+       pr_debug("NumCpus     : %u\n", num_cpus);
+       vaddr += sizeof(u32);
+       reg_entry = (struct fadump_reg_entry *)vaddr;
+
+       /* Allocate buffer to hold cpu crash notes. */
+       fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
+       fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
+       note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size);
+       if (!note_buf) {
+               printk(KERN_ERR "Failed to allocate 0x%lx bytes for "
+                       "cpu notes buffer\n", fw_dump.cpu_notes_buf_size);
+               return -ENOMEM;
+       }
+       fw_dump.cpu_notes_buf = __pa(note_buf);
+
+       pr_debug("Allocated buffer for cpu notes of size %ld at %p\n",
+                       (num_cpus * sizeof(note_buf_t)), note_buf);
+
+       if (fw_dump.fadumphdr_addr)
+               fdh = __va(fw_dump.fadumphdr_addr);
+
+       for (i = 0; i < num_cpus; i++) {
+               if (reg_entry->reg_id != REG_ID("CPUSTRT")) {
+                       printk(KERN_ERR "Unable to read CPU state data\n");
+                       rc = -ENOENT;
+                       goto error_out;
+               }
+               /* Lower 4 bytes of reg_value contains logical cpu id */
+               cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK;
+               if (!cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) {
+                       SKIP_TO_NEXT_CPU(reg_entry);
+                       continue;
+               }
+               pr_debug("Reading register data for cpu %d...\n", cpu);
+               if (fdh && fdh->crashing_cpu == cpu) {
+                       regs = fdh->regs;
+                       note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
+                       SKIP_TO_NEXT_CPU(reg_entry);
+               } else {
+                       reg_entry++;
+                       reg_entry = fadump_read_registers(reg_entry, &regs);
+                       note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
+               }
+       }
+       fadump_final_note(note_buf);
+
+       pr_debug("Updating elfcore header (%llx) with cpu notes\n",
+                                                       fdh->elfcorehdr_addr);
+       fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr));
+       return 0;
+
+error_out:
+       fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf),
+                                       fw_dump.cpu_notes_buf_size);
+       fw_dump.cpu_notes_buf = 0;
+       fw_dump.cpu_notes_buf_size = 0;
+       return rc;
+
+}
+
+/*
+ * Validate and process the dump data stored by firmware before exporting
+ * it through '/proc/vmcore'.
+ */
+static int __init process_fadump(const struct fadump_mem_struct *fdm_active)
+{
+       struct fadump_crash_info_header *fdh;
+       int rc = 0;
+
+       if (!fdm_active || !fw_dump.fadumphdr_addr)
+               return -EINVAL;
+
+       /* Check if the dump data is valid. */
+       if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) ||
+                       (fdm_active->cpu_state_data.error_flags != 0) ||
+                       (fdm_active->rmr_region.error_flags != 0)) {
+               printk(KERN_ERR "Dump taken by platform is not valid\n");
+               return -EINVAL;
+       }
+       if ((fdm_active->rmr_region.bytes_dumped !=
+                       fdm_active->rmr_region.source_len) ||
+                       !fdm_active->cpu_state_data.bytes_dumped) {
+               printk(KERN_ERR "Dump taken by platform is incomplete\n");
+               return -EINVAL;
+       }
+
+       /* Validate the fadump crash info header */
+       fdh = __va(fw_dump.fadumphdr_addr);
+       if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
+               printk(KERN_ERR "Crash info header is not valid.\n");
+               return -EINVAL;
+       }
+
+       rc = fadump_build_cpu_notes(fdm_active);
+       if (rc)
+               return rc;
+
+       /*
+        * We are done validating dump info and elfcore header is now ready
+        * to be exported. set elfcorehdr_addr so that vmcore module will
+        * export the elfcore header through '/proc/vmcore'.
+        */
+       elfcorehdr_addr = fdh->elfcorehdr_addr;
+
+       return 0;
+}
+
+static inline void fadump_add_crash_memory(unsigned long long base,
+                                       unsigned long long end)
+{
+       if (base == end)
+               return;
+
+       pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
+               crash_mem_ranges, base, end - 1, (end - base));
+       crash_memory_ranges[crash_mem_ranges].base = base;
+       crash_memory_ranges[crash_mem_ranges].size = end - base;
+       crash_mem_ranges++;
+}
+
+static void fadump_exclude_reserved_area(unsigned long long start,
+                                       unsigned long long end)
+{
+       unsigned long long ra_start, ra_end;
+
+       ra_start = fw_dump.reserve_dump_area_start;
+       ra_end = ra_start + fw_dump.reserve_dump_area_size;
+
+       if ((ra_start < end) && (ra_end > start)) {
+               if ((start < ra_start) && (end > ra_end)) {
+                       fadump_add_crash_memory(start, ra_start);
+                       fadump_add_crash_memory(ra_end, end);
+               } else if (start < ra_start) {
+                       fadump_add_crash_memory(start, ra_start);
+               } else if (ra_end < end) {
+                       fadump_add_crash_memory(ra_end, end);
+               }
+       } else
+               fadump_add_crash_memory(start, end);
+}
+
+static int fadump_init_elfcore_header(char *bufp)
+{
+       struct elfhdr *elf;
+
+       elf = (struct elfhdr *) bufp;
+       bufp += sizeof(struct elfhdr);
+       memcpy(elf->e_ident, ELFMAG, SELFMAG);
+       elf->e_ident[EI_CLASS] = ELF_CLASS;
+       elf->e_ident[EI_DATA] = ELF_DATA;
+       elf->e_ident[EI_VERSION] = EV_CURRENT;
+       elf->e_ident[EI_OSABI] = ELF_OSABI;
+       memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+       elf->e_type = ET_CORE;
+       elf->e_machine = ELF_ARCH;
+       elf->e_version = EV_CURRENT;
+       elf->e_entry = 0;
+       elf->e_phoff = sizeof(struct elfhdr);
+       elf->e_shoff = 0;
+       elf->e_flags = ELF_CORE_EFLAGS;
+       elf->e_ehsize = sizeof(struct elfhdr);
+       elf->e_phentsize = sizeof(struct elf_phdr);
+       elf->e_phnum = 0;
+       elf->e_shentsize = 0;
+       elf->e_shnum = 0;
+       elf->e_shstrndx = 0;
+
+       return 0;
+}
+
+/*
+ * Traverse through memblock structure and setup crash memory ranges. These
+ * ranges will be used create PT_LOAD program headers in elfcore header.
+ */
+static void fadump_setup_crash_memory_ranges(void)
+{
+       struct memblock_region *reg;
+       unsigned long long start, end;
+
+       pr_debug("Setup crash memory ranges.\n");
+       crash_mem_ranges = 0;
+       /*
+        * add the first memory chunk (RMA_START through boot_memory_size) as
+        * a separate memory chunk. The reason is, at the time crash firmware
+        * will move the content of this memory chunk to different location
+        * specified during fadump registration. We need to create a separate
+        * program header for this chunk with the correct offset.
+        */
+       fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
+
+       for_each_memblock(memory, reg) {
+               start = (unsigned long long)reg->base;
+               end = start + (unsigned long long)reg->size;
+               if (start == RMA_START && end >= fw_dump.boot_memory_size)
+                       start = fw_dump.boot_memory_size;
+
+               /* add this range excluding the reserved dump area. */
+               fadump_exclude_reserved_area(start, end);
+       }
+}
+
+/*
+ * If the given physical address falls within the boot memory region then
+ * return the relocated address that points to the dump region reserved
+ * for saving initial boot memory contents.
+ */
+static inline unsigned long fadump_relocate(unsigned long paddr)
+{
+       if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
+               return fdm.rmr_region.destination_address + paddr;
+       else
+               return paddr;
+}
+
+static int fadump_create_elfcore_headers(char *bufp)
+{
+       struct elfhdr *elf;
+       struct elf_phdr *phdr;
+       int i;
+
+       fadump_init_elfcore_header(bufp);
+       elf = (struct elfhdr *)bufp;
+       bufp += sizeof(struct elfhdr);
+
+       /*
+        * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
+        * will be populated during second kernel boot after crash. Hence
+        * this PT_NOTE will always be the first elf note.
+        *
+        * NOTE: Any new ELF note addition should be placed after this note.
+        */
+       phdr = (struct elf_phdr *)bufp;
+       bufp += sizeof(struct elf_phdr);
+       phdr->p_type = PT_NOTE;
+       phdr->p_flags = 0;
+       phdr->p_vaddr = 0;
+       phdr->p_align = 0;
+
+       phdr->p_offset = 0;
+       phdr->p_paddr = 0;
+       phdr->p_filesz = 0;
+       phdr->p_memsz = 0;
+
+       (elf->e_phnum)++;
+
+       /* setup ELF PT_NOTE for vmcoreinfo */
+       phdr = (struct elf_phdr *)bufp;
+       bufp += sizeof(struct elf_phdr);
+       phdr->p_type    = PT_NOTE;
+       phdr->p_flags   = 0;
+       phdr->p_vaddr   = 0;
+       phdr->p_align   = 0;
+
+       phdr->p_paddr   = fadump_relocate(paddr_vmcoreinfo_note());
+       phdr->p_offset  = phdr->p_paddr;
+       phdr->p_memsz   = vmcoreinfo_max_size;
+       phdr->p_filesz  = vmcoreinfo_max_size;
+
+       /* Increment number of program headers. */
+       (elf->e_phnum)++;
+
+       /* setup PT_LOAD sections. */
+
+       for (i = 0; i < crash_mem_ranges; i++) {
+               unsigned long long mbase, msize;
+               mbase = crash_memory_ranges[i].base;
+               msize = crash_memory_ranges[i].size;
+
+               if (!msize)
+                       continue;
+
+               phdr = (struct elf_phdr *)bufp;
+               bufp += sizeof(struct elf_phdr);
+               phdr->p_type    = PT_LOAD;
+               phdr->p_flags   = PF_R|PF_W|PF_X;
+               phdr->p_offset  = mbase;
+
+               if (mbase == RMA_START) {
+                       /*
+                        * The entire RMA region will be moved by firmware
+                        * to the specified destination_address. Hence set
+                        * the correct offset.
+                        */
+                       phdr->p_offset = fdm.rmr_region.destination_address;
+               }
+
+               phdr->p_paddr = mbase;
+               phdr->p_vaddr = (unsigned long)__va(mbase);
+               phdr->p_filesz = msize;
+               phdr->p_memsz = msize;
+               phdr->p_align = 0;
+
+               /* Increment number of program headers. */
+               (elf->e_phnum)++;
+       }
+       return 0;
+}
+
+static unsigned long init_fadump_header(unsigned long addr)
+{
+       struct fadump_crash_info_header *fdh;
+
+       if (!addr)
+               return 0;
+
+       fw_dump.fadumphdr_addr = addr;
+       fdh = __va(addr);
+       addr += sizeof(struct fadump_crash_info_header);
+
+       memset(fdh, 0, sizeof(struct fadump_crash_info_header));
+       fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
+       fdh->elfcorehdr_addr = addr;
+       /* We will set the crashing cpu id in crash_fadump() during crash. */
+       fdh->crashing_cpu = CPU_UNKNOWN;
+
+       return addr;
+}
+
+static void register_fadump(void)
+{
+       unsigned long addr;
+       void *vaddr;
+
+       /*
+        * If no memory is reserved then we can not register for firmware-
+        * assisted dump.
+        */
+       if (!fw_dump.reserve_dump_area_size)
+               return;
+
+       fadump_setup_crash_memory_ranges();
+
+       addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len;
+       /* Initialize fadump crash info header. */
+       addr = init_fadump_header(addr);
+       vaddr = __va(addr);
+
+       pr_debug("Creating ELF core headers at %#016lx\n", addr);
+       fadump_create_elfcore_headers(vaddr);
+
+       /* register the future kernel dump with firmware. */
+       register_fw_dump(&fdm);
+}
+
+static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
+{
+       int rc = 0;
+       unsigned int wait_time;
+
+       pr_debug("Un-register firmware-assisted dump\n");
+
+       /* TODO: Add upper time limit for the delay */
+       do {
+               rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+                       FADUMP_UNREGISTER, fdm,
+                       sizeof(struct fadump_mem_struct));
+
+               wait_time = rtas_busy_delay_time(rc);
+               if (wait_time)
+                       mdelay(wait_time);
+       } while (wait_time);
+
+       if (rc) {
+               printk(KERN_ERR "Failed to un-register firmware-assisted dump."
+                       " unexpected error(%d).\n", rc);
+               return rc;
+       }
+       fw_dump.dump_registered = 0;
+       return 0;
+}
+
+static int fadump_invalidate_dump(struct fadump_mem_struct *fdm)
+{
+       int rc = 0;
+       unsigned int wait_time;
+
+       pr_debug("Invalidating firmware-assisted dump registration\n");
+
+       /* TODO: Add upper time limit for the delay */
+       do {
+               rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+                       FADUMP_INVALIDATE, fdm,
+                       sizeof(struct fadump_mem_struct));
+
+               wait_time = rtas_busy_delay_time(rc);
+               if (wait_time)
+                       mdelay(wait_time);
+       } while (wait_time);
+
+       if (rc) {
+               printk(KERN_ERR "Failed to invalidate firmware-assisted dump "
+                       "rgistration. unexpected error(%d).\n", rc);
+               return rc;
+       }
+       fw_dump.dump_active = 0;
+       fdm_active = NULL;
+       return 0;
+}
+
+void fadump_cleanup(void)
+{
+       /* Invalidate the registration only if dump is active. */
+       if (fw_dump.dump_active) {
+               init_fadump_mem_struct(&fdm,
+                       fdm_active->cpu_state_data.destination_address);
+               fadump_invalidate_dump(&fdm);
+       }
+}
+
+/*
+ * Release the memory that was reserved in early boot to preserve the memory
+ * contents. The released memory will be available for general use.
+ */
+static void fadump_release_memory(unsigned long begin, unsigned long end)
+{
+       unsigned long addr;
+       unsigned long ra_start, ra_end;
+
+       ra_start = fw_dump.reserve_dump_area_start;
+       ra_end = ra_start + fw_dump.reserve_dump_area_size;
+
+       for (addr = begin; addr < end; addr += PAGE_SIZE) {
+               /*
+                * exclude the dump reserve area. Will reuse it for next
+                * fadump registration.
+                */
+               if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
+                       continue;
+
+               ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
+               init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
+               free_page((unsigned long)__va(addr));
+               totalram_pages++;
+       }
+}
+
+static void fadump_invalidate_release_mem(void)
+{
+       unsigned long reserved_area_start, reserved_area_end;
+       unsigned long destination_address;
+
+       mutex_lock(&fadump_mutex);
+       if (!fw_dump.dump_active) {
+               mutex_unlock(&fadump_mutex);
+               return;
+       }
+
+       destination_address = fdm_active->cpu_state_data.destination_address;
+       fadump_cleanup();
+       mutex_unlock(&fadump_mutex);
+
+       /*
+        * Save the current reserved memory bounds we will require them
+        * later for releasing the memory for general use.
+        */
+       reserved_area_start = fw_dump.reserve_dump_area_start;
+       reserved_area_end = reserved_area_start +
+                       fw_dump.reserve_dump_area_size;
+       /*
+        * Setup reserve_dump_area_start and its size so that we can
+        * reuse this reserved memory for Re-registration.
+        */
+       fw_dump.reserve_dump_area_start = destination_address;
+       fw_dump.reserve_dump_area_size = get_fadump_area_size();
+
+       fadump_release_memory(reserved_area_start, reserved_area_end);
+       if (fw_dump.cpu_notes_buf) {
+               fadump_cpu_notes_buf_free(
+                               (unsigned long)__va(fw_dump.cpu_notes_buf),
+                               fw_dump.cpu_notes_buf_size);
+               fw_dump.cpu_notes_buf = 0;
+               fw_dump.cpu_notes_buf_size = 0;
+       }
+       /* Initialize the kernel dump memory structure for FAD registration. */
+       init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+}
+
+static ssize_t fadump_release_memory_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       if (!fw_dump.dump_active)
+               return -EPERM;
+
+       if (buf[0] == '1') {
+               /*
+                * Take away the '/proc/vmcore'. We are releasing the dump
+                * memory, hence it will not be valid anymore.
+                */
+               vmcore_cleanup();
+               fadump_invalidate_release_mem();
+
+       } else
+               return -EINVAL;
+       return count;
+}
+
+static ssize_t fadump_enabled_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buf)
+{
+       return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
+}
+
+static ssize_t fadump_register_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buf)
+{
+       return sprintf(buf, "%d\n", fw_dump.dump_registered);
+}
+
+static ssize_t fadump_register_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       int ret = 0;
+
+       if (!fw_dump.fadump_enabled || fdm_active)
+               return -EPERM;
+
+       mutex_lock(&fadump_mutex);
+
+       switch (buf[0]) {
+       case '0':
+               if (fw_dump.dump_registered == 0) {
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               /* Un-register Firmware-assisted dump */
+               fadump_unregister_dump(&fdm);
+               break;
+       case '1':
+               if (fw_dump.dump_registered == 1) {
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               /* Register Firmware-assisted dump */
+               register_fadump();
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+unlock_out:
+       mutex_unlock(&fadump_mutex);
+       return ret < 0 ? ret : count;
+}
+
+static int fadump_region_show(struct seq_file *m, void *private)
+{
+       const struct fadump_mem_struct *fdm_ptr;
+
+       if (!fw_dump.fadump_enabled)
+               return 0;
+
+       mutex_lock(&fadump_mutex);
+       if (fdm_active)
+               fdm_ptr = fdm_active;
+       else {
+               mutex_unlock(&fadump_mutex);
+               fdm_ptr = &fdm;
+       }
+
+       seq_printf(m,
+                       "CPU : [%#016llx-%#016llx] %#llx bytes, "
+                       "Dumped: %#llx\n",
+                       fdm_ptr->cpu_state_data.destination_address,
+                       fdm_ptr->cpu_state_data.destination_address +
+                       fdm_ptr->cpu_state_data.source_len - 1,
+                       fdm_ptr->cpu_state_data.source_len,
+                       fdm_ptr->cpu_state_data.bytes_dumped);
+       seq_printf(m,
+                       "HPTE: [%#016llx-%#016llx] %#llx bytes, "
+                       "Dumped: %#llx\n",
+                       fdm_ptr->hpte_region.destination_address,
+                       fdm_ptr->hpte_region.destination_address +
+                       fdm_ptr->hpte_region.source_len - 1,
+                       fdm_ptr->hpte_region.source_len,
+                       fdm_ptr->hpte_region.bytes_dumped);
+       seq_printf(m,
+                       "DUMP: [%#016llx-%#016llx] %#llx bytes, "
+                       "Dumped: %#llx\n",
+                       fdm_ptr->rmr_region.destination_address,
+                       fdm_ptr->rmr_region.destination_address +
+                       fdm_ptr->rmr_region.source_len - 1,
+                       fdm_ptr->rmr_region.source_len,
+                       fdm_ptr->rmr_region.bytes_dumped);
+
+       if (!fdm_active ||
+               (fw_dump.reserve_dump_area_start ==
+               fdm_ptr->cpu_state_data.destination_address))
+               goto out;
+
+       /* Dump is active. Show reserved memory region. */
+       seq_printf(m,
+                       "    : [%#016llx-%#016llx] %#llx bytes, "
+                       "Dumped: %#llx\n",
+                       (unsigned long long)fw_dump.reserve_dump_area_start,
+                       fdm_ptr->cpu_state_data.destination_address - 1,
+                       fdm_ptr->cpu_state_data.destination_address -
+                       fw_dump.reserve_dump_area_start,
+                       fdm_ptr->cpu_state_data.destination_address -
+                       fw_dump.reserve_dump_area_start);
+out:
+       if (fdm_active)
+               mutex_unlock(&fadump_mutex);
+       return 0;
+}
+
+static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
+                                               0200, NULL,
+                                               fadump_release_memory_store);
+static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
+                                               0444, fadump_enabled_show,
+                                               NULL);
+static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
+                                               0644, fadump_register_show,
+                                               fadump_register_store);
+
+static int fadump_region_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fadump_region_show, inode->i_private);
+}
+
+static const struct file_operations fadump_region_fops = {
+       .open    = fadump_region_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+static void fadump_init_files(void)
+{
+       struct dentry *debugfs_file;
+       int rc = 0;
+
+       rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
+       if (rc)
+               printk(KERN_ERR "fadump: unable to create sysfs file"
+                       " fadump_enabled (%d)\n", rc);
+
+       rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
+       if (rc)
+               printk(KERN_ERR "fadump: unable to create sysfs file"
+                       " fadump_registered (%d)\n", rc);
+
+       debugfs_file = debugfs_create_file("fadump_region", 0444,
+                                       powerpc_debugfs_root, NULL,
+                                       &fadump_region_fops);
+       if (!debugfs_file)
+               printk(KERN_ERR "fadump: unable to create debugfs file"
+                               " fadump_region\n");
+
+       if (fw_dump.dump_active) {
+               rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
+               if (rc)
+                       printk(KERN_ERR "fadump: unable to create sysfs file"
+                               " fadump_release_mem (%d)\n", rc);
+       }
+       return;
+}
+
+/*
+ * Prepare for firmware-assisted dump.
+ */
+int __init setup_fadump(void)
+{
+       if (!fw_dump.fadump_enabled)
+               return 0;
+
+       if (!fw_dump.fadump_supported) {
+               printk(KERN_ERR "Firmware-assisted dump is not supported on"
+                       " this hardware\n");
+               return 0;
+       }
+
+       fadump_show_config();
+       /*
+        * If dump data is available then see if it is valid and prepare for
+        * saving it to the disk.
+        */
+       if (fw_dump.dump_active) {
+               /*
+                * if dump process fails then invalidate the registration
+                * and release memory before proceeding for re-registration.
+                */
+               if (process_fadump(fdm_active) < 0)
+                       fadump_invalidate_release_mem();
+       }
+       /* Initialize the kernel dump memory structure for FAD registration. */
+       else if (fw_dump.reserve_dump_area_size)
+               init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+       fadump_init_files();
+
+       return 1;
+}
+subsys_initcall(setup_fadump);
index 0654dba..dc0488b 100644 (file)
@@ -395,7 +395,7 @@ DataAccess:
        bl      hash_page
 1:     lwz     r5,_DSISR(r11)          /* get DSISR value */
        mfspr   r4,SPRN_DAR
-       EXC_XFER_EE_LITE(0x300, handle_page_fault)
+       EXC_XFER_LITE(0x300, handle_page_fault)
 
 
 /* Instruction access exception. */
@@ -410,7 +410,7 @@ InstructionAccess:
        bl      hash_page
 1:     mr      r4,r12
        mr      r5,r9
-       EXC_XFER_EE_LITE(0x400, handle_page_fault)
+       EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
        EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
index 872a6af..4989661 100644 (file)
@@ -394,7 +394,7 @@ label:
        NORMAL_EXCEPTION_PROLOG
        mr      r4,r12                  /* Pass SRR0 as arg2 */
        li      r5,0                    /* Pass zero as arg3 */
-       EXC_XFER_EE_LITE(0x400, handle_page_fault)
+       EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* 0x0500 - External Interrupt Exception */
        EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
@@ -747,7 +747,7 @@ DataAccess:
        mfspr   r5,SPRN_ESR             /* Grab the ESR, save it, pass arg3 */
        stw     r5,_ESR(r11)
        mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
-       EXC_XFER_EE_LITE(0x300, handle_page_fault)
+       EXC_XFER_LITE(0x300, handle_page_fault)
 
 /* Other PowerPC processors, namely those derived from the 6xx-series
  * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved.
index 06c7251..58bddee 100644 (file)
 #include <asm/cputable.h>
 #include <asm/setup.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/lpar_map.h>
 #include <asm/thread_info.h>
 #include <asm/firmware.h>
 #include <asm/page_64.h>
 #include <asm/irqflags.h>
 #include <asm/kvm_book3s_asm.h>
 #include <asm/ptrace.h>
+#include <asm/hw_irq.h>
 
 /* The physical memory is laid out such that the secondary processor
  * spin code sits at 0x0000...0x00ff. On server, the vectors follow
  *     entry in r9 for debugging purposes
  *   2. Secondary processors enter at 0x60 with PIR in gpr3
  *
- *  For iSeries:
- *   1. The MMU is on (as it always is for iSeries)
- *   2. The kernel is entered at system_reset_iSeries
- *
  *  For Book3E processors:
  *   1. The MMU is on running in AS0 in a state defined in ePAPR
  *   2. The kernel is entered at __start
@@ -93,15 +89,6 @@ __secondary_hold_spinloop:
 __secondary_hold_acknowledge:
        .llong  0x0
 
-#ifdef CONFIG_PPC_ISERIES
-       /*
-        * At offset 0x20, there is a pointer to iSeries LPAR data.
-        * This is required by the hypervisor
-        */
-       . = 0x20
-       .llong hvReleaseData-KERNELBASE
-#endif /* CONFIG_PPC_ISERIES */
-
 #ifdef CONFIG_RELOCATABLE
        /* This flag is set to 1 by a loader if the kernel should run
         * at the loaded address instead of the linked address.  This
@@ -564,7 +551,8 @@ _GLOBAL(pmac_secondary_start)
         */
        li      r0,0
        stb     r0,PACASOFTIRQEN(r13)
-       stb     r0,PACAHARDIRQEN(r13)
+       li      r0,PACA_IRQ_HARD_DIS
+       stb     r0,PACAIRQHAPPENED(r13)
 
        /* Create a temp kernel stack for use before relocation is on.  */
        ld      r1,PACAEMERGSP(r13)
@@ -582,7 +570,7 @@ _GLOBAL(pmac_secondary_start)
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
- *   r1               = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
+ *   r1               = stack pointer (real addr of temp stack)
  *   r24       = cpu# (in Linux terms)
  *   r13       = paca virtual address
  *   SPRG_PACA = paca virtual address
@@ -595,7 +583,7 @@ __secondary_start:
        /* Set thread priority to MEDIUM */
        HMT_MEDIUM
 
-       /* Initialize the kernel stack.  Just a repeat for iSeries.      */
+       /* Initialize the kernel stack */
        LOAD_REG_ADDR(r3, current_set)
        sldi    r28,r24,3               /* get current_set[cpu#]         */
        ldx     r14,r3,r28
@@ -615,20 +603,16 @@ __secondary_start:
        li      r7,0
        mtlr    r7
 
+       /* Mark interrupts soft and hard disabled (they might be enabled
+        * in the PACA when doing hotplug)
+        */
+       stb     r7,PACASOFTIRQEN(r13)
+       li      r0,PACA_IRQ_HARD_DIS
+       stb     r0,PACAIRQHAPPENED(r13)
+
        /* enable MMU and jump to start_secondary */
        LOAD_REG_ADDR(r3, .start_secondary_prolog)
        LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       ori     r4,r4,MSR_EE
-       li      r8,1
-       stb     r8,PACAHARDIRQEN(r13)
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
-BEGIN_FW_FTR_SECTION
-       stb     r7,PACAHARDIRQEN(r13)
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
-       stb     r7,PACASOFTIRQEN(r13)
 
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
@@ -771,22 +755,18 @@ _INIT_GLOBAL(start_here_common)
        /* Load the TOC (virtual address) */
        ld      r2,PACATOC(r13)
 
+       /* Do more system initializations in virtual mode */
        bl      .setup_system
 
-       /* Load up the kernel context */
-5:
-       li      r5,0
-       stb     r5,PACASOFTIRQEN(r13)   /* Soft Disabled */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       mfmsr   r5
-       ori     r5,r5,MSR_EE            /* Hard Enabled on iSeries*/
-       mtmsrd  r5
-       li      r5,1
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
-       stb     r5,PACAHARDIRQEN(r13)   /* Hard Disabled on others */
+       /* Mark interrupts soft and hard disabled (they might be enabled
+        * in the PACA when doing hotplug)
+        */
+       li      r0,0
+       stb     r0,PACASOFTIRQEN(r13)
+       li      r0,PACA_IRQ_HARD_DIS
+       stb     r0,PACAIRQHAPPENED(r13)
 
+       /* Generic kernel entry */
        bl      .start_kernel
 
        /* Not reached */
index b68cb17..b2a5860 100644 (file)
@@ -220,7 +220,7 @@ DataAccess:
        mfspr   r4,SPRN_DAR
        li      r10,0x00f0
        mtspr   SPRN_DAR,r10    /* Tag DAR, to be used in DTLB Error */
-       EXC_XFER_EE_LITE(0x300, handle_page_fault)
+       EXC_XFER_LITE(0x300, handle_page_fault)
 
 /* Instruction access exception.
  * This is "never generated" by the MPC8xx.  We jump to it for other
@@ -231,7 +231,7 @@ InstructionAccess:
        EXCEPTION_PROLOG
        mr      r4,r12
        mr      r5,r9
-       EXC_XFER_EE_LITE(0x400, handle_page_fault)
+       EXC_XFER_LITE(0x400, handle_page_fault)
 
 /* External interrupt */
        EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
index fc921bf..0e41753 100644 (file)
@@ -359,7 +359,7 @@ label:
        mfspr   r5,SPRN_ESR;            /* Grab the ESR and save it */        \
        stw     r5,_ESR(r11);                                                 \
        mfspr   r4,SPRN_DEAR;           /* Grab the DEAR */                   \
-       EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+       EXC_XFER_LITE(0x0300, handle_page_fault)
 
 #define INSTRUCTION_STORAGE_EXCEPTION                                        \
        START_EXCEPTION(InstructionStorage)                                   \
@@ -368,7 +368,7 @@ label:
        stw     r5,_ESR(r11);                                                 \
        mr      r4,r12;                 /* Pass SRR0 as arg2 */               \
        li      r5,0;                   /* Pass zero as arg3 */               \
-       EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+       EXC_XFER_LITE(0x0400, handle_page_fault)
 
 #define ALIGNMENT_EXCEPTION                                                  \
        START_EXCEPTION(Alignment)                                            \
index d5d78c4..28e6259 100644 (file)
@@ -319,7 +319,7 @@ interrupt_base:
        mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
        andis.  r10,r5,(ESR_ILK|ESR_DLK)@h
        bne     1f
-       EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+       EXC_XFER_LITE(0x0300, handle_page_fault)
 1:
        addi    r3,r1,STACK_FRAME_OVERHEAD
        EXC_XFER_EE_LITE(0x0300, CacheLockingException)
index c97fc60..e8e8211 100644 (file)
@@ -84,7 +84,11 @@ void cpu_idle(void)
 
                                start_critical_timings();
 
-                               local_irq_enable();
+                               /* Some power_save functions return with
+                                * interrupts enabled, some don't.
+                                */
+                               if (irqs_disabled())
+                                       local_irq_enable();
                                set_thread_flag(TIF_POLLING_NRFLAG);
 
                        } else {
index 16c002d..ff007b5 100644 (file)
@@ -29,43 +29,30 @@ _GLOBAL(book3e_idle)
        wrteei  0
 
        /* Now check if an interrupt came in while we were soft disabled
-        * since we may otherwise lose it (doorbells etc...). We know
-        * that since PACAHARDIRQEN will have been cleared in that case.
+        * since we may otherwise lose it (doorbells etc...).
         */
-       lbz     r3,PACAHARDIRQEN(r13)
+       lbz     r3,PACAIRQHAPPENED(r13)
        cmpwi   cr0,r3,0
-       beqlr
+       bnelr
 
-       /* Now we are going to mark ourselves as soft and hard enables in
+       /* Now we are going to mark ourselves as soft and hard enabled in
         * order to be able to take interrupts while asleep. We inform lockdep
         * of that. We don't actually turn interrupts on just yet tho.
         */
 #ifdef CONFIG_TRACE_IRQFLAGS
        stdu    r1,-128(r1)
        bl      .trace_hardirqs_on
+       addi    r1,r1,128
 #endif
        li      r0,1
        stb     r0,PACASOFTIRQEN(r13)
-       stb     r0,PACAHARDIRQEN(r13)
        
        /* Interrupts will make use return to LR, so get something we want
         * in there
         */
        bl      1f
 
-       /* Hard disable interrupts again */
-       wrteei  0
-
-       /* Mark them off again in the PACA as well */
-       li      r0,0
-       stb     r0,PACASOFTIRQEN(r13)
-       stb     r0,PACAHARDIRQEN(r13)
-
-       /* Tell lockdep about it */
-#ifdef CONFIG_TRACE_IRQFLAGS
-       bl      .trace_hardirqs_off
-       addi    r1,r1,128
-#endif
+       /* And return (interrupts are on) */
        ld      r0,16(r1)
        mtlr    r0
        blr
index ba31954..2c71b0f 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/irqflags.h>
 
 #undef DEBUG
 
@@ -29,14 +30,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
        cmpwi   0,r4,0
        beqlr
 
-       /* Go to NAP now */
+       /* Hard disable interrupts */
        mfmsr   r7
        rldicl  r0,r7,48,1
        rotldi  r0,r0,16
-       mtmsrd  r0,1                    /* hard-disable interrupts */
+       mtmsrd  r0,1
+
+       /* Check if something happened while soft-disabled */
+       lbz     r0,PACAIRQHAPPENED(r13)
+       cmpwi   cr0,r0,0
+       bnelr
+
+       /* Soft-enable interrupts */
+#ifdef CONFIG_TRACE_IRQFLAGS
+       mflr    r0
+       std     r0,16(r1)
+       stdu    r1,-128(r1)
+       bl      .trace_hardirqs_on
+       addi    r1,r1,128
+       ld      r0,16(r1)
+       mtlr    r0
+       mfmsr   r7
+#endif /* CONFIG_TRACE_IRQFLAGS */
+
        li      r0,1
        stb     r0,PACASOFTIRQEN(r13)   /* we'll hard-enable shortly */
-       stb     r0,PACAHARDIRQEN(r13)
 BEGIN_FTR_SECTION
        DSSALL
        sync
index fcdff19..0cdc9a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  This file contains the power_save function for 970-family CPUs.
+ *  This file contains the power_save function for Power7 CPUs.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -15,6 +15,7 @@
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/ppc-opcode.h>
+#include <asm/hw_irq.h>
 
 #undef DEBUG
 
@@ -51,9 +52,25 @@ _GLOBAL(power7_idle)
        rldicl  r9,r9,48,1
        rotldi  r9,r9,16
        mtmsrd  r9,1                    /* hard-disable interrupts */
+
+       /* Check if something happened while soft-disabled */
+       lbz     r0,PACAIRQHAPPENED(r13)
+       cmpwi   cr0,r0,0
+       beq     1f
+       addi    r1,r1,INT_FRAME_SIZE
+       ld      r0,16(r1)
+       mtlr    r0
+       blr
+
+1:     /* We mark irqs hard disabled as this is the state we'll
+        * be in when returning and we need to tell arch_local_irq_restore()
+        * about it
+        */
+       li      r0,PACA_IRQ_HARD_DIS
+       stb     r0,PACAIRQHAPPENED(r13)
+
+       /* We haven't lost state ... yet */
        li      r0,0
-       stb     r0,PACASOFTIRQEN(r13)   /* we'll hard-enable shortly */
-       stb     r0,PACAHARDIRQEN(r13)
        stb     r0,PACA_NAPSTATELOST(r13)
 
        /* Continue saving state */
index 0cfcf98..359f078 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/kdump.h>
+#include <asm/fadump.h>
 
 #define DBG(...)
 
@@ -445,7 +446,12 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 
 static void iommu_table_clear(struct iommu_table *tbl)
 {
-       if (!is_kdump_kernel()) {
+       /*
+        * In case of firmware assisted dump system goes through clean
+        * reboot process at the time of system crash. Hence it's safe to
+        * clear the TCE entries if firmware assisted dump is active.
+        */
+       if (!is_kdump_kernel() || is_fadump_active()) {
                /* Clear the table in case firmware left allocations in it */
                ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
                return;
index bdfb3ee..a3d128e 100644 (file)
@@ -93,20 +93,16 @@ extern int tau_interrupts(int);
 
 #ifdef CONFIG_PPC64
 
-#ifndef CONFIG_SPARSE_IRQ
-EXPORT_SYMBOL(irq_desc);
-#endif
-
 int distribute_irqs = 1;
 
-static inline notrace unsigned long get_hard_enabled(void)
+static inline notrace unsigned long get_irq_happened(void)
 {
-       unsigned long enabled;
+       unsigned long happened;
 
        __asm__ __volatile__("lbz %0,%1(13)"
-       : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled)));
+       : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened)));
 
-       return enabled;
+       return happened;
 }
 
 static inline notrace void set_soft_enabled(unsigned long enable)
@@ -115,88 +111,162 @@ static inline notrace void set_soft_enabled(unsigned long enable)
        : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
 }
 
-static inline notrace void decrementer_check_overflow(void)
+static inline notrace int decrementer_check_overflow(void)
 {
-       u64 now = get_tb_or_rtc();
-       u64 *next_tb;
-
-       preempt_disable();
-       next_tb = &__get_cpu_var(decrementers_next_tb);
-
+       u64 now = get_tb_or_rtc();
+       u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
        if (now >= *next_tb)
                set_dec(1);
-       preempt_enable();
+       return now >= *next_tb;
 }
 
-notrace void arch_local_irq_restore(unsigned long en)
+/* This is called whenever we are re-enabling interrupts
+ * and returns either 0 (nothing to do) or 500/900 if there's
+ * either an EE or a DEC to generate.
+ *
+ * This is called in two contexts: From arch_local_irq_restore()
+ * before soft-enabling interrupts, and from the exception exit
+ * path when returning from an interrupt from a soft-disabled to
+ * a soft enabled context. In both case we have interrupts hard
+ * disabled.
+ *
+ * We take care of only clearing the bits we handled in the
+ * PACA irq_happened field since we can only re-emit one at a
+ * time and we don't want to "lose" one.
+ */
+notrace unsigned int __check_irq_replay(void)
 {
        /*
-        * get_paca()->soft_enabled = en;
-        * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1?
-        * That was allowed before, and in such a case we do need to take care
-        * that gcc will set soft_enabled directly via r13, not choose to use
-        * an intermediate register, lest we're preempted to a different cpu.
+        * We use local_paca rather than get_paca() to avoid all
+        * the debug_smp_processor_id() business in this low level
+        * function
         */
-       set_soft_enabled(en);
-       if (!en)
-               return;
+       unsigned char happened = local_paca->irq_happened;
 
-#ifdef CONFIG_PPC_STD_MMU_64
-       if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-               /*
-                * Do we need to disable preemption here?  Not really: in the
-                * unlikely event that we're preempted to a different cpu in
-                * between getting r13, loading its lppaca_ptr, and loading
-                * its any_int, we might call iseries_handle_interrupts without
-                * an interrupt pending on the new cpu, but that's no disaster,
-                * is it?  And the business of preempting us off the old cpu
-                * would itself involve a local_irq_restore which handles the
-                * interrupt to that cpu.
-                *
-                * But use "local_paca->lppaca_ptr" instead of "get_lppaca()"
-                * to avoid any preemption checking added into get_paca().
-                */
-               if (local_paca->lppaca_ptr->int_dword.any_int)
-                       iseries_handle_interrupts();
+       /* Clear bit 0 which we wouldn't clear otherwise */
+       local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
+
+       /*
+        * Force the delivery of pending soft-disabled interrupts on PS3.
+        * Any HV call will have this side effect.
+        */
+       if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+               u64 tmp, tmp2;
+               lv1_get_version_info(&tmp, &tmp2);
        }
-#endif /* CONFIG_PPC_STD_MMU_64 */
 
        /*
-        * if (get_paca()->hard_enabled) return;
-        * But again we need to take care that gcc gets hard_enabled directly
-        * via r13, not choose to use an intermediate register, lest we're
-        * preempted to a different cpu in between the two instructions.
+        * We may have missed a decrementer interrupt. We check the
+        * decrementer itself rather than the paca irq_happened field
+        * in case we also had a rollover while hard disabled
+        */
+       local_paca->irq_happened &= ~PACA_IRQ_DEC;
+       if (decrementer_check_overflow())
+               return 0x900;
+
+       /* Finally check if an external interrupt happened */
+       local_paca->irq_happened &= ~PACA_IRQ_EE;
+       if (happened & PACA_IRQ_EE)
+               return 0x500;
+
+#ifdef CONFIG_PPC_BOOK3E
+       /* Finally check if an EPR external interrupt happened
+        * this bit is typically set if we need to handle another
+        * "edge" interrupt from within the MPIC "EPR" handler
         */
-       if (get_hard_enabled())
+       local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
+       if (happened & PACA_IRQ_EE_EDGE)
+               return 0x500;
+
+       local_paca->irq_happened &= ~PACA_IRQ_DBELL;
+       if (happened & PACA_IRQ_DBELL)
+               return 0x280;
+#endif /* CONFIG_PPC_BOOK3E */
+
+       /* There should be nothing left ! */
+       BUG_ON(local_paca->irq_happened != 0);
+
+       return 0;
+}
+
+notrace void arch_local_irq_restore(unsigned long en)
+{
+       unsigned char irq_happened;
+       unsigned int replay;
+
+       /* Write the new soft-enabled value */
+       set_soft_enabled(en);
+       if (!en)
+               return;
+       /*
+        * From this point onward, we can take interrupts, preempt,
+        * etc... unless we got hard-disabled. We check if an event
+        * happened. If none happened, we know we can just return.
+        *
+        * We may have preempted before the check below, in which case
+        * we are checking the "new" CPU instead of the old one. This
+        * is only a problem if an event happened on the "old" CPU.
+        *
+        * External interrupt events on non-iseries will have caused
+        * interrupts to be hard-disabled, so there is no problem, we
+        * cannot have preempted.
+        */
+       irq_happened = get_irq_happened();
+       if (!irq_happened)
                return;
 
        /*
-        * Need to hard-enable interrupts here.  Since currently disabled,
-        * no need to take further asm precautions against preemption; but
-        * use local_paca instead of get_paca() to avoid preemption checking.
+        * We need to hard disable to get a trusted value from
+        * __check_irq_replay(). We also need to soft-disable
+        * again to avoid warnings in there due to the use of
+        * per-cpu variables.
+        *
+        * We know that if the value in irq_happened is exactly 0x01
+        * then we are already hard disabled (there are other less
+        * common cases that we'll ignore for now), so we skip the
+        * (expensive) mtmsrd.
         */
-       local_paca->hard_enabled = en;
+       if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
+               __hard_irq_disable();
+       set_soft_enabled(0);
 
        /*
-        * Trigger the decrementer if we have a pending event. Some processors
-        * only trigger on edge transitions of the sign bit. We might also
-        * have disabled interrupts long enough that the decrementer wrapped
-        * to positive.
+        * Check if anything needs to be re-emitted. We haven't
+        * soft-enabled yet to avoid warnings in decrementer_check_overflow
+        * accessing per-cpu variables
         */
-       decrementer_check_overflow();
+       replay = __check_irq_replay();
+
+       /* We can soft-enable now */
+       set_soft_enabled(1);
 
        /*
-        * Force the delivery of pending soft-disabled interrupts on PS3.
-        * Any HV call will have this side effect.
+        * And replay if we have to. This will return with interrupts
+        * hard-enabled.
         */
-       if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
-               u64 tmp, tmp2;
-               lv1_get_version_info(&tmp, &tmp2);
+       if (replay) {
+               __replay_interrupt(replay);
+               return;
        }
 
+       /* Finally, let's ensure we are hard enabled */
        __hard_irq_enable();
 }
 EXPORT_SYMBOL(arch_local_irq_restore);
+
+/*
+ * This is specifically called by assembly code to re-enable interrupts
+ * if they are currently disabled. This is typically called before
+ * schedule() or do_signal() when returning to userspace. We do it
+ * in C to avoid the burden of dealing with lockdep etc...
+ */
+void restore_interrupts(void)
+{
+       if (irqs_disabled())
+               local_irq_enable();
+}
+
 #endif /* CONFIG_PPC64 */
 
 int arch_show_interrupts(struct seq_file *p, int prec)
@@ -364,8 +434,17 @@ void do_IRQ(struct pt_regs *regs)
 
        check_stack_overflow();
 
+       /*
+        * Query the platform PIC for the interrupt & ack it.
+        *
+        * This will typically lower the interrupt line to the CPU
+        */
        irq = ppc_md.get_irq();
 
+       /* We can hard enable interrupts now */
+       may_hard_irq_enable();
+
+       /* And finally process it */
        if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
                handle_one_irq(irq);
        else if (irq != NO_IRQ_IGNORE)
@@ -374,15 +453,6 @@ void do_IRQ(struct pt_regs *regs)
        irq_exit();
        set_irq_regs(old_regs);
 
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES) &&
-                       get_lppaca()->int_dword.fields.decr_int) {
-               get_lppaca()->int_dword.fields.decr_int = 0;
-               /* Signal a fake decrementer interrupt */
-               timer_interrupt(regs);
-       }
-#endif
-
        trace_irq_exit(regs);
 }
 
index 4797529..d45ec58 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
-#include <asm/firmware.h>
 
 unsigned long isa_io_base;     /* NULL if no ISA bus */
 EXPORT_SYMBOL(isa_io_base);
@@ -261,8 +260,6 @@ static struct notifier_block isa_bridge_notifier = {
  */
 static int __init isa_bridge_init(void)
 {
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
        bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
        return 0;
 }
index 578f35f..ac12bd8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/iseries/hv_lp_config.h>
 #include <asm/lppaca.h>
 #include <asm/hvcall.h>
 #include <asm/firmware.h>
@@ -55,80 +54,14 @@ static unsigned long get_purr(void)
        int cpu;
 
        for_each_possible_cpu(cpu) {
-               if (firmware_has_feature(FW_FEATURE_ISERIES))
-                       sum_purr += lppaca_of(cpu).emulated_time_base;
-               else {
-                       struct cpu_usage *cu;
+               struct cpu_usage *cu;
 
-                       cu = &per_cpu(cpu_usage_array, cpu);
-                       sum_purr += cu->current_tb;
-               }
+               cu = &per_cpu(cpu_usage_array, cpu);
+               sum_purr += cu->current_tb;
        }
        return sum_purr;
 }
 
-#ifdef CONFIG_PPC_ISERIES
-
-/*
- * Methods used to fetch LPAR data when running on an iSeries platform.
- */
-static int iseries_lparcfg_data(struct seq_file *m, void *v)
-{
-       unsigned long pool_id;
-       int shared, entitled_capacity, max_entitled_capacity;
-       int processors, max_processors;
-       unsigned long purr = get_purr();
-
-       shared = (int)(local_paca->lppaca_ptr->shared_proc);
-
-       seq_printf(m, "system_active_processors=%d\n",
-                  (int)HvLpConfig_getSystemPhysicalProcessors());
-
-       seq_printf(m, "system_potential_processors=%d\n",
-                  (int)HvLpConfig_getSystemPhysicalProcessors());
-
-       processors = (int)HvLpConfig_getPhysicalProcessors();
-       seq_printf(m, "partition_active_processors=%d\n", processors);
-
-       max_processors = (int)HvLpConfig_getMaxPhysicalProcessors();
-       seq_printf(m, "partition_potential_processors=%d\n", max_processors);
-
-       if (shared) {
-               entitled_capacity = HvLpConfig_getSharedProcUnits();
-               max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits();
-       } else {
-               entitled_capacity = processors * 100;
-               max_entitled_capacity = max_processors * 100;
-       }
-       seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity);
-
-       seq_printf(m, "partition_max_entitled_capacity=%d\n",
-                  max_entitled_capacity);
-
-       if (shared) {
-               pool_id = HvLpConfig_getSharedPoolIndex();
-               seq_printf(m, "pool=%d\n", (int)pool_id);
-               seq_printf(m, "pool_capacity=%d\n",
-                          (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) *
-                                100));
-               seq_printf(m, "purr=%ld\n", purr);
-       }
-
-       seq_printf(m, "shared_processor_mode=%d\n", shared);
-
-       return 0;
-}
-
-#else                          /* CONFIG_PPC_ISERIES */
-
-static int iseries_lparcfg_data(struct seq_file *m, void *v)
-{
-       return 0;
-}
-
-#endif                         /* CONFIG_PPC_ISERIES */
-
-#ifdef CONFIG_PPC_PSERIES
 /*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
@@ -648,8 +581,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
        u8 new_weight, *new_weight_ptr = &new_weight;
        ssize_t retval;
 
-       if (!firmware_has_feature(FW_FEATURE_SPLPAR) ||
-                       firmware_has_feature(FW_FEATURE_ISERIES))
+       if (!firmware_has_feature(FW_FEATURE_SPLPAR))
                return -EINVAL;
 
        if (count > kbuf_sz)
@@ -709,21 +641,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
        return retval;
 }
 
-#else                          /* CONFIG_PPC_PSERIES */
-
-static int pseries_lparcfg_data(struct seq_file *m, void *v)
-{
-       return 0;
-}
-
-static ssize_t lparcfg_write(struct file *file, const char __user * buf,
-                            size_t count, loff_t * off)
-{
-       return -EINVAL;
-}
-
-#endif                         /* CONFIG_PPC_PSERIES */
-
 static int lparcfg_data(struct seq_file *m, void *v)
 {
        struct device_node *rootdn;
@@ -738,19 +655,11 @@ static int lparcfg_data(struct seq_file *m, void *v)
        rootdn = of_find_node_by_path("/");
        if (rootdn) {
                tmp = of_get_property(rootdn, "model", NULL);
-               if (tmp) {
+               if (tmp)
                        model = tmp;
-                       /* Skip "IBM," - see platforms/iseries/dt.c */
-                       if (firmware_has_feature(FW_FEATURE_ISERIES))
-                               model += 4;
-               }
                tmp = of_get_property(rootdn, "system-id", NULL);
-               if (tmp) {
+               if (tmp)
                        system_id = tmp;
-                       /* Skip "IBM," - see platforms/iseries/dt.c */
-                       if (firmware_has_feature(FW_FEATURE_ISERIES))
-                               system_id += 4;
-               }
                lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
                                        NULL);
                if (lp_index_ptr)
@@ -761,8 +670,6 @@ static int lparcfg_data(struct seq_file *m, void *v)
        seq_printf(m, "system_type=%s\n", model);
        seq_printf(m, "partition_id=%d\n", (int)lp_index);
 
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return iseries_lparcfg_data(m, v);
        return pseries_lparcfg_data(m, v);
 }
 
@@ -786,8 +693,7 @@ static int __init lparcfg_init(void)
        umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
 
        /* Allow writing if we have FW_FEATURE_SPLPAR */
-       if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
-                       !firmware_has_feature(FW_FEATURE_ISERIES))
+       if (firmware_has_feature(FW_FEATURE_SPLPAR))
                mode |= S_IWUSR;
 
        ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops);
index b69463e..ba16874 100644 (file)
@@ -5,7 +5,6 @@
  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
  * and Paul Mackerras.
  *
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
  * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
  *
  * setjmp/longjmp code by Paul Mackerras.
diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/kernel/mpc7450-pmu.c
deleted file mode 100644 (file)
index fe21b51..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Performance counter support for MPC7450-family processors.
- *
- * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/string.h>
-#include <linux/perf_event.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-#define N_COUNTER      6       /* Number of hardware counters */
-#define MAX_ALT                3       /* Maximum number of event alternative codes */
-
-/*
- * Bits in event code for MPC7450 family
- */
-#define PM_THRMULT_MSKS        0x40000
-#define PM_THRESH_SH   12
-#define PM_THRESH_MSK  0x3f
-#define PM_PMC_SH      8
-#define PM_PMC_MSK     7
-#define PM_PMCSEL_MSK  0x7f
-
-/*
- * Classify events according to how specific their PMC requirements are.
- * Result is:
- *     0: can go on any PMC
- *     1: can go on PMCs 1-4
- *     2: can go on PMCs 1,2,4
- *     3: can go on PMCs 1 or 2
- *     4: can only go on one PMC
- *     -1: event code is invalid
- */
-#define N_CLASSES      5
-
-static int mpc7450_classify_event(u32 event)
-{
-       int pmc;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > N_COUNTER)
-                       return -1;
-               return 4;
-       }
-       event &= PM_PMCSEL_MSK;
-       if (event <= 1)
-               return 0;
-       if (event <= 7)
-               return 1;
-       if (event <= 13)
-               return 2;
-       if (event <= 22)
-               return 3;
-       return -1;
-}
-
-/*
- * Events using threshold and possible threshold scale:
- *     code    scale?  name
- *     11e     N       PM_INSTQ_EXCEED_CYC
- *     11f     N       PM_ALTV_IQ_EXCEED_CYC
- *     128     Y       PM_DTLB_SEARCH_EXCEED_CYC
- *     12b     Y       PM_LD_MISS_EXCEED_L1_CYC
- *     220     N       PM_CQ_EXCEED_CYC
- *     30c     N       PM_GPR_RB_EXCEED_CYC
- *     30d     ?       PM_FPR_IQ_EXCEED_CYC ?
- *     311     Y       PM_ITLB_SEARCH_EXCEED
- *     410     N       PM_GPR_IQ_EXCEED_CYC
- */
-
-/*
- * Return use of threshold and threshold scale bits:
- * 0 = uses neither, 1 = uses threshold, 2 = uses both
- */
-static int mpc7450_threshold_use(u32 event)
-{
-       int pmc, sel;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       sel = event & PM_PMCSEL_MSK;
-       switch (pmc) {
-       case 1:
-               if (sel == 0x1e || sel == 0x1f)
-                       return 1;
-               if (sel == 0x28 || sel == 0x2b)
-                       return 2;
-               break;
-       case 2:
-               if (sel == 0x20)
-                       return 1;
-               break;
-       case 3:
-               if (sel == 0xc || sel == 0xd)
-                       return 1;
-               if (sel == 0x11)
-                       return 2;
-               break;
-       case 4:
-               if (sel == 0x10)
-                       return 1;
-               break;
-       }
-       return 0;
-}
-
-/*
- * Layout of constraint bits:
- * 33222222222211111111110000000000
- * 10987654321098765432109876543210
- *  |<    ><  > < > < ><><><><><><>
- *  TS TV   G4   G3  G2P6P5P4P3P2P1
- *
- * P1 - P6
- *     0 - 11: Count of events needing PMC1 .. PMC6
- *
- * G2
- *     12 - 14: Count of events needing PMC1 or PMC2
- *
- * G3
- *     16 - 18: Count of events needing PMC1, PMC2 or PMC4
- *
- * G4
- *     20 - 23: Count of events needing PMC1, PMC2, PMC3 or PMC4
- *
- * TV
- *     24 - 29: Threshold value requested
- *
- * TS
- *     30: Threshold scale value requested
- */
-
-static u32 pmcbits[N_COUNTER][2] = {
-       { 0x00844002, 0x00111001 },     /* PMC1 mask, value: P1,G2,G3,G4 */
-       { 0x00844008, 0x00111004 },     /* PMC2: P2,G2,G3,G4 */
-       { 0x00800020, 0x00100010 },     /* PMC3: P3,G4 */
-       { 0x00840080, 0x00110040 },     /* PMC4: P4,G3,G4 */
-       { 0x00000200, 0x00000100 },     /* PMC5: P5 */
-       { 0x00000800, 0x00000400 }      /* PMC6: P6 */
-};
-
-static u32 classbits[N_CLASSES - 1][2] = {
-       { 0x00000000, 0x00000000 },     /* class 0: no constraint */
-       { 0x00800000, 0x00100000 },     /* class 1: G4 */
-       { 0x00040000, 0x00010000 },     /* class 2: G3 */
-       { 0x00004000, 0x00001000 },     /* class 3: G2 */
-};
-
-static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
-                                 unsigned long *valp)
-{
-       int pmc, class;
-       u32 mask, value;
-       int thresh, tuse;
-
-       class = mpc7450_classify_event(event);
-       if (class < 0)
-               return -1;
-       if (class == 4) {
-               pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
-               mask  = pmcbits[pmc - 1][0];
-               value = pmcbits[pmc - 1][1];
-       } else {
-               mask  = classbits[class][0];
-               value = classbits[class][1];
-       }
-
-       tuse = mpc7450_threshold_use(event);
-       if (tuse) {
-               thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
-               mask  |= 0x3f << 24;
-               value |= thresh << 24;
-               if (tuse == 2) {
-                       mask |= 0x40000000;
-                       if ((unsigned int)event & PM_THRMULT_MSKS)
-                               value |= 0x40000000;
-               }
-       }
-
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-       { 0x217, 0x317 },               /* PM_L1_DCACHE_MISS */
-       { 0x418, 0x50f, 0x60f },        /* PM_SNOOP_RETRY */
-       { 0x502, 0x602 },               /* PM_L2_HIT */
-       { 0x503, 0x603 },               /* PM_L3_HIT */
-       { 0x504, 0x604 },               /* PM_L2_ICACHE_MISS */
-       { 0x505, 0x605 },               /* PM_L3_ICACHE_MISS */
-       { 0x506, 0x606 },               /* PM_L2_DCACHE_MISS */
-       { 0x507, 0x607 },               /* PM_L3_DCACHE_MISS */
-       { 0x50a, 0x623 },               /* PM_LD_HIT_L3 */
-       { 0x50b, 0x624 },               /* PM_ST_HIT_L3 */
-       { 0x50d, 0x60d },               /* PM_L2_TOUCH_HIT */
-       { 0x50e, 0x60e },               /* PM_L3_TOUCH_HIT */
-       { 0x512, 0x612 },               /* PM_INT_LOCAL */
-       { 0x513, 0x61d },               /* PM_L2_MISS */
-       { 0x514, 0x61e },               /* PM_L3_MISS */
-};
-
-/*
- * Scan the alternatives table for a match and return the
- * index into the alternatives table if found, else -1.
- */
-static int find_alternative(u32 event)
-{
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-               if (event < event_alternatives[i][0])
-                       break;
-               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
-                       if (event == event_alternatives[i][j])
-                               return i;
-       }
-       return -1;
-}
-
-static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, nalt = 1;
-       u32 ae;
-
-       alt[0] = event;
-       nalt = 1;
-       i = find_alternative((u32)event);
-       if (i >= 0) {
-               for (j = 0; j < MAX_ALT; ++j) {
-                       ae = event_alternatives[i][j];
-                       if (ae && ae != (u32)event)
-                               alt[nalt++] = ae;
-               }
-       }
-       return nalt;
-}
-
-/*
- * Bitmaps of which PMCs each class can use for classes 0 - 3.
- * Bit i is set if PMC i+1 is usable.
- */
-static const u8 classmap[N_CLASSES] = {
-       0x3f, 0x0f, 0x0b, 0x03, 0
-};
-
-/* Bit position and width of each PMCSEL field */
-static const int pmcsel_shift[N_COUNTER] = {
-       6,      0,      27,     22,     17,     11
-};
-static const u32 pmcsel_mask[N_COUNTER] = {
-       0x7f,   0x3f,   0x1f,   0x1f,   0x1f,   0x3f
-};
-
-/*
- * Compute MMCR0/1/2 values for a set of events.
- */
-static int mpc7450_compute_mmcr(u64 event[], int n_ev,
-                               unsigned int hwc[], unsigned long mmcr[])
-{
-       u8 event_index[N_CLASSES][N_COUNTER];
-       int n_classevent[N_CLASSES];
-       int i, j, class, tuse;
-       u32 pmc_inuse = 0, pmc_avail;
-       u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
-       u32 ev, pmc, thresh;
-
-       if (n_ev > N_COUNTER)
-               return -1;
-
-       /* First pass: count usage in each class */
-       for (i = 0; i < N_CLASSES; ++i)
-               n_classevent[i] = 0;
-       for (i = 0; i < n_ev; ++i) {
-               class = mpc7450_classify_event(event[i]);
-               if (class < 0)
-                       return -1;
-               j = n_classevent[class]++;
-               event_index[class][j] = i;
-       }
-
-       /* Second pass: allocate PMCs from most specific event to least */
-       for (class = N_CLASSES - 1; class >= 0; --class) {
-               for (i = 0; i < n_classevent[class]; ++i) {
-                       ev = event[event_index[class][i]];
-                       if (class == 4) {
-                               pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
-                               if (pmc_inuse & (1 << (pmc - 1)))
-                                       return -1;
-                       } else {
-                               /* Find a suitable PMC */
-                               pmc_avail = classmap[class] & ~pmc_inuse;
-                               if (!pmc_avail)
-                                       return -1;
-                               pmc = ffs(pmc_avail);
-                       }
-                       pmc_inuse |= 1 << (pmc - 1);
-
-                       tuse = mpc7450_threshold_use(ev);
-                       if (tuse) {
-                               thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
-                               mmcr0 |= thresh << 16;
-                               if (tuse == 2 && (ev & PM_THRMULT_MSKS))
-                                       mmcr2 = 0x80000000;
-                       }
-                       ev &= pmcsel_mask[pmc - 1];
-                       ev <<= pmcsel_shift[pmc - 1];
-                       if (pmc <= 2)
-                               mmcr0 |= ev;
-                       else
-                               mmcr1 |= ev;
-                       hwc[event_index[class][i]] = pmc - 1;
-               }
-       }
-
-       if (pmc_inuse & 1)
-               mmcr0 |= MMCR0_PMC1CE;
-       if (pmc_inuse & 0x3e)
-               mmcr0 |= MMCR0_PMCnCE;
-
-       /* Return MMCRx values */
-       mmcr[0] = mmcr0;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcr2;
-       return 0;
-}
-
-/*
- * Disable counting by a PMC.
- * Note that the pmc argument is 0-based here, not 1-based.
- */
-static void mpc7450_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       if (pmc <= 1)
-               mmcr[0] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
-       else
-               mmcr[1] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
-}
-
-static int mpc7450_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 1,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 2,
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x217, /* PM_L1_DCACHE_MISS */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x122, /* PM_BR_CMPL */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x41c, /* PM_BR_MPRED */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x225   },
-               [C(OP_WRITE)] = {       0,              0x227   },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x129,          0x115   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    0x634,          0       },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       0,              0       },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x312   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x223   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x122,          0x41c   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-};
-
-struct power_pmu mpc7450_pmu = {
-       .name                   = "MPC7450 family",
-       .n_counter              = N_COUNTER,
-       .max_alternatives       = MAX_ALT,
-       .add_fields             = 0x00111555ul,
-       .test_adder             = 0x00301000ul,
-       .compute_mmcr           = mpc7450_compute_mmcr,
-       .get_constraint         = mpc7450_get_constraint,
-       .get_alternatives       = mpc7450_get_alternatives,
-       .disable_pmc            = mpc7450_disable_pmc,
-       .n_generic              = ARRAY_SIZE(mpc7450_generic_events),
-       .generic_events         = mpc7450_generic_events,
-       .cache_events           = &mpc7450_cache_events,
-};
-
-static int __init init_mpc7450_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
-               return -ENODEV;
-
-       return register_power_pmu(&mpc7450_pmu);
-}
-
-early_initcall(init_mpc7450_pmu);
index e1612df..2049f2d 100644 (file)
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
+#include <linux/atomic.h>
 
 #include <asm/errno.h>
 #include <asm/topology.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
-#include <linux/atomic.h>
+#include <asm/eeh.h>
 
 #ifdef CONFIG_PPC_OF_PLATFORM_PCI
 
@@ -66,6 +67,9 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev)
        /* Init pci_dn data structures */
        pci_devs_phb_init_dynamic(phb);
 
+       /* Create EEH devices for the PHB */
+       eeh_dev_phb_init_dynamic(phb);
+
        /* Register devices with EEH */
 #ifdef CONFIG_EEH
        if (dev->dev.of_node->child)
index 41456ff..0bb1f98 100644 (file)
 #include <linux/export.h>
 #include <linux/memblock.h>
 
-#include <asm/firmware.h>
 #include <asm/lppaca.h>
 #include <asm/paca.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/iseries/hv_types.h>
 #include <asm/kexec.h>
 
 /* This symbol is provided by the linker - let it fill in the paca
@@ -30,8 +27,8 @@ extern unsigned long __toc_start;
  * The structure which the hypervisor knows about - this structure
  * should not cross a page boundary.  The vpa_init/register_vpa call
  * is now known to fail if the lppaca structure crosses a page
- * boundary.  The lppaca is also used on legacy iSeries and POWER5
- * pSeries boxes.  The lppaca is 640 bytes long, and cannot readily
+ * boundary.  The lppaca is also used on POWER5 pSeries boxes.
+ * The lppaca is 640 bytes long, and cannot readily
  * change since the hypervisor knows its layout, so a 1kB alignment
  * will suffice to ensure that it doesn't cross a page boundary.
  */
@@ -183,12 +180,9 @@ void __init allocate_pacas(void)
        /*
         * We can't take SLB misses on the paca, and we want to access them
         * in real mode, so allocate them within the RMA and also within
-        * the first segment. On iSeries they must be within the area mapped
-        * by the HV, which is HvPagesToMap * HVPAGESIZE bytes.
+        * the first segment.
         */
        limit = min(0x10000000ULL, ppc64_rma_size);
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               limit = min(limit, HvPagesToMap * HVPAGESIZE);
 
        paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
 
index cce98d7..d0373bc 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/byteorder.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
-#include <asm/firmware.h>
 #include <asm/eeh.h>
 
 static DEFINE_SPINLOCK(hose_spinlock);
@@ -219,20 +218,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
        struct of_irq oirq;
        unsigned int virq;
 
-       /* The current device-tree that iSeries generates from the HV
-        * PCI informations doesn't contain proper interrupt routing,
-        * and all the fallback would do is print out crap, so we
-        * don't attempt to resolve the interrupts here at all, some
-        * iSeries specific fixup does it.
-        *
-        * In the long run, we will hopefully fix the generated device-tree
-        * instead.
-        */
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return -1;
-#endif
-
        pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev));
 
 #ifdef DEBUG
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c
deleted file mode 100644 (file)
index 564c1d8..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Performance counter callchain support - powerpc architecture code
- *
- * Copyright Â© 2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/perf_event.h>
-#include <linux/percpu.h>
-#include <linux/uaccess.h>
-#include <linux/mm.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-#include <asm/vdso.h>
-#ifdef CONFIG_PPC64
-#include "ppc32.h"
-#endif
-
-
-/*
- * Is sp valid as the address of the next kernel stack frame after prev_sp?
- * The next frame may be in a different stack area but should not go
- * back down in the same stack area.
- */
-static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
-{
-       if (sp & 0xf)
-               return 0;               /* must be 16-byte aligned */
-       if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
-               return 0;
-       if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
-               return 1;
-       /*
-        * sp could decrease when we jump off an interrupt stack
-        * back to the regular process stack.
-        */
-       if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
-               return 1;
-       return 0;
-}
-
-void
-perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
-       unsigned long sp, next_sp;
-       unsigned long next_ip;
-       unsigned long lr;
-       long level = 0;
-       unsigned long *fp;
-
-       lr = regs->link;
-       sp = regs->gpr[1];
-       perf_callchain_store(entry, regs->nip);
-
-       if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
-               return;
-
-       for (;;) {
-               fp = (unsigned long *) sp;
-               next_sp = fp[0];
-
-               if (next_sp == sp + STACK_INT_FRAME_SIZE &&
-                   fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
-                       /*
-                        * This looks like an interrupt frame for an
-                        * interrupt that occurred in the kernel
-                        */
-                       regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
-                       next_ip = regs->nip;
-                       lr = regs->link;
-                       level = 0;
-                       perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
-
-               } else {
-                       if (level == 0)
-                               next_ip = lr;
-                       else
-                               next_ip = fp[STACK_FRAME_LR_SAVE];
-
-                       /*
-                        * We can't tell which of the first two addresses
-                        * we get are valid, but we can filter out the
-                        * obviously bogus ones here.  We replace them
-                        * with 0 rather than removing them entirely so
-                        * that userspace can tell which is which.
-                        */
-                       if ((level == 1 && next_ip == lr) ||
-                           (level <= 1 && !kernel_text_address(next_ip)))
-                               next_ip = 0;
-
-                       ++level;
-               }
-
-               perf_callchain_store(entry, next_ip);
-               if (!valid_next_sp(next_sp, sp))
-                       return;
-               sp = next_sp;
-       }
-}
-
-#ifdef CONFIG_PPC64
-/*
- * On 64-bit we don't want to invoke hash_page on user addresses from
- * interrupt context, so if the access faults, we read the page tables
- * to find which page (if any) is mapped and access it directly.
- */
-static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
-{
-       pgd_t *pgdir;
-       pte_t *ptep, pte;
-       unsigned shift;
-       unsigned long addr = (unsigned long) ptr;
-       unsigned long offset;
-       unsigned long pfn;
-       void *kaddr;
-
-       pgdir = current->mm->pgd;
-       if (!pgdir)
-               return -EFAULT;
-
-       ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
-       if (!shift)
-               shift = PAGE_SHIFT;
-
-       /* align address to page boundary */
-       offset = addr & ((1UL << shift) - 1);
-       addr -= offset;
-
-       if (ptep == NULL)
-               return -EFAULT;
-       pte = *ptep;
-       if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
-               return -EFAULT;
-       pfn = pte_pfn(pte);
-       if (!page_is_ram(pfn))
-               return -EFAULT;
-
-       /* no highmem to worry about here */
-       kaddr = pfn_to_kaddr(pfn);
-       memcpy(ret, kaddr + offset, nb);
-       return 0;
-}
-
-static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
-{
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
-           ((unsigned long)ptr & 7))
-               return -EFAULT;
-
-       pagefault_disable();
-       if (!__get_user_inatomic(*ret, ptr)) {
-               pagefault_enable();
-               return 0;
-       }
-       pagefault_enable();
-
-       return read_user_stack_slow(ptr, ret, 8);
-}
-
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-           ((unsigned long)ptr & 3))
-               return -EFAULT;
-
-       pagefault_disable();
-       if (!__get_user_inatomic(*ret, ptr)) {
-               pagefault_enable();
-               return 0;
-       }
-       pagefault_enable();
-
-       return read_user_stack_slow(ptr, ret, 4);
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-       if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
-               return 0;
-       return 1;
-}
-
-/*
- * 64-bit user processes use the same stack frame for RT and non-RT signals.
- */
-struct signal_frame_64 {
-       char            dummy[__SIGNAL_FRAMESIZE];
-       struct ucontext uc;
-       unsigned long   unused[2];
-       unsigned int    tramp[6];
-       struct siginfo  *pinfo;
-       void            *puc;
-       struct siginfo  info;
-       char            abigap[288];
-};
-
-static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
-{
-       if (nip == fp + offsetof(struct signal_frame_64, tramp))
-               return 1;
-       if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
-               return 1;
-       return 0;
-}
-
-/*
- * Do some sanity checking on the signal frame pointed to by sp.
- * We check the pinfo and puc pointers in the frame.
- */
-static int sane_signal_64_frame(unsigned long sp)
-{
-       struct signal_frame_64 __user *sf;
-       unsigned long pinfo, puc;
-
-       sf = (struct signal_frame_64 __user *) sp;
-       if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
-           read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
-               return 0;
-       return pinfo == (unsigned long) &sf->info &&
-               puc == (unsigned long) &sf->uc;
-}
-
-static void perf_callchain_user_64(struct perf_callchain_entry *entry,
-                                  struct pt_regs *regs)
-{
-       unsigned long sp, next_sp;
-       unsigned long next_ip;
-       unsigned long lr;
-       long level = 0;
-       struct signal_frame_64 __user *sigframe;
-       unsigned long __user *fp, *uregs;
-
-       next_ip = regs->nip;
-       lr = regs->link;
-       sp = regs->gpr[1];
-       perf_callchain_store(entry, next_ip);
-
-       for (;;) {
-               fp = (unsigned long __user *) sp;
-               if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
-                       return;
-               if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
-                       return;
-
-               /*
-                * Note: the next_sp - sp >= signal frame size check
-                * is true when next_sp < sp, which can happen when
-                * transitioning from an alternate signal stack to the
-                * normal stack.
-                */
-               if (next_sp - sp >= sizeof(struct signal_frame_64) &&
-                   (is_sigreturn_64_address(next_ip, sp) ||
-                    (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
-                   sane_signal_64_frame(sp)) {
-                       /*
-                        * This looks like an signal frame
-                        */
-                       sigframe = (struct signal_frame_64 __user *) sp;
-                       uregs = sigframe->uc.uc_mcontext.gp_regs;
-                       if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
-                           read_user_stack_64(&uregs[PT_LNK], &lr) ||
-                           read_user_stack_64(&uregs[PT_R1], &sp))
-                               return;
-                       level = 0;
-                       perf_callchain_store(entry, PERF_CONTEXT_USER);
-                       perf_callchain_store(entry, next_ip);
-                       continue;
-               }
-
-               if (level == 0)
-                       next_ip = lr;
-               perf_callchain_store(entry, next_ip);
-               ++level;
-               sp = next_sp;
-       }
-}
-
-static inline int current_is_64bit(void)
-{
-       /*
-        * We can't use test_thread_flag() here because we may be on an
-        * interrupt stack, and the thread flags don't get copied over
-        * from the thread_info on the main stack to the interrupt stack.
-        */
-       return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
-}
-
-#else  /* CONFIG_PPC64 */
-/*
- * On 32-bit we just access the address and let hash_page create a
- * HPTE if necessary, so there is no need to fall back to reading
- * the page tables.  Since this is called at interrupt level,
- * do_page_fault() won't treat a DSI as a page fault.
- */
-static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
-{
-       int rc;
-
-       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
-           ((unsigned long)ptr & 3))
-               return -EFAULT;
-
-       pagefault_disable();
-       rc = __get_user_inatomic(*ret, ptr);
-       pagefault_enable();
-
-       return rc;
-}
-
-static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
-                                         struct pt_regs *regs)
-{
-}
-
-static inline int current_is_64bit(void)
-{
-       return 0;
-}
-
-static inline int valid_user_sp(unsigned long sp, int is_64)
-{
-       if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
-               return 0;
-       return 1;
-}
-
-#define __SIGNAL_FRAMESIZE32   __SIGNAL_FRAMESIZE
-#define sigcontext32           sigcontext
-#define mcontext32             mcontext
-#define ucontext32             ucontext
-#define compat_siginfo_t       struct siginfo
-
-#endif /* CONFIG_PPC64 */
-
-/*
- * Layout for non-RT signal frames
- */
-struct signal_frame_32 {
-       char                    dummy[__SIGNAL_FRAMESIZE32];
-       struct sigcontext32     sctx;
-       struct mcontext32       mctx;
-       int                     abigap[56];
-};
-
-/*
- * Layout for RT signal frames
- */
-struct rt_signal_frame_32 {
-       char                    dummy[__SIGNAL_FRAMESIZE32 + 16];
-       compat_siginfo_t        info;
-       struct ucontext32       uc;
-       int                     abigap[56];
-};
-
-static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-       if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
-               return 1;
-       if (vdso32_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso32_sigtramp)
-               return 1;
-       return 0;
-}
-
-static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
-{
-       if (nip == fp + offsetof(struct rt_signal_frame_32,
-                                uc.uc_mcontext.mc_pad))
-               return 1;
-       if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
-           nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
-               return 1;
-       return 0;
-}
-
-static int sane_signal_32_frame(unsigned int sp)
-{
-       struct signal_frame_32 __user *sf;
-       unsigned int regs;
-
-       sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-       if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
-               return 0;
-       return regs == (unsigned long) &sf->mctx;
-}
-
-static int sane_rt_signal_32_frame(unsigned int sp)
-{
-       struct rt_signal_frame_32 __user *sf;
-       unsigned int regs;
-
-       sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-       if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
-               return 0;
-       return regs == (unsigned long) &sf->uc.uc_mcontext;
-}
-
-static unsigned int __user *signal_frame_32_regs(unsigned int sp,
-                               unsigned int next_sp, unsigned int next_ip)
-{
-       struct mcontext32 __user *mctx = NULL;
-       struct signal_frame_32 __user *sf;
-       struct rt_signal_frame_32 __user *rt_sf;
-
-       /*
-        * Note: the next_sp - sp >= signal frame size check
-        * is true when next_sp < sp, for example, when
-        * transitioning from an alternate signal stack to the
-        * normal stack.
-        */
-       if (next_sp - sp >= sizeof(struct signal_frame_32) &&
-           is_sigreturn_32_address(next_ip, sp) &&
-           sane_signal_32_frame(sp)) {
-               sf = (struct signal_frame_32 __user *) (unsigned long) sp;
-               mctx = &sf->mctx;
-       }
-
-       if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
-           is_rt_sigreturn_32_address(next_ip, sp) &&
-           sane_rt_signal_32_frame(sp)) {
-               rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
-               mctx = &rt_sf->uc.uc_mcontext;
-       }
-
-       if (!mctx)
-               return NULL;
-       return mctx->mc_gregs;
-}
-
-static void perf_callchain_user_32(struct perf_callchain_entry *entry,
-                                  struct pt_regs *regs)
-{
-       unsigned int sp, next_sp;
-       unsigned int next_ip;
-       unsigned int lr;
-       long level = 0;
-       unsigned int __user *fp, *uregs;
-
-       next_ip = regs->nip;
-       lr = regs->link;
-       sp = regs->gpr[1];
-       perf_callchain_store(entry, next_ip);
-
-       while (entry->nr < PERF_MAX_STACK_DEPTH) {
-               fp = (unsigned int __user *) (unsigned long) sp;
-               if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
-                       return;
-               if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
-                       return;
-
-               uregs = signal_frame_32_regs(sp, next_sp, next_ip);
-               if (!uregs && level <= 1)
-                       uregs = signal_frame_32_regs(sp, next_sp, lr);
-               if (uregs) {
-                       /*
-                        * This looks like an signal frame, so restart
-                        * the stack trace with the values in it.
-                        */
-                       if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
-                           read_user_stack_32(&uregs[PT_LNK], &lr) ||
-                           read_user_stack_32(&uregs[PT_R1], &sp))
-                               return;
-                       level = 0;
-                       perf_callchain_store(entry, PERF_CONTEXT_USER);
-                       perf_callchain_store(entry, next_ip);
-                       continue;
-               }
-
-               if (level == 0)
-                       next_ip = lr;
-               perf_callchain_store(entry, next_ip);
-               ++level;
-               sp = next_sp;
-       }
-}
-
-void
-perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
-       if (current_is_64bit())
-               perf_callchain_user_64(entry, regs);
-       else
-               perf_callchain_user_32(entry, regs);
-}
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
deleted file mode 100644 (file)
index c2e27ed..0000000
+++ /dev/null
@@ -1,1448 +0,0 @@
-/*
- * Performance event support - powerpc architecture code
- *
- * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/perf_event.h>
-#include <linux/percpu.h>
-#include <linux/hardirq.h>
-#include <asm/reg.h>
-#include <asm/pmc.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/ptrace.h>
-
-struct cpu_hw_events {
-       int n_events;
-       int n_percpu;
-       int disabled;
-       int n_added;
-       int n_limited;
-       u8  pmcs_enabled;
-       struct perf_event *event[MAX_HWEVENTS];
-       u64 events[MAX_HWEVENTS];
-       unsigned int flags[MAX_HWEVENTS];
-       unsigned long mmcr[3];
-       struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
-       u8  limited_hwidx[MAX_LIMITED_HWCOUNTERS];
-       u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-       unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-       unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
-
-       unsigned int group_flag;
-       int n_txn_start;
-};
-DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
-
-struct power_pmu *ppmu;
-
-/*
- * Normally, to ignore kernel events we set the FCS (freeze counters
- * in supervisor mode) bit in MMCR0, but if the kernel runs with the
- * hypervisor bit set in the MSR, or if we are running on a processor
- * where the hypervisor bit is forced to 1 (as on Apple G5 processors),
- * then we need to use the FCHV bit to ignore kernel events.
- */
-static unsigned int freeze_events_kernel = MMCR0_FCS;
-
-/*
- * 32-bit doesn't have MMCRA but does have an MMCR2,
- * and a few other names are different.
- */
-#ifdef CONFIG_PPC32
-
-#define MMCR0_FCHV             0
-#define MMCR0_PMCjCE           MMCR0_PMCnCE
-
-#define SPRN_MMCRA             SPRN_MMCR2
-#define MMCRA_SAMPLE_ENABLE    0
-
-static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
-{
-       return 0;
-}
-static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
-static inline u32 perf_get_misc_flags(struct pt_regs *regs)
-{
-       return 0;
-}
-static inline void perf_read_regs(struct pt_regs *regs) { }
-static inline int perf_intr_is_nmi(struct pt_regs *regs)
-{
-       return 0;
-}
-
-#endif /* CONFIG_PPC32 */
-
-/*
- * Things that are specific to 64-bit implementations.
- */
-#ifdef CONFIG_PPC64
-
-static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
-{
-       unsigned long mmcra = regs->dsisr;
-
-       if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
-               unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
-               if (slot > 1)
-                       return 4 * (slot - 1);
-       }
-       return 0;
-}
-
-/*
- * The user wants a data address recorded.
- * If we're not doing instruction sampling, give them the SDAR
- * (sampled data address).  If we are doing instruction sampling, then
- * only give them the SDAR if it corresponds to the instruction
- * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
- * bit in MMCRA.
- */
-static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
-{
-       unsigned long mmcra = regs->dsisr;
-       unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
-               POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
-
-       if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
-               *addrp = mfspr(SPRN_SDAR);
-}
-
-static inline u32 perf_get_misc_flags(struct pt_regs *regs)
-{
-       unsigned long mmcra = regs->dsisr;
-       unsigned long sihv = MMCRA_SIHV;
-       unsigned long sipr = MMCRA_SIPR;
-
-       if (TRAP(regs) != 0xf00)
-               return 0;       /* not a PMU interrupt */
-
-       if (ppmu->flags & PPMU_ALT_SIPR) {
-               sihv = POWER6_MMCRA_SIHV;
-               sipr = POWER6_MMCRA_SIPR;
-       }
-
-       /* PR has priority over HV, so order below is important */
-       if (mmcra & sipr)
-               return PERF_RECORD_MISC_USER;
-       if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
-               return PERF_RECORD_MISC_HYPERVISOR;
-       return PERF_RECORD_MISC_KERNEL;
-}
-
-/*
- * Overload regs->dsisr to store MMCRA so we only need to read it once
- * on each interrupt.
- */
-static inline void perf_read_regs(struct pt_regs *regs)
-{
-       regs->dsisr = mfspr(SPRN_MMCRA);
-}
-
-/*
- * If interrupts were soft-disabled when a PMU interrupt occurs, treat
- * it as an NMI.
- */
-static inline int perf_intr_is_nmi(struct pt_regs *regs)
-{
-       return !regs->softe;
-}
-
-#endif /* CONFIG_PPC64 */
-
-static void perf_event_interrupt(struct pt_regs *regs);
-
-void perf_event_print_debug(void)
-{
-}
-
-/*
- * Read one performance monitor counter (PMC).
- */
-static unsigned long read_pmc(int idx)
-{
-       unsigned long val;
-
-       switch (idx) {
-       case 1:
-               val = mfspr(SPRN_PMC1);
-               break;
-       case 2:
-               val = mfspr(SPRN_PMC2);
-               break;
-       case 3:
-               val = mfspr(SPRN_PMC3);
-               break;
-       case 4:
-               val = mfspr(SPRN_PMC4);
-               break;
-       case 5:
-               val = mfspr(SPRN_PMC5);
-               break;
-       case 6:
-               val = mfspr(SPRN_PMC6);
-               break;
-#ifdef CONFIG_PPC64
-       case 7:
-               val = mfspr(SPRN_PMC7);
-               break;
-       case 8:
-               val = mfspr(SPRN_PMC8);
-               break;
-#endif /* CONFIG_PPC64 */
-       default:
-               printk(KERN_ERR "oops trying to read PMC%d\n", idx);
-               val = 0;
-       }
-       return val;
-}
-
-/*
- * Write one PMC.
- */
-static void write_pmc(int idx, unsigned long val)
-{
-       switch (idx) {
-       case 1:
-               mtspr(SPRN_PMC1, val);
-               break;
-       case 2:
-               mtspr(SPRN_PMC2, val);
-               break;
-       case 3:
-               mtspr(SPRN_PMC3, val);
-               break;
-       case 4:
-               mtspr(SPRN_PMC4, val);
-               break;
-       case 5:
-               mtspr(SPRN_PMC5, val);
-               break;
-       case 6:
-               mtspr(SPRN_PMC6, val);
-               break;
-#ifdef CONFIG_PPC64
-       case 7:
-               mtspr(SPRN_PMC7, val);
-               break;
-       case 8:
-               mtspr(SPRN_PMC8, val);
-               break;
-#endif /* CONFIG_PPC64 */
-       default:
-               printk(KERN_ERR "oops trying to write PMC%d\n", idx);
-       }
-}
-
-/*
- * Check if a set of events can all go on the PMU at once.
- * If they can't, this will look at alternative codes for the events
- * and see if any combination of alternative codes is feasible.
- * The feasible set is returned in event_id[].
- */
-static int power_check_constraints(struct cpu_hw_events *cpuhw,
-                                  u64 event_id[], unsigned int cflags[],
-                                  int n_ev)
-{
-       unsigned long mask, value, nv;
-       unsigned long smasks[MAX_HWEVENTS], svalues[MAX_HWEVENTS];
-       int n_alt[MAX_HWEVENTS], choice[MAX_HWEVENTS];
-       int i, j;
-       unsigned long addf = ppmu->add_fields;
-       unsigned long tadd = ppmu->test_adder;
-
-       if (n_ev > ppmu->n_counter)
-               return -1;
-
-       /* First see if the events will go on as-is */
-       for (i = 0; i < n_ev; ++i) {
-               if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
-                   && !ppmu->limited_pmc_event(event_id[i])) {
-                       ppmu->get_alternatives(event_id[i], cflags[i],
-                                              cpuhw->alternatives[i]);
-                       event_id[i] = cpuhw->alternatives[i][0];
-               }
-               if (ppmu->get_constraint(event_id[i], &cpuhw->amasks[i][0],
-                                        &cpuhw->avalues[i][0]))
-                       return -1;
-       }
-       value = mask = 0;
-       for (i = 0; i < n_ev; ++i) {
-               nv = (value | cpuhw->avalues[i][0]) +
-                       (value & cpuhw->avalues[i][0] & addf);
-               if ((((nv + tadd) ^ value) & mask) != 0 ||
-                   (((nv + tadd) ^ cpuhw->avalues[i][0]) &
-                    cpuhw->amasks[i][0]) != 0)
-                       break;
-               value = nv;
-               mask |= cpuhw->amasks[i][0];
-       }
-       if (i == n_ev)
-               return 0;       /* all OK */
-
-       /* doesn't work, gather alternatives... */
-       if (!ppmu->get_alternatives)
-               return -1;
-       for (i = 0; i < n_ev; ++i) {
-               choice[i] = 0;
-               n_alt[i] = ppmu->get_alternatives(event_id[i], cflags[i],
-                                                 cpuhw->alternatives[i]);
-               for (j = 1; j < n_alt[i]; ++j)
-                       ppmu->get_constraint(cpuhw->alternatives[i][j],
-                                            &cpuhw->amasks[i][j],
-                                            &cpuhw->avalues[i][j]);
-       }
-
-       /* enumerate all possibilities and see if any will work */
-       i = 0;
-       j = -1;
-       value = mask = nv = 0;
-       while (i < n_ev) {
-               if (j >= 0) {
-                       /* we're backtracking, restore context */
-                       value = svalues[i];
-                       mask = smasks[i];
-                       j = choice[i];
-               }
-               /*
-                * See if any alternative k for event_id i,
-                * where k > j, will satisfy the constraints.
-                */
-               while (++j < n_alt[i]) {
-                       nv = (value | cpuhw->avalues[i][j]) +
-                               (value & cpuhw->avalues[i][j] & addf);
-                       if ((((nv + tadd) ^ value) & mask) == 0 &&
-                           (((nv + tadd) ^ cpuhw->avalues[i][j])
-                            & cpuhw->amasks[i][j]) == 0)
-                               break;
-               }
-               if (j >= n_alt[i]) {
-                       /*
-                        * No feasible alternative, backtrack
-                        * to event_id i-1 and continue enumerating its
-                        * alternatives from where we got up to.
-                        */
-                       if (--i < 0)
-                               return -1;
-               } else {
-                       /*
-                        * Found a feasible alternative for event_id i,
-                        * remember where we got up to with this event_id,
-                        * go on to the next event_id, and start with
-                        * the first alternative for it.
-                        */
-                       choice[i] = j;
-                       svalues[i] = value;
-                       smasks[i] = mask;
-                       value = nv;
-                       mask |= cpuhw->amasks[i][j];
-                       ++i;
-                       j = -1;
-               }
-       }
-
-       /* OK, we have a feasible combination, tell the caller the solution */
-       for (i = 0; i < n_ev; ++i)
-               event_id[i] = cpuhw->alternatives[i][choice[i]];
-       return 0;
-}
-
-/*
- * Check if newly-added events have consistent settings for
- * exclude_{user,kernel,hv} with each other and any previously
- * added events.
- */
-static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
-                         int n_prev, int n_new)
-{
-       int eu = 0, ek = 0, eh = 0;
-       int i, n, first;
-       struct perf_event *event;
-
-       n = n_prev + n_new;
-       if (n <= 1)
-               return 0;
-
-       first = 1;
-       for (i = 0; i < n; ++i) {
-               if (cflags[i] & PPMU_LIMITED_PMC_OK) {
-                       cflags[i] &= ~PPMU_LIMITED_PMC_REQD;
-                       continue;
-               }
-               event = ctrs[i];
-               if (first) {
-                       eu = event->attr.exclude_user;
-                       ek = event->attr.exclude_kernel;
-                       eh = event->attr.exclude_hv;
-                       first = 0;
-               } else if (event->attr.exclude_user != eu ||
-                          event->attr.exclude_kernel != ek ||
-                          event->attr.exclude_hv != eh) {
-                       return -EAGAIN;
-               }
-       }
-
-       if (eu || ek || eh)
-               for (i = 0; i < n; ++i)
-                       if (cflags[i] & PPMU_LIMITED_PMC_OK)
-                               cflags[i] |= PPMU_LIMITED_PMC_REQD;
-
-       return 0;
-}
-
-static u64 check_and_compute_delta(u64 prev, u64 val)
-{
-       u64 delta = (val - prev) & 0xfffffffful;
-
-       /*
-        * POWER7 can roll back counter values, if the new value is smaller
-        * than the previous value it will cause the delta and the counter to
-        * have bogus values unless we rolled a counter over.  If a coutner is
-        * rolled back, it will be smaller, but within 256, which is the maximum
-        * number of events to rollback at once.  If we dectect a rollback
-        * return 0.  This can lead to a small lack of precision in the
-        * counters.
-        */
-       if (prev > val && (prev - val) < 256)
-               delta = 0;
-
-       return delta;
-}
-
-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;
-       /*
-        * Performance monitor interrupts come even when interrupts
-        * are soft-disabled, as long as interrupts are hard-enabled.
-        * Therefore we treat them like NMIs.
-        */
-       do {
-               prev = local64_read(&event->hw.prev_count);
-               barrier();
-               val = read_pmc(event->hw.idx);
-               delta = check_and_compute_delta(prev, val);
-               if (!delta)
-                       return;
-       } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
-
-       local64_add(delta, &event->count);
-       local64_sub(delta, &event->hw.period_left);
-}
-
-/*
- * On some machines, PMC5 and PMC6 can't be written, don't respect
- * the freeze conditions, and don't generate interrupts.  This tells
- * us if `event' is using such a PMC.
- */
-static int is_limited_pmc(int pmcnum)
-{
-       return (ppmu->flags & PPMU_LIMITED_PMC5_6)
-               && (pmcnum == 5 || pmcnum == 6);
-}
-
-static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
-                                   unsigned long pmc5, unsigned long pmc6)
-{
-       struct perf_event *event;
-       u64 val, prev, delta;
-       int i;
-
-       for (i = 0; i < cpuhw->n_limited; ++i) {
-               event = cpuhw->limited_counter[i];
-               if (!event->hw.idx)
-                       continue;
-               val = (event->hw.idx == 5) ? pmc5 : pmc6;
-               prev = local64_read(&event->hw.prev_count);
-               event->hw.idx = 0;
-               delta = check_and_compute_delta(prev, val);
-               if (delta)
-                       local64_add(delta, &event->count);
-       }
-}
-
-static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
-                                 unsigned long pmc5, unsigned long pmc6)
-{
-       struct perf_event *event;
-       u64 val, prev;
-       int i;
-
-       for (i = 0; i < cpuhw->n_limited; ++i) {
-               event = cpuhw->limited_counter[i];
-               event->hw.idx = cpuhw->limited_hwidx[i];
-               val = (event->hw.idx == 5) ? pmc5 : pmc6;
-               prev = local64_read(&event->hw.prev_count);
-               if (check_and_compute_delta(prev, val))
-                       local64_set(&event->hw.prev_count, val);
-               perf_event_update_userpage(event);
-       }
-}
-
-/*
- * Since limited events don't respect the freeze conditions, we
- * have to read them immediately after freezing or unfreezing the
- * other events.  We try to keep the values from the limited
- * events as consistent as possible by keeping the delay (in
- * cycles and instructions) between freezing/unfreezing and reading
- * the limited events as small and consistent as possible.
- * Therefore, if any limited events are in use, we read them
- * both, and always in the same order, to minimize variability,
- * and do it inside the same asm that writes MMCR0.
- */
-static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
-{
-       unsigned long pmc5, pmc6;
-
-       if (!cpuhw->n_limited) {
-               mtspr(SPRN_MMCR0, mmcr0);
-               return;
-       }
-
-       /*
-        * Write MMCR0, then read PMC5 and PMC6 immediately.
-        * To ensure we don't get a performance monitor interrupt
-        * between writing MMCR0 and freezing/thawing the limited
-        * events, we first write MMCR0 with the event overflow
-        * interrupt enable bits turned off.
-        */
-       asm volatile("mtspr %3,%2; mfspr %0,%4; mfspr %1,%5"
-                    : "=&r" (pmc5), "=&r" (pmc6)
-                    : "r" (mmcr0 & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)),
-                      "i" (SPRN_MMCR0),
-                      "i" (SPRN_PMC5), "i" (SPRN_PMC6));
-
-       if (mmcr0 & MMCR0_FC)
-               freeze_limited_counters(cpuhw, pmc5, pmc6);
-       else
-               thaw_limited_counters(cpuhw, pmc5, pmc6);
-
-       /*
-        * Write the full MMCR0 including the event overflow interrupt
-        * enable bits, if necessary.
-        */
-       if (mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE))
-               mtspr(SPRN_MMCR0, mmcr0);
-}
-
-/*
- * Disable all events to prevent PMU interrupts and to allow
- * events to be added or removed.
- */
-static void power_pmu_disable(struct pmu *pmu)
-{
-       struct cpu_hw_events *cpuhw;
-       unsigned long flags;
-
-       if (!ppmu)
-               return;
-       local_irq_save(flags);
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-
-       if (!cpuhw->disabled) {
-               cpuhw->disabled = 1;
-               cpuhw->n_added = 0;
-
-               /*
-                * Check if we ever enabled the PMU on this cpu.
-                */
-               if (!cpuhw->pmcs_enabled) {
-                       ppc_enable_pmcs();
-                       cpuhw->pmcs_enabled = 1;
-               }
-
-               /*
-                * Disable instruction sampling if it was enabled
-                */
-               if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
-                       mtspr(SPRN_MMCRA,
-                             cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-                       mb();
-               }
-
-               /*
-                * Set the 'freeze counters' bit.
-                * The barrier is to make sure the mtspr has been
-                * executed and the PMU has frozen the events
-                * before we return.
-                */
-               write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
-               mb();
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * Re-enable all events if disable == 0.
- * If we were previously disabled and events were added, then
- * put the new config on the PMU.
- */
-static void power_pmu_enable(struct pmu *pmu)
-{
-       struct perf_event *event;
-       struct cpu_hw_events *cpuhw;
-       unsigned long flags;
-       long i;
-       unsigned long val;
-       s64 left;
-       unsigned int hwc_index[MAX_HWEVENTS];
-       int n_lim;
-       int idx;
-
-       if (!ppmu)
-               return;
-       local_irq_save(flags);
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-       if (!cpuhw->disabled) {
-               local_irq_restore(flags);
-               return;
-       }
-       cpuhw->disabled = 0;
-
-       /*
-        * If we didn't change anything, or only removed events,
-        * no need to recalculate MMCR* settings and reset the PMCs.
-        * Just reenable the PMU with the current MMCR* settings
-        * (possibly updated for removal of events).
-        */
-       if (!cpuhw->n_added) {
-               mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-               mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
-               if (cpuhw->n_events == 0)
-                       ppc_set_pmu_inuse(0);
-               goto out_enable;
-       }
-
-       /*
-        * Compute MMCR* values for the new set of events
-        */
-       if (ppmu->compute_mmcr(cpuhw->events, cpuhw->n_events, hwc_index,
-                              cpuhw->mmcr)) {
-               /* shouldn't ever get here */
-               printk(KERN_ERR "oops compute_mmcr failed\n");
-               goto out;
-       }
-
-       /*
-        * Add in MMCR0 freeze bits corresponding to the
-        * attr.exclude_* bits for the first event.
-        * We have already checked that all events have the
-        * same values for these bits as the first event.
-        */
-       event = cpuhw->event[0];
-       if (event->attr.exclude_user)
-               cpuhw->mmcr[0] |= MMCR0_FCP;
-       if (event->attr.exclude_kernel)
-               cpuhw->mmcr[0] |= freeze_events_kernel;
-       if (event->attr.exclude_hv)
-               cpuhw->mmcr[0] |= MMCR0_FCHV;
-
-       /*
-        * Write the new configuration to MMCR* with the freeze
-        * bit set and set the hardware events to their initial values.
-        * Then unfreeze the events.
-        */
-       ppc_set_pmu_inuse(1);
-       mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
-       mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
-       mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
-                               | MMCR0_FC);
-
-       /*
-        * Read off any pre-existing events that need to move
-        * to another PMC.
-        */
-       for (i = 0; i < cpuhw->n_events; ++i) {
-               event = cpuhw->event[i];
-               if (event->hw.idx && event->hw.idx != hwc_index[i] + 1) {
-                       power_pmu_read(event);
-                       write_pmc(event->hw.idx, 0);
-                       event->hw.idx = 0;
-               }
-       }
-
-       /*
-        * Initialize the PMCs for all the new and moved events.
-        */
-       cpuhw->n_limited = n_lim = 0;
-       for (i = 0; i < cpuhw->n_events; ++i) {
-               event = cpuhw->event[i];
-               if (event->hw.idx)
-                       continue;
-               idx = hwc_index[i] + 1;
-               if (is_limited_pmc(idx)) {
-                       cpuhw->limited_counter[n_lim] = event;
-                       cpuhw->limited_hwidx[n_lim] = idx;
-                       ++n_lim;
-                       continue;
-               }
-               val = 0;
-               if (event->hw.sample_period) {
-                       left = local64_read(&event->hw.period_left);
-                       if (left < 0x80000000L)
-                               val = 0x80000000L - left;
-               }
-               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);
-       }
-       cpuhw->n_limited = n_lim;
-       cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
-
- out_enable:
-       mb();
-       write_mmcr0(cpuhw, cpuhw->mmcr[0]);
-
-       /*
-        * Enable instruction sampling if necessary
-        */
-       if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
-               mb();
-               mtspr(SPRN_MMCRA, cpuhw->mmcr[2]);
-       }
-
- out:
-       local_irq_restore(flags);
-}
-
-static int collect_events(struct perf_event *group, int max_count,
-                         struct perf_event *ctrs[], u64 *events,
-                         unsigned int *flags)
-{
-       int n = 0;
-       struct perf_event *event;
-
-       if (!is_software_event(group)) {
-               if (n >= max_count)
-                       return -1;
-               ctrs[n] = group;
-               flags[n] = group->hw.event_base;
-               events[n++] = group->hw.config;
-       }
-       list_for_each_entry(event, &group->sibling_list, group_entry) {
-               if (!is_software_event(event) &&
-                   event->state != PERF_EVENT_STATE_OFF) {
-                       if (n >= max_count)
-                               return -1;
-                       ctrs[n] = event;
-                       flags[n] = event->hw.event_base;
-                       events[n++] = event->hw.config;
-               }
-       }
-       return n;
-}
-
-/*
- * Add a event to the PMU.
- * If all events are not already frozen, then we disable and
- * re-enable the PMU in order to get hw_perf_enable to do the
- * actual work of reconfiguring the PMU.
- */
-static int power_pmu_add(struct perf_event *event, int ef_flags)
-{
-       struct cpu_hw_events *cpuhw;
-       unsigned long flags;
-       int n0;
-       int ret = -EAGAIN;
-
-       local_irq_save(flags);
-       perf_pmu_disable(event->pmu);
-
-       /*
-        * Add the event to the list (if there is room)
-        * and check whether the total set is still feasible.
-        */
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-       n0 = cpuhw->n_events;
-       if (n0 >= ppmu->n_counter)
-               goto out;
-       cpuhw->event[n0] = 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 performed
-        * at commit time(->commit_txn) as a whole
-        */
-       if (cpuhw->group_flag & PERF_EVENT_TXN)
-               goto nocheck;
-
-       if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
-               goto out;
-       if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
-               goto out;
-       event->hw.config = cpuhw->events[n0];
-
-nocheck:
-       ++cpuhw->n_events;
-       ++cpuhw->n_added;
-
-       ret = 0;
- out:
-       perf_pmu_enable(event->pmu);
-       local_irq_restore(flags);
-       return ret;
-}
-
-/*
- * Remove a event from the PMU.
- */
-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_pmu_disable(event->pmu);
-
-       power_pmu_read(event);
-
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-       for (i = 0; i < cpuhw->n_events; ++i) {
-               if (event == cpuhw->event[i]) {
-                       while (++i < cpuhw->n_events) {
-                               cpuhw->event[i-1] = cpuhw->event[i];
-                               cpuhw->events[i-1] = cpuhw->events[i];
-                               cpuhw->flags[i-1] = cpuhw->flags[i];
-                       }
-                       --cpuhw->n_events;
-                       ppmu->disable_pmc(event->hw.idx - 1, cpuhw->mmcr);
-                       if (event->hw.idx) {
-                               write_pmc(event->hw.idx, 0);
-                               event->hw.idx = 0;
-                       }
-                       perf_event_update_userpage(event);
-                       break;
-               }
-       }
-       for (i = 0; i < cpuhw->n_limited; ++i)
-               if (event == cpuhw->limited_counter[i])
-                       break;
-       if (i < cpuhw->n_limited) {
-               while (++i < cpuhw->n_limited) {
-                       cpuhw->limited_counter[i-1] = cpuhw->limited_counter[i];
-                       cpuhw->limited_hwidx[i-1] = cpuhw->limited_hwidx[i];
-               }
-               --cpuhw->n_limited;
-       }
-       if (cpuhw->n_events == 0) {
-               /* disable exceptions if no events are running */
-               cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
-       }
-
-       perf_pmu_enable(event->pmu);
-       local_irq_restore(flags);
-}
-
-/*
- * 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_start(struct perf_event *event, int ef_flags)
-{
-       unsigned long flags;
-       s64 left;
-       unsigned long val;
-
-       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);
-
-       val = 0;
-       if (left < 0x80000000L)
-               val = 0x80000000L - left;
-
-       write_pmc(event->hw.idx, val);
-
-       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)
-{
-       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_pmu_disable(event->pmu);
-
-       power_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);
-}
-
-/*
- * Start group events scheduling transaction
- * Set the flag to make pmu::enable() not perform the
- * schedulability test, it will be performed at commit time
- */
-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;
-}
-
-/*
- * Stop group events scheduling transaction
- * Clear the flag and pmu::enable() will perform the
- * schedulability test.
- */
-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);
-}
-
-/*
- * Commit group events scheduling transaction
- * Perform the group schedulability test as a whole
- * Return 0 if success
- */
-int power_pmu_commit_txn(struct pmu *pmu)
-{
-       struct cpu_hw_events *cpuhw;
-       long i, n;
-
-       if (!ppmu)
-               return -EAGAIN;
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-       n = cpuhw->n_events;
-       if (check_excludes(cpuhw->event, cpuhw->flags, 0, n))
-               return -EAGAIN;
-       i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n);
-       if (i < 0)
-               return -EAGAIN;
-
-       for (i = cpuhw->n_txn_start; i < n; ++i)
-               cpuhw->event[i]->hw.config = cpuhw->events[i];
-
-       cpuhw->group_flag &= ~PERF_EVENT_TXN;
-       perf_pmu_enable(pmu);
-       return 0;
-}
-
-/*
- * Return 1 if we might be able to put event on a limited PMC,
- * or 0 if not.
- * A event can only go on a limited PMC if it counts something
- * that a limited PMC can count, doesn't require interrupts, and
- * doesn't exclude any processor mode.
- */
-static int can_go_on_limited_pmc(struct perf_event *event, u64 ev,
-                                unsigned int flags)
-{
-       int n;
-       u64 alt[MAX_EVENT_ALTERNATIVES];
-
-       if (event->attr.exclude_user
-           || event->attr.exclude_kernel
-           || event->attr.exclude_hv
-           || event->attr.sample_period)
-               return 0;
-
-       if (ppmu->limited_pmc_event(ev))
-               return 1;
-
-       /*
-        * The requested event_id isn't on a limited PMC already;
-        * see if any alternative code goes on a limited PMC.
-        */
-       if (!ppmu->get_alternatives)
-               return 0;
-
-       flags |= PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD;
-       n = ppmu->get_alternatives(ev, flags, alt);
-
-       return n > 0;
-}
-
-/*
- * Find an alternative event_id that goes on a normal PMC, if possible,
- * and return the event_id code, or 0 if there is no such alternative.
- * (Note: event_id code 0 is "don't count" on all machines.)
- */
-static u64 normal_pmc_alternative(u64 ev, unsigned long flags)
-{
-       u64 alt[MAX_EVENT_ALTERNATIVES];
-       int n;
-
-       flags &= ~(PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD);
-       n = ppmu->get_alternatives(ev, flags, alt);
-       if (!n)
-               return 0;
-       return alt[0];
-}
-
-/* Number of perf_events counting hardware events */
-static atomic_t num_events;
-/* Used to avoid races in calling reserve/release_pmc_hardware */
-static DEFINE_MUTEX(pmc_reserve_mutex);
-
-/*
- * Release the PMU if this is the last perf_event.
- */
-static void hw_perf_event_destroy(struct perf_event *event)
-{
-       if (!atomic_add_unless(&num_events, -1, 1)) {
-               mutex_lock(&pmc_reserve_mutex);
-               if (atomic_dec_return(&num_events) == 0)
-                       release_pmc_hardware();
-               mutex_unlock(&pmc_reserve_mutex);
-       }
-}
-
-/*
- * Translate a generic cache event_id config to a raw event_id code.
- */
-static int hw_perf_cache_event(u64 config, u64 *eventp)
-{
-       unsigned long type, op, result;
-       int ev;
-
-       if (!ppmu->cache_events)
-               return -EINVAL;
-
-       /* unpack config */
-       type = config & 0xff;
-       op = (config >> 8) & 0xff;
-       result = (config >> 16) & 0xff;
-
-       if (type >= PERF_COUNT_HW_CACHE_MAX ||
-           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
-           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
-               return -EINVAL;
-
-       ev = (*ppmu->cache_events)[type][op][result];
-       if (ev == 0)
-               return -EOPNOTSUPP;
-       if (ev == -1)
-               return -EINVAL;
-       *eventp = ev;
-       return 0;
-}
-
-static int power_pmu_event_init(struct perf_event *event)
-{
-       u64 ev;
-       unsigned long flags;
-       struct perf_event *ctrs[MAX_HWEVENTS];
-       u64 events[MAX_HWEVENTS];
-       unsigned int cflags[MAX_HWEVENTS];
-       int n;
-       int err;
-       struct cpu_hw_events *cpuhw;
-
-       if (!ppmu)
-               return -ENOENT;
-
-       /* does not support taken branch sampling */
-       if (has_branch_stack(event))
-               return -EOPNOTSUPP;
-
-       switch (event->attr.type) {
-       case PERF_TYPE_HARDWARE:
-               ev = event->attr.config;
-               if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-                       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;
-               break;
-       case PERF_TYPE_RAW:
-               ev = event->attr.config;
-               break;
-       default:
-               return -ENOENT;
-       }
-
-       event->hw.config_base = ev;
-       event->hw.idx = 0;
-
-       /*
-        * If we are not running on a hypervisor, force the
-        * exclude_hv bit to 0 so that we don't care what
-        * the user set it to.
-        */
-       if (!firmware_has_feature(FW_FEATURE_LPAR))
-               event->attr.exclude_hv = 0;
-
-       /*
-        * If this is a per-task event, then we can use
-        * PM_RUN_* events interchangeably with their non RUN_*
-        * equivalents, e.g. PM_RUN_CYC instead of PM_CYC.
-        * XXX we should check if the task is an idle task.
-        */
-       flags = 0;
-       if (event->attach_state & PERF_ATTACH_TASK)
-               flags |= PPMU_ONLY_COUNT_RUN;
-
-       /*
-        * If this machine has limited events, check whether this
-        * event_id could go on a limited event.
-        */
-       if (ppmu->flags & PPMU_LIMITED_PMC5_6) {
-               if (can_go_on_limited_pmc(event, ev, flags)) {
-                       flags |= PPMU_LIMITED_PMC_OK;
-               } else if (ppmu->limited_pmc_event(ev)) {
-                       /*
-                        * The requested event_id is on a limited PMC,
-                        * but we can't use a limited PMC; see if any
-                        * alternative goes on a normal PMC.
-                        */
-                       ev = normal_pmc_alternative(ev, flags);
-                       if (!ev)
-                               return -EINVAL;
-               }
-       }
-
-       /*
-        * If this is in a group, check if it can go on with all the
-        * other hardware events in the group.  We assume the event
-        * hasn't been linked into its leader's sibling list at this point.
-        */
-       n = 0;
-       if (event->group_leader != event) {
-               n = collect_events(event->group_leader, ppmu->n_counter - 1,
-                                  ctrs, events, cflags);
-               if (n < 0)
-                       return -EINVAL;
-       }
-       events[n] = ev;
-       ctrs[n] = event;
-       cflags[n] = flags;
-       if (check_excludes(ctrs, cflags, n, 1))
-               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 -EINVAL;
-
-       event->hw.config = events[n];
-       event->hw.event_base = cflags[n];
-       event->hw.last_period = event->hw.sample_period;
-       local64_set(&event->hw.period_left, event->hw.last_period);
-
-       /*
-        * See if we need to reserve the PMU.
-        * If no events are currently in use, then we have to take a
-        * mutex to ensure that we don't race with another task doing
-        * reserve_pmc_hardware or release_pmc_hardware.
-        */
-       err = 0;
-       if (!atomic_inc_not_zero(&num_events)) {
-               mutex_lock(&pmc_reserve_mutex);
-               if (atomic_read(&num_events) == 0 &&
-                   reserve_pmc_hardware(perf_event_interrupt))
-                       err = -EBUSY;
-               else
-                       atomic_inc(&num_events);
-               mutex_unlock(&pmc_reserve_mutex);
-       }
-       event->destroy = hw_perf_event_destroy;
-
-       return err;
-}
-
-static int power_pmu_event_idx(struct perf_event *event)
-{
-       return event->hw.idx;
-}
-
-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,
-       .event_idx      = power_pmu_event_idx,
-};
-
-/*
- * A counter has overflowed; update its count and record
- * things if requested.  Note that interrupts are hard-disabled
- * here so there is no possibility of being interrupted.
- */
-static void record_and_restart(struct perf_event *event, unsigned long val,
-                              struct pt_regs *regs)
-{
-       u64 period = event->hw.sample_period;
-       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 = check_and_compute_delta(prev, val);
-       local64_add(delta, &event->count);
-
-       /*
-        * See if the total period for this event has expired,
-        * and update for the next period.
-        */
-       val = 0;
-       left = local64_read(&event->hw.period_left) - delta;
-       if (period) {
-               if (left <= 0) {
-                       left += period;
-                       if (left <= 0)
-                               left = period;
-                       record = 1;
-                       event->hw.last_period = event->hw.sample_period;
-               }
-               if (left < 0x80000000LL)
-                       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.
-        */
-       if (record) {
-               struct perf_sample_data data;
-
-               perf_sample_data_init(&data, ~0ULL);
-               data.period = event->hw.last_period;
-
-               if (event->attr.sample_type & PERF_SAMPLE_ADDR)
-                       perf_get_data_addr(regs, &data.addr);
-
-               if (perf_event_overflow(event, &data, regs))
-                       power_pmu_stop(event, 0);
-       }
-}
-
-/*
- * Called from generic code to get the misc flags (i.e. processor mode)
- * for an event_id.
- */
-unsigned long perf_misc_flags(struct pt_regs *regs)
-{
-       u32 flags = perf_get_misc_flags(regs);
-
-       if (flags)
-               return flags;
-       return user_mode(regs) ? PERF_RECORD_MISC_USER :
-               PERF_RECORD_MISC_KERNEL;
-}
-
-/*
- * Called from generic code to get the instruction pointer
- * for an event_id.
- */
-unsigned long perf_instruction_pointer(struct pt_regs *regs)
-{
-       unsigned long ip;
-
-       if (TRAP(regs) != 0xf00)
-               return regs->nip;       /* not a PMU interrupt */
-
-       ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
-       return ip;
-}
-
-static bool pmc_overflow(unsigned long val)
-{
-       if ((int)val < 0)
-               return true;
-
-       /*
-        * Events on POWER7 can roll back if a speculative event doesn't
-        * eventually complete. Unfortunately in some rare cases they will
-        * raise a performance monitor exception. We need to catch this to
-        * ensure we reset the PMC. In all cases the PMC will be 256 or less
-        * cycles from overflow.
-        *
-        * We only do this if the first pass fails to find any overflowing
-        * PMCs because a user might set a period of less than 256 and we
-        * don't want to mistakenly reset them.
-        */
-       if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
-               return true;
-
-       return false;
-}
-
-/*
- * Performance monitor interrupt stuff
- */
-static void perf_event_interrupt(struct pt_regs *regs)
-{
-       int i;
-       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
-       struct perf_event *event;
-       unsigned long val;
-       int found = 0;
-       int nmi;
-
-       if (cpuhw->n_limited)
-               freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),
-                                       mfspr(SPRN_PMC6));
-
-       perf_read_regs(regs);
-
-       nmi = perf_intr_is_nmi(regs);
-       if (nmi)
-               nmi_enter();
-       else
-               irq_enter();
-
-       for (i = 0; i < cpuhw->n_events; ++i) {
-               event = cpuhw->event[i];
-               if (!event->hw.idx || is_limited_pmc(event->hw.idx))
-                       continue;
-               val = read_pmc(event->hw.idx);
-               if ((int)val < 0) {
-                       /* event has overflowed */
-                       found = 1;
-                       record_and_restart(event, val, regs);
-               }
-       }
-
-       /*
-        * In case we didn't find and reset the event that caused
-        * the interrupt, scan all events and reset any that are
-        * negative, to avoid getting continual interrupts.
-        * Any that we processed in the previous loop will not be negative.
-        */
-       if (!found) {
-               for (i = 0; i < ppmu->n_counter; ++i) {
-                       if (is_limited_pmc(i + 1))
-                               continue;
-                       val = read_pmc(i + 1);
-                       if (pmc_overflow(val))
-                               write_pmc(i + 1, 0);
-               }
-       }
-
-       /*
-        * Reset MMCR0 to its normal value.  This will set PMXE and
-        * clear FC (freeze counters) and PMAO (perf mon alert occurred)
-        * and thus allow interrupts to occur again.
-        * XXX might want to use MSR.PM to keep the events frozen until
-        * we get back out of this interrupt.
-        */
-       write_mmcr0(cpuhw, cpuhw->mmcr[0]);
-
-       if (nmi)
-               nmi_exit();
-       else
-               irq_exit();
-}
-
-static void power_pmu_setup(int cpu)
-{
-       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
-
-       if (!ppmu)
-               return;
-       memset(cpuhw, 0, sizeof(*cpuhw));
-       cpuhw->mmcr[0] = MMCR0_FC;
-}
-
-static int __cpuinit
-power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
-{
-       unsigned int cpu = (long)hcpu;
-
-       switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_UP_PREPARE:
-               power_pmu_setup(cpu);
-               break;
-
-       default:
-               break;
-       }
-
-       return NOTIFY_OK;
-}
-
-int __cpuinit register_power_pmu(struct power_pmu *pmu)
-{
-       if (ppmu)
-               return -EBUSY;          /* something's already registered */
-
-       ppmu = pmu;
-       pr_info("%s performance monitor hardware support registered\n",
-               pmu->name);
-
-#ifdef MSR_HV
-       /*
-        * Use FCHV to ignore kernel events if MSR.HV is set.
-        */
-       if (mfmsr() & MSR_HV)
-               freeze_events_kernel = MMCR0_FCHV;
-#endif /* CONFIG_PPC64 */
-
-       perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
-       perf_cpu_notifier(power_pmu_notifier);
-
-       return 0;
-}
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
deleted file mode 100644 (file)
index 0a6d2a9..0000000
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Performance event support - Freescale Embedded Performance Monitor
- *
- * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
- * 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/sched.h>
-#include <linux/perf_event.h>
-#include <linux/percpu.h>
-#include <linux/hardirq.h>
-#include <asm/reg_fsl_emb.h>
-#include <asm/pmc.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/ptrace.h>
-
-struct cpu_hw_events {
-       int n_events;
-       int disabled;
-       u8  pmcs_enabled;
-       struct perf_event *event[MAX_HWEVENTS];
-};
-static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
-
-static struct fsl_emb_pmu *ppmu;
-
-/* Number of perf_events counting hardware events */
-static atomic_t num_events;
-/* Used to avoid races in calling reserve/release_pmc_hardware */
-static DEFINE_MUTEX(pmc_reserve_mutex);
-
-/*
- * If interrupts were soft-disabled when a PMU interrupt occurs, treat
- * it as an NMI.
- */
-static inline int perf_intr_is_nmi(struct pt_regs *regs)
-{
-#ifdef __powerpc64__
-       return !regs->softe;
-#else
-       return 0;
-#endif
-}
-
-static void perf_event_interrupt(struct pt_regs *regs);
-
-/*
- * Read one performance monitor counter (PMC).
- */
-static unsigned long read_pmc(int idx)
-{
-       unsigned long val;
-
-       switch (idx) {
-       case 0:
-               val = mfpmr(PMRN_PMC0);
-               break;
-       case 1:
-               val = mfpmr(PMRN_PMC1);
-               break;
-       case 2:
-               val = mfpmr(PMRN_PMC2);
-               break;
-       case 3:
-               val = mfpmr(PMRN_PMC3);
-               break;
-       default:
-               printk(KERN_ERR "oops trying to read PMC%d\n", idx);
-               val = 0;
-       }
-       return val;
-}
-
-/*
- * Write one PMC.
- */
-static void write_pmc(int idx, unsigned long val)
-{
-       switch (idx) {
-       case 0:
-               mtpmr(PMRN_PMC0, val);
-               break;
-       case 1:
-               mtpmr(PMRN_PMC1, val);
-               break;
-       case 2:
-               mtpmr(PMRN_PMC2, val);
-               break;
-       case 3:
-               mtpmr(PMRN_PMC3, val);
-               break;
-       default:
-               printk(KERN_ERR "oops trying to write PMC%d\n", idx);
-       }
-
-       isync();
-}
-
-/*
- * Write one local control A register
- */
-static void write_pmlca(int idx, unsigned long val)
-{
-       switch (idx) {
-       case 0:
-               mtpmr(PMRN_PMLCA0, val);
-               break;
-       case 1:
-               mtpmr(PMRN_PMLCA1, val);
-               break;
-       case 2:
-               mtpmr(PMRN_PMLCA2, val);
-               break;
-       case 3:
-               mtpmr(PMRN_PMLCA3, val);
-               break;
-       default:
-               printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
-       }
-
-       isync();
-}
-
-/*
- * Write one local control B register
- */
-static void write_pmlcb(int idx, unsigned long val)
-{
-       switch (idx) {
-       case 0:
-               mtpmr(PMRN_PMLCB0, val);
-               break;
-       case 1:
-               mtpmr(PMRN_PMLCB1, val);
-               break;
-       case 2:
-               mtpmr(PMRN_PMLCB2, val);
-               break;
-       case 3:
-               mtpmr(PMRN_PMLCB3, val);
-               break;
-       default:
-               printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
-       }
-
-       isync();
-}
-
-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.
-        * Therefore we treat them like NMIs.
-        */
-       do {
-               prev = local64_read(&event->hw.prev_count);
-               barrier();
-               val = read_pmc(event->hw.idx);
-       } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
-
-       /* The counters are only 32 bits wide */
-       delta = (val - prev) & 0xfffffffful;
-       local64_add(delta, &event->count);
-       local64_sub(delta, &event->hw.period_left);
-}
-
-/*
- * Disable all events to prevent PMU interrupts and to allow
- * events to be added or removed.
- */
-static void fsl_emb_pmu_disable(struct pmu *pmu)
-{
-       struct cpu_hw_events *cpuhw;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-
-       if (!cpuhw->disabled) {
-               cpuhw->disabled = 1;
-
-               /*
-                * Check if we ever enabled the PMU on this cpu.
-                */
-               if (!cpuhw->pmcs_enabled) {
-                       ppc_enable_pmcs();
-                       cpuhw->pmcs_enabled = 1;
-               }
-
-               if (atomic_read(&num_events)) {
-                       /*
-                        * Set the 'freeze all counters' bit, and disable
-                        * interrupts.  The barrier is to make sure the
-                        * mtpmr has been executed and the PMU has frozen
-                        * the events before we return.
-                        */
-
-                       mtpmr(PMRN_PMGC0, PMGC0_FAC);
-                       isync();
-               }
-       }
-       local_irq_restore(flags);
-}
-
-/*
- * Re-enable all events if disable == 0.
- * If we were previously disabled and events were added, then
- * put the new config on the PMU.
- */
-static void fsl_emb_pmu_enable(struct pmu *pmu)
-{
-       struct cpu_hw_events *cpuhw;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       cpuhw = &__get_cpu_var(cpu_hw_events);
-       if (!cpuhw->disabled)
-               goto out;
-
-       cpuhw->disabled = 0;
-       ppc_set_pmu_inuse(cpuhw->n_events != 0);
-
-       if (cpuhw->n_events > 0) {
-               mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
-               isync();
-       }
-
- out:
-       local_irq_restore(flags);
-}
-
-static int collect_events(struct perf_event *group, int max_count,
-                         struct perf_event *ctrs[])
-{
-       int n = 0;
-       struct perf_event *event;
-
-       if (!is_software_event(group)) {
-               if (n >= max_count)
-                       return -1;
-               ctrs[n] = group;
-               n++;
-       }
-       list_for_each_entry(event, &group->sibling_list, group_entry) {
-               if (!is_software_event(event) &&
-                   event->state != PERF_EVENT_STATE_OFF) {
-                       if (n >= max_count)
-                               return -1;
-                       ctrs[n] = event;
-                       n++;
-               }
-       }
-       return n;
-}
-
-/* context locked on entry */
-static int fsl_emb_pmu_add(struct perf_event *event, int flags)
-{
-       struct cpu_hw_events *cpuhw;
-       int ret = -EAGAIN;
-       int num_counters = ppmu->n_counter;
-       u64 val;
-       int i;
-
-       perf_pmu_disable(event->pmu);
-       cpuhw = &get_cpu_var(cpu_hw_events);
-
-       if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
-               num_counters = ppmu->n_restricted;
-
-       /*
-        * Allocate counters from top-down, so that restricted-capable
-        * counters are kept free as long as possible.
-        */
-       for (i = num_counters - 1; i >= 0; i--) {
-               if (cpuhw->event[i])
-                       continue;
-
-               break;
-       }
-
-       if (i < 0)
-               goto out;
-
-       event->hw.idx = i;
-       cpuhw->event[i] = event;
-       ++cpuhw->n_events;
-
-       val = 0;
-       if (event->hw.sample_period) {
-               s64 left = local64_read(&event->hw.period_left);
-               if (left < 0x80000000L)
-                       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);
-
-       write_pmlcb(i, event->hw.config >> 32);
-       write_pmlca(i, event->hw.config_base);
-
-       ret = 0;
- out:
-       put_cpu_var(cpu_hw_events);
-       perf_pmu_enable(event->pmu);
-       return ret;
-}
-
-/* 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;
-
-       fsl_emb_pmu_read(event);
-
-       cpuhw = &get_cpu_var(cpu_hw_events);
-
-       WARN_ON(event != cpuhw->event[event->hw.idx]);
-
-       write_pmlca(i, 0);
-       write_pmlcb(i, 0);
-       write_pmc(i, 0);
-
-       cpuhw->event[i] = NULL;
-       event->hw.idx = -1;
-
-       /*
-        * TODO: if at least one restricted event exists, and we
-        * just freed up a non-restricted-capable counter, and
-        * there is a restricted-capable counter occupied by
-        * a non-restricted event, migrate that event to the
-        * vacated counter.
-        */
-
-       cpuhw->n_events--;
-
- out:
-       perf_pmu_enable(event->pmu);
-       put_cpu_var(cpu_hw_events);
-}
-
-static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
-{
-       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_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 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.
- */
-static void hw_perf_event_destroy(struct perf_event *event)
-{
-       if (!atomic_add_unless(&num_events, -1, 1)) {
-               mutex_lock(&pmc_reserve_mutex);
-               if (atomic_dec_return(&num_events) == 0)
-                       release_pmc_hardware();
-               mutex_unlock(&pmc_reserve_mutex);
-       }
-}
-
-/*
- * Translate a generic cache event_id config to a raw event_id code.
- */
-static int hw_perf_cache_event(u64 config, u64 *eventp)
-{
-       unsigned long type, op, result;
-       int ev;
-
-       if (!ppmu->cache_events)
-               return -EINVAL;
-
-       /* unpack config */
-       type = config & 0xff;
-       op = (config >> 8) & 0xff;
-       result = (config >> 16) & 0xff;
-
-       if (type >= PERF_COUNT_HW_CACHE_MAX ||
-           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
-           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
-               return -EINVAL;
-
-       ev = (*ppmu->cache_events)[type][op][result];
-       if (ev == 0)
-               return -EOPNOTSUPP;
-       if (ev == -1)
-               return -EINVAL;
-       *eventp = ev;
-       return 0;
-}
-
-static int fsl_emb_pmu_event_init(struct perf_event *event)
-{
-       u64 ev;
-       struct perf_event *events[MAX_HWEVENTS];
-       int n;
-       int err;
-       int num_restricted;
-       int i;
-
-       switch (event->attr.type) {
-       case PERF_TYPE_HARDWARE:
-               ev = event->attr.config;
-               if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-                       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;
-               break;
-
-       case PERF_TYPE_RAW:
-               ev = event->attr.config;
-               break;
-
-       default:
-               return -ENOENT;
-       }
-
-       event->hw.config = ppmu->xlate_event(ev);
-       if (!(event->hw.config & FSL_EMB_EVENT_VALID))
-               return -EINVAL;
-
-       /*
-        * If this is in a group, check if it can go on with all the
-        * other hardware events in the group.  We assume the event
-        * hasn't been linked into its leader's sibling list at this point.
-        */
-       n = 0;
-       if (event->group_leader != event) {
-               n = collect_events(event->group_leader,
-                                  ppmu->n_counter - 1, events);
-               if (n < 0)
-                       return -EINVAL;
-       }
-
-       if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
-               num_restricted = 0;
-               for (i = 0; i < n; i++) {
-                       if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
-                               num_restricted++;
-               }
-
-               if (num_restricted >= ppmu->n_restricted)
-                       return -EINVAL;
-       }
-
-       event->hw.idx = -1;
-
-       event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
-                               (u32)((ev << 16) & PMLCA_EVENT_MASK);
-
-       if (event->attr.exclude_user)
-               event->hw.config_base |= PMLCA_FCU;
-       if (event->attr.exclude_kernel)
-               event->hw.config_base |= PMLCA_FCS;
-       if (event->attr.exclude_idle)
-               return -ENOTSUPP;
-
-       event->hw.last_period = event->hw.sample_period;
-       local64_set(&event->hw.period_left, event->hw.last_period);
-
-       /*
-        * See if we need to reserve the PMU.
-        * If no events are currently in use, then we have to take a
-        * mutex to ensure that we don't race with another task doing
-        * reserve_pmc_hardware or release_pmc_hardware.
-        */
-       err = 0;
-       if (!atomic_inc_not_zero(&num_events)) {
-               mutex_lock(&pmc_reserve_mutex);
-               if (atomic_read(&num_events) == 0 &&
-                   reserve_pmc_hardware(perf_event_interrupt))
-                       err = -EBUSY;
-               else
-                       atomic_inc(&num_events);
-               mutex_unlock(&pmc_reserve_mutex);
-
-               mtpmr(PMRN_PMGC0, PMGC0_FAC);
-               isync();
-       }
-       event->destroy = hw_perf_event_destroy;
-
-       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
- * here so there is no possibility of being interrupted.
- */
-static void record_and_restart(struct perf_event *event, unsigned long val,
-                              struct pt_regs *regs)
-{
-       u64 period = event->hw.sample_period;
-       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;
-       local64_add(delta, &event->count);
-
-       /*
-        * See if the total period for this event has expired,
-        * and update for the next period.
-        */
-       val = 0;
-       left = local64_read(&event->hw.period_left) - delta;
-       if (period) {
-               if (left <= 0) {
-                       left += period;
-                       if (left <= 0)
-                               left = period;
-                       record = 1;
-                       event->hw.last_period = event->hw.sample_period;
-               }
-               if (left < 0x80000000LL)
-                       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.
-        */
-       if (record) {
-               struct perf_sample_data data;
-
-               perf_sample_data_init(&data, 0);
-               data.period = event->hw.last_period;
-
-               if (perf_event_overflow(event, &data, regs))
-                       fsl_emb_pmu_stop(event, 0);
-       }
-}
-
-static void perf_event_interrupt(struct pt_regs *regs)
-{
-       int i;
-       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
-       struct perf_event *event;
-       unsigned long val;
-       int found = 0;
-       int nmi;
-
-       nmi = perf_intr_is_nmi(regs);
-       if (nmi)
-               nmi_enter();
-       else
-               irq_enter();
-
-       for (i = 0; i < ppmu->n_counter; ++i) {
-               event = cpuhw->event[i];
-
-               val = read_pmc(i);
-               if ((int)val < 0) {
-                       if (event) {
-                               /* event has overflowed */
-                               found = 1;
-                               record_and_restart(event, val, regs);
-                       } else {
-                               /*
-                                * Disabled counter is negative,
-                                * reset it just in case.
-                                */
-                               write_pmc(i, 0);
-                       }
-               }
-       }
-
-       /* PMM will keep counters frozen until we return from the interrupt. */
-       mtmsr(mfmsr() | MSR_PMM);
-       mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
-       isync();
-
-       if (nmi)
-               nmi_exit();
-       else
-               irq_exit();
-}
-
-void hw_perf_event_setup(int cpu)
-{
-       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
-
-       memset(cpuhw, 0, sizeof(*cpuhw));
-}
-
-int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
-{
-       if (ppmu)
-               return -EBUSY;          /* something's already registered */
-
-       ppmu = pmu;
-       pr_info("%s performance monitor hardware support registered\n",
-               pmu->name);
-
-       perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
-
-       return 0;
-}
diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/kernel/power4-pmu.c
deleted file mode 100644 (file)
index b4f1dda..0000000
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
- *
- * Copyright 2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER4
- */
-#define PM_PMC_SH      12      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0xf
-#define PM_UNIT_SH     8       /* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK    0xf
-#define PM_LOWER_SH    6
-#define PM_LOWER_MSK   1
-#define PM_LOWER_MSKS  0x40
-#define PM_BYTE_SH     4       /* Byte number of event bus to use */
-#define PM_BYTE_MSK    3
-#define PM_PMCSEL_MSK  7
-
-/*
- * Unit code values
- */
-#define PM_FPU         1
-#define PM_ISU1                2
-#define PM_IFU         3
-#define PM_IDU0                4
-#define PM_ISU1_ALT    6
-#define PM_ISU2                7
-#define PM_IFU_ALT     8
-#define PM_LSU0                9
-#define PM_LSU1                0xc
-#define PM_GPS         0xf
-
-/*
- * Bits in MMCR0 for POWER4
- */
-#define MMCR0_PMC1SEL_SH       8
-#define MMCR0_PMC2SEL_SH       1
-#define MMCR_PMCSEL_MSK                0x1f
-
-/*
- * Bits in MMCR1 for POWER4
- */
-#define MMCR1_TTM0SEL_SH       62
-#define MMCR1_TTC0SEL_SH       61
-#define MMCR1_TTM1SEL_SH       59
-#define MMCR1_TTC1SEL_SH       58
-#define MMCR1_TTM2SEL_SH       56
-#define MMCR1_TTC2SEL_SH       55
-#define MMCR1_TTM3SEL_SH       53
-#define MMCR1_TTC3SEL_SH       52
-#define MMCR1_TTMSEL_MSK       3
-#define MMCR1_TD_CP_DBG0SEL_SH 50
-#define MMCR1_TD_CP_DBG1SEL_SH 48
-#define MMCR1_TD_CP_DBG2SEL_SH 46
-#define MMCR1_TD_CP_DBG3SEL_SH 44
-#define MMCR1_DEBUG0SEL_SH     43
-#define MMCR1_DEBUG1SEL_SH     42
-#define MMCR1_DEBUG2SEL_SH     41
-#define MMCR1_DEBUG3SEL_SH     40
-#define MMCR1_PMC1_ADDER_SEL_SH        39
-#define MMCR1_PMC2_ADDER_SEL_SH        38
-#define MMCR1_PMC6_ADDER_SEL_SH        37
-#define MMCR1_PMC5_ADDER_SEL_SH        36
-#define MMCR1_PMC8_ADDER_SEL_SH        35
-#define MMCR1_PMC7_ADDER_SEL_SH        34
-#define MMCR1_PMC3_ADDER_SEL_SH        33
-#define MMCR1_PMC4_ADDER_SEL_SH        32
-#define MMCR1_PMC3SEL_SH       27
-#define MMCR1_PMC4SEL_SH       22
-#define MMCR1_PMC5SEL_SH       17
-#define MMCR1_PMC6SEL_SH       12
-#define MMCR1_PMC7SEL_SH       7
-#define MMCR1_PMC8SEL_SH       2       /* note bit 0 is in MMCRA for GP */
-
-static short mmcr1_adder_bits[8] = {
-       MMCR1_PMC1_ADDER_SEL_SH,
-       MMCR1_PMC2_ADDER_SEL_SH,
-       MMCR1_PMC3_ADDER_SEL_SH,
-       MMCR1_PMC4_ADDER_SEL_SH,
-       MMCR1_PMC5_ADDER_SEL_SH,
-       MMCR1_PMC6_ADDER_SEL_SH,
-       MMCR1_PMC7_ADDER_SEL_SH,
-       MMCR1_PMC8_ADDER_SEL_SH
-};
-
-/*
- * Bits in MMCRA
- */
-#define MMCRA_PMC8SEL0_SH      17      /* PMC8SEL bit 0 for GP */
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *        |[  >[  >[   >|||[  >[  ><  ><  ><  ><  ><><><><><><><><>
- *        | UC1 UC2 UC3 ||| PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
- *       \SMPL         ||\TTC3SEL
- *                     |\TTC_IFU_SEL
- *                     \TTM2SEL0
- *
- * SMPL - SAMPLE_ENABLE constraint
- *     56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
- *
- * UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
- *     55: UC1 error 0x0080_0000_0000_0000
- *     54: FPU events needed 0x0040_0000_0000_0000
- *     53: ISU1 events needed 0x0020_0000_0000_0000
- *     52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
- *
- * UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
- *     51: UC2 error 0x0008_0000_0000_0000
- *     50: FPU events needed 0x0004_0000_0000_0000
- *     49: IFU events needed 0x0002_0000_0000_0000
- *     48: LSU0 events needed 0x0001_0000_0000_0000
- *
- * UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
- *     47: UC3 error 0x8000_0000_0000
- *     46: LSU0 events needed 0x4000_0000_0000
- *     45: IFU events needed 0x2000_0000_0000
- *     44: IDU0|ISU2 events needed 0x1000_0000_0000
- *     43: ISU1 events needed 0x0800_0000_0000
- *
- * TTM2SEL0
- *     42: 0 = IDU0 events needed
- *                1 = ISU2 events needed 0x0400_0000_0000
- *
- * TTC_IFU_SEL
- *     41: 0 = IFU.U events needed
- *                1 = IFU.L events needed 0x0200_0000_0000
- *
- * TTC3SEL
- *     40: 0 = LSU1.U events needed
- *                1 = LSU1.L events needed 0x0100_0000_0000
- *
- * PS1
- *     39: PS1 error 0x0080_0000_0000
- *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
- *
- * PS2
- *     35: PS2 error 0x0008_0000_0000
- *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
- *
- * B0
- *     28-31: Byte 0 event source 0xf000_0000
- *                1 = FPU
- *        2 = ISU1
- *        3 = IFU
- *        4 = IDU0
- *        7 = ISU2
- *        9 = LSU0
- *        c = LSU1
- *        f = GPS
- *
- * B1, B2, B3
- *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
- *
- * P8
- *     15: P8 error 0x8000
- *     14-15: Count of events needing PMC8
- *
- * P1..P7
- *     0-13: Count of events needing PMC1..PMC7
- *
- * Note: this doesn't allow events using IFU.U to be combined with events
- * using IFU.L, though that is feasible (using TTM0 and TTM2).  However
- * there are no listed events for IFU.L (they are debug events not
- * verified for performance monitoring) so this shouldn't cause a
- * problem.
- */
-
-static struct unitinfo {
-       unsigned long   value, mask;
-       int             unit;
-       int             lowerbit;
-} p4_unitinfo[16] = {
-       [PM_FPU]  = { 0x44000000000000ul, 0x88000000000000ul, PM_FPU, 0 },
-       [PM_ISU1] = { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
-       [PM_ISU1_ALT] =
-                   { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
-       [PM_IFU]  = { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
-       [PM_IFU_ALT] =
-                   { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
-       [PM_IDU0] = { 0x10100000000000ul, 0x80840000000000ul, PM_IDU0, 1 },
-       [PM_ISU2] = { 0x10140000000000ul, 0x80840000000000ul, PM_ISU2, 0 },
-       [PM_LSU0] = { 0x01400000000000ul, 0x08800000000000ul, PM_LSU0, 0 },
-       [PM_LSU1] = { 0x00000000000000ul, 0x00010000000000ul, PM_LSU1, 40 },
-       [PM_GPS]  = { 0x00000000000000ul, 0x00000000000000ul, PM_GPS, 0 }
-};
-
-static unsigned char direct_marked_event[8] = {
-       (1<<2) | (1<<3),        /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
-       (1<<3) | (1<<5),        /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
-       (1<<3),                 /* PMC3: PM_MRK_ST_CMPL_INT */
-       (1<<4) | (1<<5),        /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
-       (1<<4) | (1<<5),        /* PMC5: PM_MRK_GRP_TIMEO */
-       (1<<3) | (1<<4) | (1<<5),
-               /* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
-       (1<<4) | (1<<5),        /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
-       (1<<4),                 /* PMC8: PM_MRK_LSU_FIN */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int p4_marked_instr_event(u64 event)
-{
-       int pmc, psel, unit, byte, bit;
-       unsigned int mask;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = event & PM_PMCSEL_MSK;
-       if (pmc) {
-               if (direct_marked_event[pmc - 1] & (1 << psel))
-                       return 1;
-               if (psel == 0)          /* add events */
-                       bit = (pmc <= 4)? pmc - 1: 8 - pmc;
-               else if (psel == 6)     /* decode events */
-                       bit = 4;
-               else
-                       return 0;
-       } else
-               bit = psel;
-
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       mask = 0;
-       switch (unit) {
-       case PM_LSU1:
-               if (event & PM_LOWER_MSKS)
-                       mask = 1 << 28;         /* byte 7 bit 4 */
-               else
-                       mask = 6 << 24;         /* byte 3 bits 1 and 2 */
-               break;
-       case PM_LSU0:
-               /* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
-               mask = 0x083dff00;
-       }
-       return (mask >> (byte * 8 + bit)) & 1;
-}
-
-static int p4_get_constraint(u64 event, unsigned long *maskp,
-                            unsigned long *valp)
-{
-       int pmc, byte, unit, lower, sh;
-       unsigned long mask = 0, value = 0;
-       int grp = -1;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 8)
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-               grp = ((pmc - 1) >> 1) & 1;
-       }
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       if (unit) {
-               lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
-
-               /*
-                * Bus events on bytes 0 and 2 can be counted
-                * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
-                */
-               if (!pmc)
-                       grp = byte & 1;
-
-               if (!p4_unitinfo[unit].unit)
-                       return -1;
-               mask  |= p4_unitinfo[unit].mask;
-               value |= p4_unitinfo[unit].value;
-               sh = p4_unitinfo[unit].lowerbit;
-               if (sh > 1)
-                       value |= (unsigned long)lower << sh;
-               else if (lower != sh)
-                       return -1;
-               unit = p4_unitinfo[unit].unit;
-
-               /* Set byte lane select field */
-               mask  |= 0xfULL << (28 - 4 * byte);
-               value |= (unsigned long)unit << (28 - 4 * byte);
-       }
-       if (grp == 0) {
-               /* increment PMC1/2/5/6 field */
-               mask  |= 0x8000000000ull;
-               value |= 0x1000000000ull;
-       } else {
-               /* increment PMC3/4/7/8 field */
-               mask  |= 0x800000000ull;
-               value |= 0x100000000ull;
-       }
-
-       /* Marked instruction events need sample_enable set */
-       if (p4_marked_instr_event(event)) {
-               mask  |= 1ull << 56;
-               value |= 1ull << 56;
-       }
-
-       /* PMCSEL=6 decode events on byte 2 need sample_enable clear */
-       if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
-               mask  |= 1ull << 56;
-
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-static unsigned int ppc_inst_cmpl[] = {
-       0x1001, 0x4001, 0x6001, 0x7001, 0x8001
-};
-
-static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, na;
-
-       alt[0] = event;
-       na = 1;
-
-       /* 2 possibilities for PM_GRP_DISP_REJECT */
-       if (event == 0x8003 || event == 0x0224) {
-               alt[1] = event ^ (0x8003 ^ 0x0224);
-               return 2;
-       }
-
-       /* 2 possibilities for PM_ST_MISS_L1 */
-       if (event == 0x0c13 || event == 0x0c23) {
-               alt[1] = event ^ (0x0c13 ^ 0x0c23);
-               return 2;
-       }
-
-       /* several possibilities for PM_INST_CMPL */
-       for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
-               if (event == ppc_inst_cmpl[i]) {
-                       for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
-                               if (j != i)
-                                       alt[na++] = ppc_inst_cmpl[j];
-                       break;
-               }
-       }
-
-       return na;
-}
-
-static int p4_compute_mmcr(u64 event[], int n_ev,
-                          unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
-       unsigned int pmc, unit, byte, psel, lower;
-       unsigned int ttm, grp;
-       unsigned int pmc_inuse = 0;
-       unsigned int pmc_grp_use[2];
-       unsigned char busbyte[4];
-       unsigned char unituse[16];
-       unsigned int unitlower = 0;
-       int i;
-
-       if (n_ev > 8)
-               return -1;
-
-       /* First pass to count resource use */
-       pmc_grp_use[0] = pmc_grp_use[1] = 0;
-       memset(busbyte, 0, sizeof(busbyte));
-       memset(unituse, 0, sizeof(unituse));
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;
-                       pmc_inuse |= 1 << (pmc - 1);
-                       /* count 1/2/5/6 vs 3/4/7/8 use */
-                       ++pmc_grp_use[((pmc - 1) >> 1) & 1];
-               }
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
-               if (unit) {
-                       if (!pmc)
-                               ++pmc_grp_use[byte & 1];
-                       if (unit == 6 || unit == 8)
-                               /* map alt ISU1/IFU codes: 6->2, 8->3 */
-                               unit = (unit >> 1) - 1;
-                       if (busbyte[byte] && busbyte[byte] != unit)
-                               return -1;
-                       busbyte[byte] = unit;
-                       lower <<= unit;
-                       if (unituse[unit] && lower != (unitlower & lower))
-                               return -1;
-                       unituse[unit] = 1;
-                       unitlower |= lower;
-               }
-       }
-       if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
-               return -1;
-
-       /*
-        * Assign resources and set multiplexer selects.
-        *
-        * Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
-        * Each TTMx can only select one unit, but since
-        * units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
-        * we have some choices.
-        */
-       if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
-               unituse[6] = 1;         /* Move 2 to 6 */
-               unituse[2] = 0;
-       }
-       if (unituse[3] & (unituse[1] | unituse[2])) {
-               unituse[8] = 1;         /* Move 3 to 8 */
-               unituse[3] = 0;
-               unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
-       }
-       /* Check only one unit per TTMx */
-       if (unituse[1] + unituse[2] + unituse[3] > 1 ||
-           unituse[4] + unituse[6] + unituse[7] > 1 ||
-           unituse[8] + unituse[9] > 1 ||
-           (unituse[5] | unituse[10] | unituse[11] |
-            unituse[13] | unituse[14]))
-               return -1;
-
-       /* Set TTMxSEL fields.  Note, units 1-3 => TTM0SEL codes 0-2 */
-       mmcr1 |= (unsigned long)(unituse[3] * 2 + unituse[2])
-               << MMCR1_TTM0SEL_SH;
-       mmcr1 |= (unsigned long)(unituse[7] * 3 + unituse[6] * 2)
-               << MMCR1_TTM1SEL_SH;
-       mmcr1 |= (unsigned long)unituse[9] << MMCR1_TTM2SEL_SH;
-
-       /* Set TTCxSEL fields. */
-       if (unitlower & 0xe)
-               mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
-       if (unitlower & 0xf0)
-               mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
-       if (unitlower & 0xf00)
-               mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
-       if (unitlower & 0x7000)
-               mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
-
-       /* Set byte lane select fields. */
-       for (byte = 0; byte < 4; ++byte) {
-               unit = busbyte[byte];
-               if (!unit)
-                       continue;
-               if (unit == 0xf) {
-                       /* special case for GPS */
-                       mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
-               } else {
-                       if (!unituse[unit])
-                               ttm = unit - 1;         /* 2->1, 3->2 */
-                       else
-                               ttm = unit >> 2;
-                       mmcr1 |= (unsigned long)ttm
-                               << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-               }
-       }
-
-       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               psel = event[i] & PM_PMCSEL_MSK;
-               if (!pmc) {
-                       /* Bus event or 00xxx direct event (off or cycles) */
-                       if (unit)
-                               psel |= 0x10 | ((byte & 2) << 2);
-                       for (pmc = 0; pmc < 8; ++pmc) {
-                               if (pmc_inuse & (1 << pmc))
-                                       continue;
-                               grp = (pmc >> 1) & 1;
-                               if (unit) {
-                                       if (grp == (byte & 1))
-                                               break;
-                               } else if (pmc_grp_use[grp] < 4) {
-                                       ++pmc_grp_use[grp];
-                                       break;
-                               }
-                       }
-                       pmc_inuse |= 1 << pmc;
-               } else {
-                       /* Direct event */
-                       --pmc;
-                       if (psel == 0 && (byte & 2))
-                               /* add events on higher-numbered bus */
-                               mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
-                       else if (psel == 6 && byte == 3)
-                               /* seem to need to set sample_enable here */
-                               mmcra |= MMCRA_SAMPLE_ENABLE;
-                       psel |= 8;
-               }
-               if (pmc <= 1)
-                       mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
-               else
-                       mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
-               if (pmc == 7)   /* PMC8 */
-                       mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
-               hwc[i] = pmc;
-               if (p4_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-       }
-
-       if (pmc_inuse & 1)
-               mmcr0 |= MMCR0_PMC1CE;
-       if (pmc_inuse & 0xfe)
-               mmcr0 |= MMCR0_PMCjCE;
-
-       mmcra |= 0x2000;        /* mark only one IOP per PPC instruction */
-
-       /* Return MMCRx values */
-       mmcr[0] = mmcr0;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-static void p4_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       /*
-        * Setting the PMCxSEL field to 0 disables PMC x.
-        * (Note that pmc is 0-based here, not 1-based.)
-        */
-       if (pmc <= 1) {
-               mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
-       } else {
-               mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
-               if (pmc == 7)
-                       mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
-       }
-}
-
-static int p4_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 7,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x1001,
-       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x8c10, /* PM_LD_REF_L1 */
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c10, /* PM_LD_MISS_L1 */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x330,  /* PM_BR_ISSUED */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x331,  /* PM_BR_MPRED_CR */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x8c10,         0x3c10  },
-               [C(OP_WRITE)] = {       0x7c10,         0xc13   },
-               [C(OP_PREFETCH)] = {    0xc35,          0       },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       0,              0       },
-               [C(OP_PREFETCH)] = {    0xc34,          0       },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x904   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x900   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x330,          0x331   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-};
-
-static struct power_pmu power4_pmu = {
-       .name                   = "POWER4/4+",
-       .n_counter              = 8,
-       .max_alternatives       = 5,
-       .add_fields             = 0x0000001100005555ul,
-       .test_adder             = 0x0011083300000000ul,
-       .compute_mmcr           = p4_compute_mmcr,
-       .get_constraint         = p4_get_constraint,
-       .get_alternatives       = p4_get_alternatives,
-       .disable_pmc            = p4_disable_pmc,
-       .n_generic              = ARRAY_SIZE(p4_generic_events),
-       .generic_events         = p4_generic_events,
-       .cache_events           = &power4_cache_events,
-};
-
-static int __init init_power4_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
-               return -ENODEV;
-
-       return register_power_pmu(&power4_pmu);
-}
-
-early_initcall(init_power4_pmu);
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/kernel/power5+-pmu.c
deleted file mode 100644 (file)
index a8757ba..0000000
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Performance counter support for POWER5+/++ (not POWER5) processors.
- *
- * Copyright 2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
- */
-#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0xf
-#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
-#define PM_UNIT_SH     16      /* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK    0xf
-#define PM_BYTE_SH     12      /* Byte number of event bus to use */
-#define PM_BYTE_MSK    7
-#define PM_GRS_SH      8       /* Storage subsystem mux select */
-#define PM_GRS_MSK     7
-#define PM_BUSEVENT_MSK        0x80    /* Set if event uses event bus */
-#define PM_PMCSEL_MSK  0x7f
-
-/* Values in PM_UNIT field */
-#define PM_FPU         0
-#define PM_ISU0                1
-#define PM_IFU         2
-#define PM_ISU1                3
-#define PM_IDU         4
-#define PM_ISU0_ALT    6
-#define PM_GRS         7
-#define PM_LSU0                8
-#define PM_LSU1                0xc
-#define PM_LASTUNIT    0xc
-
-/*
- * Bits in MMCR1 for POWER5+
- */
-#define MMCR1_TTM0SEL_SH       62
-#define MMCR1_TTM1SEL_SH       60
-#define MMCR1_TTM2SEL_SH       58
-#define MMCR1_TTM3SEL_SH       56
-#define MMCR1_TTMSEL_MSK       3
-#define MMCR1_TD_CP_DBG0SEL_SH 54
-#define MMCR1_TD_CP_DBG1SEL_SH 52
-#define MMCR1_TD_CP_DBG2SEL_SH 50
-#define MMCR1_TD_CP_DBG3SEL_SH 48
-#define MMCR1_GRS_L2SEL_SH     46
-#define MMCR1_GRS_L2SEL_MSK    3
-#define MMCR1_GRS_L3SEL_SH     44
-#define MMCR1_GRS_L3SEL_MSK    3
-#define MMCR1_GRS_MCSEL_SH     41
-#define MMCR1_GRS_MCSEL_MSK    7
-#define MMCR1_GRS_FABSEL_SH    39
-#define MMCR1_GRS_FABSEL_MSK   3
-#define MMCR1_PMC1_ADDER_SEL_SH        35
-#define MMCR1_PMC2_ADDER_SEL_SH        34
-#define MMCR1_PMC3_ADDER_SEL_SH        33
-#define MMCR1_PMC4_ADDER_SEL_SH        32
-#define MMCR1_PMC1SEL_SH       25
-#define MMCR1_PMC2SEL_SH       17
-#define MMCR1_PMC3SEL_SH       9
-#define MMCR1_PMC4SEL_SH       1
-#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
-#define MMCR1_PMCSEL_MSK       0x7f
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *             [  ><><>< ><> <><>[  >  <  ><  ><  ><  ><><><><><><>
- *             NC  G0G1G2 G3 T0T1 UC    B0  B1  B2  B3 P6P5P4P3P2P1
- *
- * NC - number of counters
- *     51: NC error 0x0008_0000_0000_0000
- *     48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
- *
- * G0..G3 - GRS mux constraints
- *     46-47: GRS_L2SEL value
- *     44-45: GRS_L3SEL value
- *     41-44: GRS_MCSEL value
- *     39-40: GRS_FABSEL value
- *     Note that these match up with their bit positions in MMCR1
- *
- * T0 - TTM0 constraint
- *     36-37: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0x30_0000_0000
- *
- * T1 - TTM1 constraint
- *     34-35: TTM1SEL value (0=IDU, 3=GRS) 0x0c_0000_0000
- *
- * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
- *     33: UC3 error 0x02_0000_0000
- *     32: FPU|IFU|ISU1 events needed 0x01_0000_0000
- *     31: ISU0 events needed 0x01_8000_0000
- *     30: IDU|GRS events needed 0x00_4000_0000
- *
- * B0
- *     24-27: Byte 0 event source 0x0f00_0000
- *           Encoding as for the event code
- *
- * B1, B2, B3
- *     20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
- *
- * P6
- *     11: P6 error 0x800
- *     10-11: Count of events needing PMC6
- *
- * P1..P5
- *     0-9: Count of events needing PMC1..PMC5
- */
-
-static const int grsel_shift[8] = {
-       MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
-       MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
-       MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
-};
-
-/* Masks and values for using events from the various units */
-static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
-       [PM_FPU] =   { 0x3200000000ul, 0x0100000000ul },
-       [PM_ISU0] =  { 0x0200000000ul, 0x0080000000ul },
-       [PM_ISU1] =  { 0x3200000000ul, 0x3100000000ul },
-       [PM_IFU] =   { 0x3200000000ul, 0x2100000000ul },
-       [PM_IDU] =   { 0x0e00000000ul, 0x0040000000ul },
-       [PM_GRS] =   { 0x0e00000000ul, 0x0c40000000ul },
-};
-
-static int power5p_get_constraint(u64 event, unsigned long *maskp,
-                                 unsigned long *valp)
-{
-       int pmc, byte, unit, sh;
-       int bit, fmask;
-       unsigned long mask = 0, value = 0;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 6)
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-               if (pmc >= 5 && !(event == 0x500009 || event == 0x600005))
-                       return -1;
-       }
-       if (event & PM_BUSEVENT_MSK) {
-               unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-               if (unit > PM_LASTUNIT)
-                       return -1;
-               if (unit == PM_ISU0_ALT)
-                       unit = PM_ISU0;
-               mask |= unit_cons[unit][0];
-               value |= unit_cons[unit][1];
-               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-               if (byte >= 4) {
-                       if (unit != PM_LSU1)
-                               return -1;
-                       /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
-                       ++unit;
-                       byte &= 3;
-               }
-               if (unit == PM_GRS) {
-                       bit = event & 7;
-                       fmask = (bit == 6)? 7: 3;
-                       sh = grsel_shift[bit];
-                       mask |= (unsigned long)fmask << sh;
-                       value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
-                               << sh;
-               }
-               /* Set byte lane select field */
-               mask  |= 0xfUL << (24 - 4 * byte);
-               value |= (unsigned long)unit << (24 - 4 * byte);
-       }
-       if (pmc < 5) {
-               /* need a counter from PMC1-4 set */
-               mask  |= 0x8000000000000ul;
-               value |= 0x1000000000000ul;
-       }
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-static int power5p_limited_pmc_event(u64 event)
-{
-       int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-
-       return pmc == 5 || pmc == 6;
-}
-
-#define MAX_ALT        3       /* at most 3 alternatives for any event */
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-       { 0x100c0,  0x40001f },                 /* PM_GCT_FULL_CYC */
-       { 0x120e4,  0x400002 },                 /* PM_GRP_DISP_REJECT */
-       { 0x230e2,  0x323087 },                 /* PM_BR_PRED_CR */
-       { 0x230e3,  0x223087, 0x3230a0 },       /* PM_BR_PRED_TA */
-       { 0x410c7,  0x441084 },                 /* PM_THRD_L2MISS_BOTH_CYC */
-       { 0x800c4,  0xc20e0 },                  /* PM_DTLB_MISS */
-       { 0xc50c6,  0xc60e0 },                  /* PM_MRK_DTLB_MISS */
-       { 0x100005, 0x600005 },                 /* PM_RUN_CYC */
-       { 0x100009, 0x200009 },                 /* PM_INST_CMPL */
-       { 0x200015, 0x300015 },                 /* PM_LSU_LMQ_SRQ_EMPTY_CYC */
-       { 0x300009, 0x400009 },                 /* PM_INST_DISP */
-};
-
-/*
- * Scan the alternatives table for a match and return the
- * index into the alternatives table if found, else -1.
- */
-static int find_alternative(unsigned int event)
-{
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-               if (event < event_alternatives[i][0])
-                       break;
-               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
-                       if (event == event_alternatives[i][j])
-                               return i;
-       }
-       return -1;
-}
-
-static const unsigned char bytedecode_alternatives[4][4] = {
-       /* PMC 1 */     { 0x21, 0x23, 0x25, 0x27 },
-       /* PMC 2 */     { 0x07, 0x17, 0x0e, 0x1e },
-       /* PMC 3 */     { 0x20, 0x22, 0x24, 0x26 },
-       /* PMC 4 */     { 0x07, 0x17, 0x0e, 0x1e }
-};
-
-/*
- * Some direct events for decodes of event bus byte 3 have alternative
- * PMCSEL values on other counters.  This returns the alternative
- * event code for those that do, or -1 otherwise.  This also handles
- * alternative PCMSEL values for add events.
- */
-static s64 find_alternative_bdecode(u64 event)
-{
-       int pmc, altpmc, pp, j;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc == 0 || pmc > 4)
-               return -1;
-       altpmc = 5 - pmc;       /* 1 <-> 4, 2 <-> 3 */
-       pp = event & PM_PMCSEL_MSK;
-       for (j = 0; j < 4; ++j) {
-               if (bytedecode_alternatives[pmc - 1][j] == pp) {
-                       return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
-                               (altpmc << PM_PMC_SH) |
-                               bytedecode_alternatives[altpmc - 1][j];
-               }
-       }
-
-       /* new decode alternatives for power5+ */
-       if (pmc == 1 && (pp == 0x0d || pp == 0x0e))
-               return event + (2 << PM_PMC_SH) + (0x2e - 0x0d);
-       if (pmc == 3 && (pp == 0x2e || pp == 0x2f))
-               return event - (2 << PM_PMC_SH) - (0x2e - 0x0d);
-
-       /* alternative add event encodings */
-       if (pp == 0x10 || pp == 0x28)
-               return ((event ^ (0x10 ^ 0x28)) & ~PM_PMC_MSKS) |
-                       (altpmc << PM_PMC_SH);
-
-       return -1;
-}
-
-static int power5p_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, nalt = 1;
-       int nlim;
-       s64 ae;
-
-       alt[0] = event;
-       nalt = 1;
-       nlim = power5p_limited_pmc_event(event);
-       i = find_alternative(event);
-       if (i >= 0) {
-               for (j = 0; j < MAX_ALT; ++j) {
-                       ae = event_alternatives[i][j];
-                       if (ae && ae != event)
-                               alt[nalt++] = ae;
-                       nlim += power5p_limited_pmc_event(ae);
-               }
-       } else {
-               ae = find_alternative_bdecode(event);
-               if (ae > 0)
-                       alt[nalt++] = ae;
-       }
-
-       if (flags & PPMU_ONLY_COUNT_RUN) {
-               /*
-                * We're only counting in RUN state,
-                * so PM_CYC is equivalent to PM_RUN_CYC
-                * and PM_INST_CMPL === PM_RUN_INST_CMPL.
-                * This doesn't include alternatives that don't provide
-                * any extra flexibility in assigning PMCs (e.g.
-                * 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC).
-                * Note that even with these additional alternatives
-                * we never end up with more than 3 alternatives for any event.
-                */
-               j = nalt;
-               for (i = 0; i < nalt; ++i) {
-                       switch (alt[i]) {
-                       case 0xf:       /* PM_CYC */
-                               alt[j++] = 0x600005;    /* PM_RUN_CYC */
-                               ++nlim;
-                               break;
-                       case 0x600005:  /* PM_RUN_CYC */
-                               alt[j++] = 0xf;
-                               break;
-                       case 0x100009:  /* PM_INST_CMPL */
-                               alt[j++] = 0x500009;    /* PM_RUN_INST_CMPL */
-                               ++nlim;
-                               break;
-                       case 0x500009:  /* PM_RUN_INST_CMPL */
-                               alt[j++] = 0x100009;    /* PM_INST_CMPL */
-                               alt[j++] = 0x200009;
-                               break;
-                       }
-               }
-               nalt = j;
-       }
-
-       if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
-               /* remove the limited PMC events */
-               j = 0;
-               for (i = 0; i < nalt; ++i) {
-                       if (!power5p_limited_pmc_event(alt[i])) {
-                               alt[j] = alt[i];
-                               ++j;
-                       }
-               }
-               nalt = j;
-       } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
-               /* remove all but the limited PMC events */
-               j = 0;
-               for (i = 0; i < nalt; ++i) {
-                       if (power5p_limited_pmc_event(alt[i])) {
-                               alt[j] = alt[i];
-                               ++j;
-                       }
-               }
-               nalt = j;
-       }
-
-       return nalt;
-}
-
-/*
- * Map of which direct events on which PMCs are marked instruction events.
- * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
- * Bit 0 is set if it is marked for all PMCs.
- * The 0x80 bit indicates a byte decode PMCSEL value.
- */
-static unsigned char direct_event_is_marked[0x28] = {
-       0,      /* 00 */
-       0x1f,   /* 01 PM_IOPS_CMPL */
-       0x2,    /* 02 PM_MRK_GRP_DISP */
-       0xe,    /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
-       0,      /* 04 */
-       0x1c,   /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
-       0x80,   /* 06 */
-       0x80,   /* 07 */
-       0, 0, 0,/* 08 - 0a */
-       0x18,   /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
-       0,      /* 0c */
-       0x80,   /* 0d */
-       0x80,   /* 0e */
-       0,      /* 0f */
-       0,      /* 10 */
-       0x14,   /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
-       0,      /* 12 */
-       0x10,   /* 13 PM_MRK_GRP_CMPL */
-       0x1f,   /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
-       0x2,    /* 15 PM_MRK_GRP_ISSUED */
-       0x80,   /* 16 */
-       0x80,   /* 17 */
-       0, 0, 0, 0, 0,
-       0x80,   /* 1d */
-       0x80,   /* 1e */
-       0,      /* 1f */
-       0x80,   /* 20 */
-       0x80,   /* 21 */
-       0x80,   /* 22 */
-       0x80,   /* 23 */
-       0x80,   /* 24 */
-       0x80,   /* 25 */
-       0x80,   /* 26 */
-       0x80,   /* 27 */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int power5p_marked_instr_event(u64 event)
-{
-       int pmc, psel;
-       int bit, byte, unit;
-       u32 mask;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = event & PM_PMCSEL_MSK;
-       if (pmc >= 5)
-               return 0;
-
-       bit = -1;
-       if (psel < sizeof(direct_event_is_marked)) {
-               if (direct_event_is_marked[psel] & (1 << pmc))
-                       return 1;
-               if (direct_event_is_marked[psel] & 0x80)
-                       bit = 4;
-               else if (psel == 0x08)
-                       bit = pmc - 1;
-               else if (psel == 0x10)
-                       bit = 4 - pmc;
-               else if (psel == 0x1b && (pmc == 1 || pmc == 3))
-                       bit = 4;
-       } else if ((psel & 0x48) == 0x40) {
-               bit = psel & 7;
-       } else if (psel == 0x28) {
-               bit = pmc - 1;
-       } else if (pmc == 3 && (psel == 0x2e || psel == 0x2f)) {
-               bit = 4;
-       }
-
-       if (!(event & PM_BUSEVENT_MSK) || bit == -1)
-               return 0;
-
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       if (unit == PM_LSU0) {
-               /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
-               mask = 0x5dff00;
-       } else if (unit == PM_LSU1 && byte >= 4) {
-               byte -= 4;
-               /* byte 5 bits 6-7, byte 6 bits 0,4, byte 7 bits 0-4,6 */
-               mask = 0x5f11c000;
-       } else
-               return 0;
-
-       return (mask >> (byte * 8 + bit)) & 1;
-}
-
-static int power5p_compute_mmcr(u64 event[], int n_ev,
-                               unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr1 = 0;
-       unsigned long mmcra = 0;
-       unsigned int pmc, unit, byte, psel;
-       unsigned int ttm;
-       int i, isbus, bit, grsel;
-       unsigned int pmc_inuse = 0;
-       unsigned char busbyte[4];
-       unsigned char unituse[16];
-       int ttmuse;
-
-       if (n_ev > 6)
-               return -1;
-
-       /* First pass to count resource use */
-       memset(busbyte, 0, sizeof(busbyte));
-       memset(unituse, 0, sizeof(unituse));
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc > 6)
-                               return -1;
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;
-                       pmc_inuse |= 1 << (pmc - 1);
-               }
-               if (event[i] & PM_BUSEVENT_MSK) {
-                       unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-                       byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-                       if (unit > PM_LASTUNIT)
-                               return -1;
-                       if (unit == PM_ISU0_ALT)
-                               unit = PM_ISU0;
-                       if (byte >= 4) {
-                               if (unit != PM_LSU1)
-                                       return -1;
-                               ++unit;
-                               byte &= 3;
-                       }
-                       if (busbyte[byte] && busbyte[byte] != unit)
-                               return -1;
-                       busbyte[byte] = unit;
-                       unituse[unit] = 1;
-               }
-       }
-
-       /*
-        * Assign resources and set multiplexer selects.
-        *
-        * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
-        * choice we have to deal with.
-        */
-       if (unituse[PM_ISU0] &
-           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
-               unituse[PM_ISU0_ALT] = 1;       /* move ISU to TTM1 */
-               unituse[PM_ISU0] = 0;
-       }
-       /* Set TTM[01]SEL fields. */
-       ttmuse = 0;
-       for (i = PM_FPU; i <= PM_ISU1; ++i) {
-               if (!unituse[i])
-                       continue;
-               if (ttmuse++)
-                       return -1;
-               mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
-       }
-       ttmuse = 0;
-       for (; i <= PM_GRS; ++i) {
-               if (!unituse[i])
-                       continue;
-               if (ttmuse++)
-                       return -1;
-               mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
-       }
-       if (ttmuse > 1)
-               return -1;
-
-       /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
-       for (byte = 0; byte < 4; ++byte) {
-               unit = busbyte[byte];
-               if (!unit)
-                       continue;
-               if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
-                       /* get ISU0 through TTM1 rather than TTM0 */
-                       unit = PM_ISU0_ALT;
-               } else if (unit == PM_LSU1 + 1) {
-                       /* select lower word of LSU1 for this byte */
-                       mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
-               }
-               ttm = unit >> 2;
-               mmcr1 |= (unsigned long)ttm
-                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-       }
-
-       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               psel = event[i] & PM_PMCSEL_MSK;
-               isbus = event[i] & PM_BUSEVENT_MSK;
-               if (!pmc) {
-                       /* Bus event or any-PMC direct event */
-                       for (pmc = 0; pmc < 4; ++pmc) {
-                               if (!(pmc_inuse & (1 << pmc)))
-                                       break;
-                       }
-                       if (pmc >= 4)
-                               return -1;
-                       pmc_inuse |= 1 << pmc;
-               } else if (pmc <= 4) {
-                       /* Direct event */
-                       --pmc;
-                       if (isbus && (byte & 2) &&
-                           (psel == 8 || psel == 0x10 || psel == 0x28))
-                               /* add events on higher-numbered bus */
-                               mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
-               } else {
-                       /* Instructions or run cycles on PMC5/6 */
-                       --pmc;
-               }
-               if (isbus && unit == PM_GRS) {
-                       bit = psel & 7;
-                       grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
-                       mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
-               }
-               if (power5p_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-               if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1))
-                       /* select alternate byte lane */
-                       psel |= 0x10;
-               if (pmc <= 3)
-                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
-               hwc[i] = pmc;
-       }
-
-       /* Return MMCRx values */
-       mmcr[0] = 0;
-       if (pmc_inuse & 1)
-               mmcr[0] = MMCR0_PMC1CE;
-       if (pmc_inuse & 0x3e)
-               mmcr[0] |= MMCR0_PMCjCE;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-static void power5p_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       if (pmc <= 3)
-               mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
-}
-
-static int power5p_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 0xf,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x100009,
-       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x1c10a8, /* LD_REF_L1 */
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c1088, /* LD_MISS_L1 */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x230e4,  /* BR_ISSUED */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x230e5,  /* BR_MPRED_CR */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x1c10a8,       0x3c1088        },
-               [C(OP_WRITE)] = {       0x2c10a8,       0xc10c3         },
-               [C(OP_PREFETCH)] = {    0xc70e7,        -1              },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0               },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    0,              0               },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0               },
-               [C(OP_WRITE)] = {       0,              0               },
-               [C(OP_PREFETCH)] = {    0xc50c3,        0               },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0xc20e4,        0x800c4         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x800c0         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x230e4,        0x230e5         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1              },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-};
-
-static struct power_pmu power5p_pmu = {
-       .name                   = "POWER5+/++",
-       .n_counter              = 6,
-       .max_alternatives       = MAX_ALT,
-       .add_fields             = 0x7000000000055ul,
-       .test_adder             = 0x3000040000000ul,
-       .compute_mmcr           = power5p_compute_mmcr,
-       .get_constraint         = power5p_get_constraint,
-       .get_alternatives       = power5p_get_alternatives,
-       .disable_pmc            = power5p_disable_pmc,
-       .limited_pmc_event      = power5p_limited_pmc_event,
-       .flags                  = PPMU_LIMITED_PMC5_6,
-       .n_generic              = ARRAY_SIZE(power5p_generic_events),
-       .generic_events         = power5p_generic_events,
-       .cache_events           = &power5p_cache_events,
-};
-
-static int __init init_power5p_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+")
-            && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")))
-               return -ENODEV;
-
-       return register_power_pmu(&power5p_pmu);
-}
-
-early_initcall(init_power5p_pmu);
diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/kernel/power5-pmu.c
deleted file mode 100644 (file)
index e7f06eb..0000000
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * Performance counter support for POWER5 (not POWER5++) processors.
- *
- * Copyright 2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER5 (not POWER5++)
- */
-#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0xf
-#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
-#define PM_UNIT_SH     16      /* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK    0xf
-#define PM_BYTE_SH     12      /* Byte number of event bus to use */
-#define PM_BYTE_MSK    7
-#define PM_GRS_SH      8       /* Storage subsystem mux select */
-#define PM_GRS_MSK     7
-#define PM_BUSEVENT_MSK        0x80    /* Set if event uses event bus */
-#define PM_PMCSEL_MSK  0x7f
-
-/* Values in PM_UNIT field */
-#define PM_FPU         0
-#define PM_ISU0                1
-#define PM_IFU         2
-#define PM_ISU1                3
-#define PM_IDU         4
-#define PM_ISU0_ALT    6
-#define PM_GRS         7
-#define PM_LSU0                8
-#define PM_LSU1                0xc
-#define PM_LASTUNIT    0xc
-
-/*
- * Bits in MMCR1 for POWER5
- */
-#define MMCR1_TTM0SEL_SH       62
-#define MMCR1_TTM1SEL_SH       60
-#define MMCR1_TTM2SEL_SH       58
-#define MMCR1_TTM3SEL_SH       56
-#define MMCR1_TTMSEL_MSK       3
-#define MMCR1_TD_CP_DBG0SEL_SH 54
-#define MMCR1_TD_CP_DBG1SEL_SH 52
-#define MMCR1_TD_CP_DBG2SEL_SH 50
-#define MMCR1_TD_CP_DBG3SEL_SH 48
-#define MMCR1_GRS_L2SEL_SH     46
-#define MMCR1_GRS_L2SEL_MSK    3
-#define MMCR1_GRS_L3SEL_SH     44
-#define MMCR1_GRS_L3SEL_MSK    3
-#define MMCR1_GRS_MCSEL_SH     41
-#define MMCR1_GRS_MCSEL_MSK    7
-#define MMCR1_GRS_FABSEL_SH    39
-#define MMCR1_GRS_FABSEL_MSK   3
-#define MMCR1_PMC1_ADDER_SEL_SH        35
-#define MMCR1_PMC2_ADDER_SEL_SH        34
-#define MMCR1_PMC3_ADDER_SEL_SH        33
-#define MMCR1_PMC4_ADDER_SEL_SH        32
-#define MMCR1_PMC1SEL_SH       25
-#define MMCR1_PMC2SEL_SH       17
-#define MMCR1_PMC3SEL_SH       9
-#define MMCR1_PMC4SEL_SH       1
-#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
-#define MMCR1_PMCSEL_MSK       0x7f
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *         <><>[  ><><>< ><> [  >[ >[ ><  ><  ><  ><  ><><><><><><>
- *         T0T1 NC G0G1G2 G3  UC PS1PS2 B0  B1  B2  B3 P6P5P4P3P2P1
- *
- * T0 - TTM0 constraint
- *     54-55: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0xc0_0000_0000_0000
- *
- * T1 - TTM1 constraint
- *     52-53: TTM1SEL value (0=IDU, 3=GRS) 0x30_0000_0000_0000
- *
- * NC - number of counters
- *     51: NC error 0x0008_0000_0000_0000
- *     48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
- *
- * G0..G3 - GRS mux constraints
- *     46-47: GRS_L2SEL value
- *     44-45: GRS_L3SEL value
- *     41-44: GRS_MCSEL value
- *     39-40: GRS_FABSEL value
- *     Note that these match up with their bit positions in MMCR1
- *
- * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
- *     37: UC3 error 0x20_0000_0000
- *     36: FPU|IFU|ISU1 events needed 0x10_0000_0000
- *     35: ISU0 events needed 0x08_0000_0000
- *     34: IDU|GRS events needed 0x04_0000_0000
- *
- * PS1
- *     33: PS1 error 0x2_0000_0000
- *     31-32: count of events needing PMC1/2 0x1_8000_0000
- *
- * PS2
- *     30: PS2 error 0x4000_0000
- *     28-29: count of events needing PMC3/4 0x3000_0000
- *
- * B0
- *     24-27: Byte 0 event source 0x0f00_0000
- *           Encoding as for the event code
- *
- * B1, B2, B3
- *     20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
- *
- * P1..P6
- *     0-11: Count of events needing PMC1..PMC6
- */
-
-static const int grsel_shift[8] = {
-       MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
-       MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
-       MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
-};
-
-/* Masks and values for using events from the various units */
-static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
-       [PM_FPU] =   { 0xc0002000000000ul, 0x00001000000000ul },
-       [PM_ISU0] =  { 0x00002000000000ul, 0x00000800000000ul },
-       [PM_ISU1] =  { 0xc0002000000000ul, 0xc0001000000000ul },
-       [PM_IFU] =   { 0xc0002000000000ul, 0x80001000000000ul },
-       [PM_IDU] =   { 0x30002000000000ul, 0x00000400000000ul },
-       [PM_GRS] =   { 0x30002000000000ul, 0x30000400000000ul },
-};
-
-static int power5_get_constraint(u64 event, unsigned long *maskp,
-                                unsigned long *valp)
-{
-       int pmc, byte, unit, sh;
-       int bit, fmask;
-       unsigned long mask = 0, value = 0;
-       int grp = -1;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 6)
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-               if (pmc <= 4)
-                       grp = (pmc - 1) >> 1;
-               else if (event != 0x500009 && event != 0x600005)
-                       return -1;
-       }
-       if (event & PM_BUSEVENT_MSK) {
-               unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-               if (unit > PM_LASTUNIT)
-                       return -1;
-               if (unit == PM_ISU0_ALT)
-                       unit = PM_ISU0;
-               mask |= unit_cons[unit][0];
-               value |= unit_cons[unit][1];
-               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-               if (byte >= 4) {
-                       if (unit != PM_LSU1)
-                               return -1;
-                       /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
-                       ++unit;
-                       byte &= 3;
-               }
-               if (unit == PM_GRS) {
-                       bit = event & 7;
-                       fmask = (bit == 6)? 7: 3;
-                       sh = grsel_shift[bit];
-                       mask |= (unsigned long)fmask << sh;
-                       value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
-                               << sh;
-               }
-               /*
-                * Bus events on bytes 0 and 2 can be counted
-                * on PMC1/2; bytes 1 and 3 on PMC3/4.
-                */
-               if (!pmc)
-                       grp = byte & 1;
-               /* Set byte lane select field */
-               mask  |= 0xfUL << (24 - 4 * byte);
-               value |= (unsigned long)unit << (24 - 4 * byte);
-       }
-       if (grp == 0) {
-               /* increment PMC1/2 field */
-               mask  |= 0x200000000ul;
-               value |= 0x080000000ul;
-       } else if (grp == 1) {
-               /* increment PMC3/4 field */
-               mask  |= 0x40000000ul;
-               value |= 0x10000000ul;
-       }
-       if (pmc < 5) {
-               /* need a counter from PMC1-4 set */
-               mask  |= 0x8000000000000ul;
-               value |= 0x1000000000000ul;
-       }
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-#define MAX_ALT        3       /* at most 3 alternatives for any event */
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-       { 0x120e4,  0x400002 },                 /* PM_GRP_DISP_REJECT */
-       { 0x410c7,  0x441084 },                 /* PM_THRD_L2MISS_BOTH_CYC */
-       { 0x100005, 0x600005 },                 /* PM_RUN_CYC */
-       { 0x100009, 0x200009, 0x500009 },       /* PM_INST_CMPL */
-       { 0x300009, 0x400009 },                 /* PM_INST_DISP */
-};
-
-/*
- * Scan the alternatives table for a match and return the
- * index into the alternatives table if found, else -1.
- */
-static int find_alternative(u64 event)
-{
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-               if (event < event_alternatives[i][0])
-                       break;
-               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
-                       if (event == event_alternatives[i][j])
-                               return i;
-       }
-       return -1;
-}
-
-static const unsigned char bytedecode_alternatives[4][4] = {
-       /* PMC 1 */     { 0x21, 0x23, 0x25, 0x27 },
-       /* PMC 2 */     { 0x07, 0x17, 0x0e, 0x1e },
-       /* PMC 3 */     { 0x20, 0x22, 0x24, 0x26 },
-       /* PMC 4 */     { 0x07, 0x17, 0x0e, 0x1e }
-};
-
-/*
- * Some direct events for decodes of event bus byte 3 have alternative
- * PMCSEL values on other counters.  This returns the alternative
- * event code for those that do, or -1 otherwise.
- */
-static s64 find_alternative_bdecode(u64 event)
-{
-       int pmc, altpmc, pp, j;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc == 0 || pmc > 4)
-               return -1;
-       altpmc = 5 - pmc;       /* 1 <-> 4, 2 <-> 3 */
-       pp = event & PM_PMCSEL_MSK;
-       for (j = 0; j < 4; ++j) {
-               if (bytedecode_alternatives[pmc - 1][j] == pp) {
-                       return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
-                               (altpmc << PM_PMC_SH) |
-                               bytedecode_alternatives[altpmc - 1][j];
-               }
-       }
-       return -1;
-}
-
-static int power5_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, nalt = 1;
-       s64 ae;
-
-       alt[0] = event;
-       nalt = 1;
-       i = find_alternative(event);
-       if (i >= 0) {
-               for (j = 0; j < MAX_ALT; ++j) {
-                       ae = event_alternatives[i][j];
-                       if (ae && ae != event)
-                               alt[nalt++] = ae;
-               }
-       } else {
-               ae = find_alternative_bdecode(event);
-               if (ae > 0)
-                       alt[nalt++] = ae;
-       }
-       return nalt;
-}
-
-/*
- * Map of which direct events on which PMCs are marked instruction events.
- * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
- * Bit 0 is set if it is marked for all PMCs.
- * The 0x80 bit indicates a byte decode PMCSEL value.
- */
-static unsigned char direct_event_is_marked[0x28] = {
-       0,      /* 00 */
-       0x1f,   /* 01 PM_IOPS_CMPL */
-       0x2,    /* 02 PM_MRK_GRP_DISP */
-       0xe,    /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
-       0,      /* 04 */
-       0x1c,   /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
-       0x80,   /* 06 */
-       0x80,   /* 07 */
-       0, 0, 0,/* 08 - 0a */
-       0x18,   /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
-       0,      /* 0c */
-       0x80,   /* 0d */
-       0x80,   /* 0e */
-       0,      /* 0f */
-       0,      /* 10 */
-       0x14,   /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
-       0,      /* 12 */
-       0x10,   /* 13 PM_MRK_GRP_CMPL */
-       0x1f,   /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
-       0x2,    /* 15 PM_MRK_GRP_ISSUED */
-       0x80,   /* 16 */
-       0x80,   /* 17 */
-       0, 0, 0, 0, 0,
-       0x80,   /* 1d */
-       0x80,   /* 1e */
-       0,      /* 1f */
-       0x80,   /* 20 */
-       0x80,   /* 21 */
-       0x80,   /* 22 */
-       0x80,   /* 23 */
-       0x80,   /* 24 */
-       0x80,   /* 25 */
-       0x80,   /* 26 */
-       0x80,   /* 27 */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int power5_marked_instr_event(u64 event)
-{
-       int pmc, psel;
-       int bit, byte, unit;
-       u32 mask;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = event & PM_PMCSEL_MSK;
-       if (pmc >= 5)
-               return 0;
-
-       bit = -1;
-       if (psel < sizeof(direct_event_is_marked)) {
-               if (direct_event_is_marked[psel] & (1 << pmc))
-                       return 1;
-               if (direct_event_is_marked[psel] & 0x80)
-                       bit = 4;
-               else if (psel == 0x08)
-                       bit = pmc - 1;
-               else if (psel == 0x10)
-                       bit = 4 - pmc;
-               else if (psel == 0x1b && (pmc == 1 || pmc == 3))
-                       bit = 4;
-       } else if ((psel & 0x58) == 0x40)
-               bit = psel & 7;
-
-       if (!(event & PM_BUSEVENT_MSK))
-               return 0;
-
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       if (unit == PM_LSU0) {
-               /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
-               mask = 0x5dff00;
-       } else if (unit == PM_LSU1 && byte >= 4) {
-               byte -= 4;
-               /* byte 4 bits 1,3,5,7, byte 5 bits 6-7, byte 7 bits 0-4,6 */
-               mask = 0x5f00c0aa;
-       } else
-               return 0;
-
-       return (mask >> (byte * 8 + bit)) & 1;
-}
-
-static int power5_compute_mmcr(u64 event[], int n_ev,
-                              unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr1 = 0;
-       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
-       unsigned int pmc, unit, byte, psel;
-       unsigned int ttm, grp;
-       int i, isbus, bit, grsel;
-       unsigned int pmc_inuse = 0;
-       unsigned int pmc_grp_use[2];
-       unsigned char busbyte[4];
-       unsigned char unituse[16];
-       int ttmuse;
-
-       if (n_ev > 6)
-               return -1;
-
-       /* First pass to count resource use */
-       pmc_grp_use[0] = pmc_grp_use[1] = 0;
-       memset(busbyte, 0, sizeof(busbyte));
-       memset(unituse, 0, sizeof(unituse));
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc > 6)
-                               return -1;
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;
-                       pmc_inuse |= 1 << (pmc - 1);
-                       /* count 1/2 vs 3/4 use */
-                       if (pmc <= 4)
-                               ++pmc_grp_use[(pmc - 1) >> 1];
-               }
-               if (event[i] & PM_BUSEVENT_MSK) {
-                       unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-                       byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-                       if (unit > PM_LASTUNIT)
-                               return -1;
-                       if (unit == PM_ISU0_ALT)
-                               unit = PM_ISU0;
-                       if (byte >= 4) {
-                               if (unit != PM_LSU1)
-                                       return -1;
-                               ++unit;
-                               byte &= 3;
-                       }
-                       if (!pmc)
-                               ++pmc_grp_use[byte & 1];
-                       if (busbyte[byte] && busbyte[byte] != unit)
-                               return -1;
-                       busbyte[byte] = unit;
-                       unituse[unit] = 1;
-               }
-       }
-       if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2)
-               return -1;
-
-       /*
-        * Assign resources and set multiplexer selects.
-        *
-        * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
-        * choice we have to deal with.
-        */
-       if (unituse[PM_ISU0] &
-           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
-               unituse[PM_ISU0_ALT] = 1;       /* move ISU to TTM1 */
-               unituse[PM_ISU0] = 0;
-       }
-       /* Set TTM[01]SEL fields. */
-       ttmuse = 0;
-       for (i = PM_FPU; i <= PM_ISU1; ++i) {
-               if (!unituse[i])
-                       continue;
-               if (ttmuse++)
-                       return -1;
-               mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
-       }
-       ttmuse = 0;
-       for (; i <= PM_GRS; ++i) {
-               if (!unituse[i])
-                       continue;
-               if (ttmuse++)
-                       return -1;
-               mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
-       }
-       if (ttmuse > 1)
-               return -1;
-
-       /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
-       for (byte = 0; byte < 4; ++byte) {
-               unit = busbyte[byte];
-               if (!unit)
-                       continue;
-               if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
-                       /* get ISU0 through TTM1 rather than TTM0 */
-                       unit = PM_ISU0_ALT;
-               } else if (unit == PM_LSU1 + 1) {
-                       /* select lower word of LSU1 for this byte */
-                       mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
-               }
-               ttm = unit >> 2;
-               mmcr1 |= (unsigned long)ttm
-                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-       }
-
-       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               psel = event[i] & PM_PMCSEL_MSK;
-               isbus = event[i] & PM_BUSEVENT_MSK;
-               if (!pmc) {
-                       /* Bus event or any-PMC direct event */
-                       for (pmc = 0; pmc < 4; ++pmc) {
-                               if (pmc_inuse & (1 << pmc))
-                                       continue;
-                               grp = (pmc >> 1) & 1;
-                               if (isbus) {
-                                       if (grp == (byte & 1))
-                                               break;
-                               } else if (pmc_grp_use[grp] < 2) {
-                                       ++pmc_grp_use[grp];
-                                       break;
-                               }
-                       }
-                       pmc_inuse |= 1 << pmc;
-               } else if (pmc <= 4) {
-                       /* Direct event */
-                       --pmc;
-                       if ((psel == 8 || psel == 0x10) && isbus && (byte & 2))
-                               /* add events on higher-numbered bus */
-                               mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
-               } else {
-                       /* Instructions or run cycles on PMC5/6 */
-                       --pmc;
-               }
-               if (isbus && unit == PM_GRS) {
-                       bit = psel & 7;
-                       grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
-                       mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
-               }
-               if (power5_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-               if (pmc <= 3)
-                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
-               hwc[i] = pmc;
-       }
-
-       /* Return MMCRx values */
-       mmcr[0] = 0;
-       if (pmc_inuse & 1)
-               mmcr[0] = MMCR0_PMC1CE;
-       if (pmc_inuse & 0x3e)
-               mmcr[0] |= MMCR0_PMCjCE;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-static void power5_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       if (pmc <= 3)
-               mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
-}
-
-static int power5_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 0xf,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x100009,
-       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x4c1090, /* LD_REF_L1 */
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c1088, /* LD_MISS_L1 */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x230e4,  /* BR_ISSUED */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x230e5,  /* BR_MPRED_CR */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x4c1090,       0x3c1088        },
-               [C(OP_WRITE)] = {       0x3c1090,       0xc10c3         },
-               [C(OP_PREFETCH)] = {    0xc70e7,        0               },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0               },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    0,              0               },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x3c309b        },
-               [C(OP_WRITE)] = {       0,              0               },
-               [C(OP_PREFETCH)] = {    0xc50c3,        0               },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x2c4090,       0x800c4         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x800c0         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x230e4,        0x230e5         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1              },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-};
-
-static struct power_pmu power5_pmu = {
-       .name                   = "POWER5",
-       .n_counter              = 6,
-       .max_alternatives       = MAX_ALT,
-       .add_fields             = 0x7000090000555ul,
-       .test_adder             = 0x3000490000000ul,
-       .compute_mmcr           = power5_compute_mmcr,
-       .get_constraint         = power5_get_constraint,
-       .get_alternatives       = power5_get_alternatives,
-       .disable_pmc            = power5_disable_pmc,
-       .n_generic              = ARRAY_SIZE(power5_generic_events),
-       .generic_events         = power5_generic_events,
-       .cache_events           = &power5_cache_events,
-};
-
-static int __init init_power5_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
-               return -ENODEV;
-
-       return register_power_pmu(&power5_pmu);
-}
-
-early_initcall(init_power5_pmu);
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c
deleted file mode 100644 (file)
index 0bbc901..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Performance counter support for POWER6 processors.
- *
- * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER6
- */
-#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0x7
-#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
-#define PM_UNIT_SH     16      /* Unit event comes (TTMxSEL encoding) */
-#define PM_UNIT_MSK    0xf
-#define PM_UNIT_MSKS   (PM_UNIT_MSK << PM_UNIT_SH)
-#define PM_LLAV                0x8000  /* Load lookahead match value */
-#define PM_LLA         0x4000  /* Load lookahead match enable */
-#define PM_BYTE_SH     12      /* Byte of event bus to use */
-#define PM_BYTE_MSK    3
-#define PM_SUBUNIT_SH  8       /* Subunit event comes from (NEST_SEL enc.) */
-#define PM_SUBUNIT_MSK 7
-#define PM_SUBUNIT_MSKS        (PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
-#define PM_PMCSEL_MSK  0xff    /* PMCxSEL value */
-#define PM_BUSEVENT_MSK        0xf3700
-
-/*
- * Bits in MMCR1 for POWER6
- */
-#define MMCR1_TTM0SEL_SH       60
-#define MMCR1_TTMSEL_SH(n)     (MMCR1_TTM0SEL_SH - (n) * 4)
-#define MMCR1_TTMSEL_MSK       0xf
-#define MMCR1_TTMSEL(m, n)     (((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
-#define MMCR1_NESTSEL_SH       45
-#define MMCR1_NESTSEL_MSK      0x7
-#define MMCR1_NESTSEL(m)       (((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
-#define MMCR1_PMC1_LLA         (1ul << 44)
-#define MMCR1_PMC1_LLA_VALUE   (1ul << 39)
-#define MMCR1_PMC1_ADDR_SEL    (1ul << 35)
-#define MMCR1_PMC1SEL_SH       24
-#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
-#define MMCR1_PMCSEL_MSK       0xff
-
-/*
- * Map of which direct events on which PMCs are marked instruction events.
- * Indexed by PMCSEL value >> 1.
- * Bottom 4 bits are a map of which PMCs are interesting,
- * top 4 bits say what sort of event:
- *   0 = direct marked event,
- *   1 = byte decode event,
- *   4 = add/and event (PMC1 -> bits 0 & 4),
- *   5 = add/and event (PMC1 -> bits 1 & 5),
- *   6 = add/and event (PMC1 -> bits 2 & 6),
- *   7 = add/and event (PMC1 -> bits 3 & 7).
- */
-static unsigned char direct_event_is_marked[0x60 >> 1] = {
-       0,      /* 00 */
-       0,      /* 02 */
-       0,      /* 04 */
-       0x07,   /* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
-       0x04,   /* 08 PM_MRK_DFU_FIN */
-       0x06,   /* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
-       0,      /* 0c */
-       0,      /* 0e */
-       0x02,   /* 10 PM_MRK_INST_DISP */
-       0x08,   /* 12 PM_MRK_LSU_DERAT_MISS */
-       0,      /* 14 */
-       0,      /* 16 */
-       0x0c,   /* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
-       0x0f,   /* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
-       0x01,   /* 1c PM_MRK_INST_ISSUED */
-       0,      /* 1e */
-       0,      /* 20 */
-       0,      /* 22 */
-       0,      /* 24 */
-       0,      /* 26 */
-       0x15,   /* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
-       0,      /* 2a */
-       0,      /* 2c */
-       0,      /* 2e */
-       0x4f,   /* 30 */
-       0x7f,   /* 32 */
-       0x4f,   /* 34 */
-       0x5f,   /* 36 */
-       0x6f,   /* 38 */
-       0x4f,   /* 3a */
-       0,      /* 3c */
-       0x08,   /* 3e PM_MRK_INST_TIMEO */
-       0x1f,   /* 40 */
-       0x1f,   /* 42 */
-       0x1f,   /* 44 */
-       0x1f,   /* 46 */
-       0x1f,   /* 48 */
-       0x1f,   /* 4a */
-       0x1f,   /* 4c */
-       0x1f,   /* 4e */
-       0,      /* 50 */
-       0x05,   /* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
-       0x1c,   /* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
-       0x02,   /* 56 PM_MRK_LD_MISS_L1 */
-       0,      /* 58 */
-       0,      /* 5a */
-       0,      /* 5c */
-       0,      /* 5e */
-};
-
-/*
- * Masks showing for each unit which bits are marked events.
- * These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
- */
-static u32 marked_bus_events[16] = {
-       0x01000000,     /* direct events set 1: byte 3 bit 0 */
-       0x00010000,     /* direct events set 2: byte 2 bit 0 */
-       0, 0, 0, 0,     /* IDU, IFU, nest: nothing */
-       0x00000088,     /* VMX set 1: byte 0 bits 3, 7 */
-       0x000000c0,     /* VMX set 2: byte 0 bits 4-7 */
-       0x04010000,     /* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
-       0xff010000u,    /* LSU set 2: byte 2 bit 0, all of byte 3 */
-       0,              /* LSU set 3 */
-       0x00000010,     /* VMX set 3: byte 0 bit 4 */
-       0,              /* BFP set 1 */
-       0x00000022,     /* BFP set 2: byte 0 bits 1, 5 */
-       0, 0
-};
-       
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int power6_marked_instr_event(u64 event)
-{
-       int pmc, psel, ptype;
-       int bit, byte, unit;
-       u32 mask;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = (event & PM_PMCSEL_MSK) >> 1;    /* drop edge/level bit */
-       if (pmc >= 5)
-               return 0;
-
-       bit = -1;
-       if (psel < sizeof(direct_event_is_marked)) {
-               ptype = direct_event_is_marked[psel];
-               if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
-                       return 0;
-               ptype >>= 4;
-               if (ptype == 0)
-                       return 1;
-               if (ptype == 1)
-                       bit = 0;
-               else
-                       bit = ptype ^ (pmc - 1);
-       } else if ((psel & 0x48) == 0x40)
-               bit = psel & 7;
-
-       if (!(event & PM_BUSEVENT_MSK) || bit == -1)
-               return 0;
-
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       mask = marked_bus_events[unit];
-       return (mask >> (byte * 8 + bit)) & 1;
-}
-
-/*
- * Assign PMC numbers and compute MMCR1 value for a set of events
- */
-static int p6_compute_mmcr(u64 event[], int n_ev,
-                          unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr1 = 0;
-       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
-       int i;
-       unsigned int pmc, ev, b, u, s, psel;
-       unsigned int ttmset = 0;
-       unsigned int pmc_inuse = 0;
-
-       if (n_ev > 6)
-               return -1;
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;      /* collision! */
-                       pmc_inuse |= 1 << (pmc - 1);
-               }
-       }
-       for (i = 0; i < n_ev; ++i) {
-               ev = event[i];
-               pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       --pmc;
-               } else {
-                       /* can go on any PMC; find a free one */
-                       for (pmc = 0; pmc < 4; ++pmc)
-                               if (!(pmc_inuse & (1 << pmc)))
-                                       break;
-                       if (pmc >= 4)
-                               return -1;
-                       pmc_inuse |= 1 << pmc;
-               }
-               hwc[i] = pmc;
-               psel = ev & PM_PMCSEL_MSK;
-               if (ev & PM_BUSEVENT_MSK) {
-                       /* this event uses the event bus */
-                       b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
-                       u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
-                       /* check for conflict on this byte of event bus */
-                       if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
-                               return -1;
-                       mmcr1 |= (unsigned long)u << MMCR1_TTMSEL_SH(b);
-                       ttmset |= 1 << b;
-                       if (u == 5) {
-                               /* Nest events have a further mux */
-                               s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
-                               if ((ttmset & 0x10) &&
-                                   MMCR1_NESTSEL(mmcr1) != s)
-                                       return -1;
-                               ttmset |= 0x10;
-                               mmcr1 |= (unsigned long)s << MMCR1_NESTSEL_SH;
-                       }
-                       if (0x30 <= psel && psel <= 0x3d) {
-                               /* these need the PMCx_ADDR_SEL bits */
-                               if (b >= 2)
-                                       mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
-                       }
-                       /* bus select values are different for PMC3/4 */
-                       if (pmc >= 2 && (psel & 0x90) == 0x80)
-                               psel ^= 0x20;
-               }
-               if (ev & PM_LLA) {
-                       mmcr1 |= MMCR1_PMC1_LLA >> pmc;
-                       if (ev & PM_LLAV)
-                               mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
-               }
-               if (power6_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-               if (pmc < 4)
-                       mmcr1 |= (unsigned long)psel << MMCR1_PMCSEL_SH(pmc);
-       }
-       mmcr[0] = 0;
-       if (pmc_inuse & 1)
-               mmcr[0] = MMCR0_PMC1CE;
-       if (pmc_inuse & 0xe)
-               mmcr[0] |= MMCR0_PMCjCE;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-/*
- * Layout of constraint bits:
- *
- *     0-1     add field: number of uses of PMC1 (max 1)
- *     2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
- *     12-15   add field: number of uses of PMC1-4 (max 4)
- *     16-19   select field: unit on byte 0 of event bus
- *     20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
- *     32-34   select field: nest (subunit) event selector
- */
-static int p6_get_constraint(u64 event, unsigned long *maskp,
-                            unsigned long *valp)
-{
-       int pmc, byte, sh, subunit;
-       unsigned long mask = 0, value = 0;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-       }
-       if (event & PM_BUSEVENT_MSK) {
-               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-               sh = byte * 4 + (16 - PM_UNIT_SH);
-               mask |= PM_UNIT_MSKS << sh;
-               value |= (unsigned long)(event & PM_UNIT_MSKS) << sh;
-               if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
-                       subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
-                       mask  |= (unsigned long)PM_SUBUNIT_MSK << 32;
-                       value |= (unsigned long)subunit << 32;
-               }
-       }
-       if (pmc <= 4) {
-               mask  |= 0x8000;        /* add field for count of PMC1-4 uses */
-               value |= 0x1000;
-       }
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-static int p6_limited_pmc_event(u64 event)
-{
-       int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-
-       return pmc == 5 || pmc == 6;
-}
-
-#define MAX_ALT        4       /* at most 4 alternatives for any event */
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-       { 0x0130e8, 0x2000f6, 0x3000fc },       /* PM_PTEG_RELOAD_VALID */
-       { 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
-       { 0x080088, 0x200054, 0x3000f0 },       /* PM_ST_MISS_L1 */
-       { 0x10000a, 0x2000f4, 0x600005 },       /* PM_RUN_CYC */
-       { 0x10000b, 0x2000f5 },                 /* PM_RUN_COUNT */
-       { 0x10000e, 0x400010 },                 /* PM_PURR */
-       { 0x100010, 0x4000f8 },                 /* PM_FLUSH */
-       { 0x10001a, 0x200010 },                 /* PM_MRK_INST_DISP */
-       { 0x100026, 0x3000f8 },                 /* PM_TB_BIT_TRANS */
-       { 0x100054, 0x2000f0 },                 /* PM_ST_FIN */
-       { 0x100056, 0x2000fc },                 /* PM_L1_ICACHE_MISS */
-       { 0x1000f0, 0x40000a },                 /* PM_INST_IMC_MATCH_CMPL */
-       { 0x1000f8, 0x200008 },                 /* PM_GCT_EMPTY_CYC */
-       { 0x1000fc, 0x400006 },                 /* PM_LSU_DERAT_MISS_CYC */
-       { 0x20000e, 0x400007 },                 /* PM_LSU_DERAT_MISS */
-       { 0x200012, 0x300012 },                 /* PM_INST_DISP */
-       { 0x2000f2, 0x3000f2 },                 /* PM_INST_DISP */
-       { 0x2000f8, 0x300010 },                 /* PM_EXT_INT */
-       { 0x2000fe, 0x300056 },                 /* PM_DATA_FROM_L2MISS */
-       { 0x2d0030, 0x30001a },                 /* PM_MRK_FPU_FIN */
-       { 0x30000a, 0x400018 },                 /* PM_MRK_INST_FIN */
-       { 0x3000f6, 0x40000e },                 /* PM_L1_DCACHE_RELOAD_VALID */
-       { 0x3000fe, 0x400056 },                 /* PM_DATA_FROM_L3MISS */
-};
-
-/*
- * This could be made more efficient with a binary search on
- * a presorted list, if necessary
- */
-static int find_alternatives_list(u64 event)
-{
-       int i, j;
-       unsigned int alt;
-
-       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-               if (event < event_alternatives[i][0])
-                       return -1;
-               for (j = 0; j < MAX_ALT; ++j) {
-                       alt = event_alternatives[i][j];
-                       if (!alt || event < alt)
-                               break;
-                       if (event == alt)
-                               return i;
-               }
-       }
-       return -1;
-}
-
-static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, nlim;
-       unsigned int psel, pmc;
-       unsigned int nalt = 1;
-       u64 aevent;
-
-       alt[0] = event;
-       nlim = p6_limited_pmc_event(event);
-
-       /* check the alternatives table */
-       i = find_alternatives_list(event);
-       if (i >= 0) {
-               /* copy out alternatives from list */
-               for (j = 0; j < MAX_ALT; ++j) {
-                       aevent = event_alternatives[i][j];
-                       if (!aevent)
-                               break;
-                       if (aevent != event)
-                               alt[nalt++] = aevent;
-                       nlim += p6_limited_pmc_event(aevent);
-               }
-
-       } else {
-               /* Check for alternative ways of computing sum events */
-               /* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
-               psel = event & (PM_PMCSEL_MSK & ~1);    /* ignore edge bit */
-               pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc && (psel == 0x32 || psel == 0x34))
-                       alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
-                               ((5 - pmc) << PM_PMC_SH);
-
-               /* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
-               if (pmc && (psel == 0x38 || psel == 0x3a))
-                       alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
-                               ((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
-       }
-
-       if (flags & PPMU_ONLY_COUNT_RUN) {
-               /*
-                * We're only counting in RUN state,
-                * so PM_CYC is equivalent to PM_RUN_CYC,
-                * PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
-                * This doesn't include alternatives that don't provide
-                * any extra flexibility in assigning PMCs (e.g.
-                * 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
-                * Note that even with these additional alternatives
-                * we never end up with more than 4 alternatives for any event.
-                */
-               j = nalt;
-               for (i = 0; i < nalt; ++i) {
-                       switch (alt[i]) {
-                       case 0x1e:      /* PM_CYC */
-                               alt[j++] = 0x600005;    /* PM_RUN_CYC */
-                               ++nlim;
-                               break;
-                       case 0x10000a:  /* PM_RUN_CYC */
-                               alt[j++] = 0x1e;        /* PM_CYC */
-                               break;
-                       case 2:         /* PM_INST_CMPL */
-                               alt[j++] = 0x500009;    /* PM_RUN_INST_CMPL */
-                               ++nlim;
-                               break;
-                       case 0x500009:  /* PM_RUN_INST_CMPL */
-                               alt[j++] = 2;           /* PM_INST_CMPL */
-                               break;
-                       case 0x10000e:  /* PM_PURR */
-                               alt[j++] = 0x4000f4;    /* PM_RUN_PURR */
-                               break;
-                       case 0x4000f4:  /* PM_RUN_PURR */
-                               alt[j++] = 0x10000e;    /* PM_PURR */
-                               break;
-                       }
-               }
-               nalt = j;
-       }
-
-       if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
-               /* remove the limited PMC events */
-               j = 0;
-               for (i = 0; i < nalt; ++i) {
-                       if (!p6_limited_pmc_event(alt[i])) {
-                               alt[j] = alt[i];
-                               ++j;
-                       }
-               }
-               nalt = j;
-       } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
-               /* remove all but the limited PMC events */
-               j = 0;
-               for (i = 0; i < nalt; ++i) {
-                       if (p6_limited_pmc_event(alt[i])) {
-                               alt[j] = alt[i];
-                               ++j;
-                       }
-               }
-               nalt = j;
-       }
-
-       return nalt;
-}
-
-static void p6_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       /* Set PMCxSEL to 0 to disable PMCx */
-       if (pmc <= 3)
-               mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
-}
-
-static int power6_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 0x1e,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 2,
-       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x280030, /* LD_REF_L1 */
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x30000c, /* LD_MISS_L1 */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x410a0,  /* BR_PRED */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x400052, /* BR_MPRED */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- * The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
- */
-static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x280030,       0x80080         },
-               [C(OP_WRITE)] = {       0x180032,       0x80088         },
-               [C(OP_PREFETCH)] = {    0x810a4,        0               },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x100056        },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    0x4008c,        0               },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x150730,       0x250532        },
-               [C(OP_WRITE)] = {       0x250432,       0x150432        },
-               [C(OP_PREFETCH)] = {    0x810a6,        0               },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x20000e        },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x420ce         },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x430e6,        0x400052        },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1              },
-               [C(OP_WRITE)] = {       -1,             -1              },
-               [C(OP_PREFETCH)] = {    -1,             -1              },
-       },
-};
-
-static struct power_pmu power6_pmu = {
-       .name                   = "POWER6",
-       .n_counter              = 6,
-       .max_alternatives       = MAX_ALT,
-       .add_fields             = 0x1555,
-       .test_adder             = 0x3000,
-       .compute_mmcr           = p6_compute_mmcr,
-       .get_constraint         = p6_get_constraint,
-       .get_alternatives       = p6_get_alternatives,
-       .disable_pmc            = p6_disable_pmc,
-       .limited_pmc_event      = p6_limited_pmc_event,
-       .flags                  = PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
-       .n_generic              = ARRAY_SIZE(power6_generic_events),
-       .generic_events         = power6_generic_events,
-       .cache_events           = &power6_cache_events,
-};
-
-static int __init init_power6_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
-               return -ENODEV;
-
-       return register_power_pmu(&power6_pmu);
-}
-
-early_initcall(init_power6_pmu);
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c
deleted file mode 100644 (file)
index 1251e4d..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Performance counter support for POWER7 processors.
- *
- * Copyright 2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/perf_event.h>
-#include <linux/string.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for POWER7
- */
-#define PM_PMC_SH      16      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0xf
-#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
-#define PM_UNIT_SH     12      /* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK    0xf
-#define PM_COMBINE_SH  11      /* Combined event bit */
-#define PM_COMBINE_MSK 1
-#define PM_COMBINE_MSKS        0x800
-#define PM_L2SEL_SH    8       /* L2 event select */
-#define PM_L2SEL_MSK   7
-#define PM_PMCSEL_MSK  0xff
-
-/*
- * Bits in MMCR1 for POWER7
- */
-#define MMCR1_TTM0SEL_SH       60
-#define MMCR1_TTM1SEL_SH       56
-#define MMCR1_TTM2SEL_SH       52
-#define MMCR1_TTM3SEL_SH       48
-#define MMCR1_TTMSEL_MSK       0xf
-#define MMCR1_L2SEL_SH         45
-#define MMCR1_L2SEL_MSK                7
-#define MMCR1_PMC1_COMBINE_SH  35
-#define MMCR1_PMC2_COMBINE_SH  34
-#define MMCR1_PMC3_COMBINE_SH  33
-#define MMCR1_PMC4_COMBINE_SH  32
-#define MMCR1_PMC1SEL_SH       24
-#define MMCR1_PMC2SEL_SH       16
-#define MMCR1_PMC3SEL_SH       8
-#define MMCR1_PMC4SEL_SH       0
-#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
-#define MMCR1_PMCSEL_MSK       0xff
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *                                                 [  ><><><><><><>
- *                                                  NC P6P5P4P3P2P1
- *
- * NC - number of counters
- *     15: NC error 0x8000
- *     12-14: number of events needing PMC1-4 0x7000
- *
- * P6
- *     11: P6 error 0x800
- *     10-11: Count of events needing PMC6
- *
- * P1..P5
- *     0-9: Count of events needing PMC1..PMC5
- */
-
-static int power7_get_constraint(u64 event, unsigned long *maskp,
-                                unsigned long *valp)
-{
-       int pmc, sh;
-       unsigned long mask = 0, value = 0;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 6)
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-               if (pmc >= 5 && !(event == 0x500fa || event == 0x600f4))
-                       return -1;
-       }
-       if (pmc < 5) {
-               /* need a counter from PMC1-4 set */
-               mask  |= 0x8000;
-               value |= 0x1000;
-       }
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-#define MAX_ALT        2       /* at most 2 alternatives for any event */
-
-static const unsigned int event_alternatives[][MAX_ALT] = {
-       { 0x200f2, 0x300f2 },           /* PM_INST_DISP */
-       { 0x200f4, 0x600f4 },           /* PM_RUN_CYC */
-       { 0x400fa, 0x500fa },           /* PM_RUN_INST_CMPL */
-};
-
-/*
- * Scan the alternatives table for a match and return the
- * index into the alternatives table if found, else -1.
- */
-static int find_alternative(u64 event)
-{
-       int i, j;
-
-       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
-               if (event < event_alternatives[i][0])
-                       break;
-               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
-                       if (event == event_alternatives[i][j])
-                               return i;
-       }
-       return -1;
-}
-
-static s64 find_alternative_decode(u64 event)
-{
-       int pmc, psel;
-
-       /* this only handles the 4x decode events */
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = event & PM_PMCSEL_MSK;
-       if ((pmc == 2 || pmc == 4) && (psel & ~7) == 0x40)
-               return event - (1 << PM_PMC_SH) + 8;
-       if ((pmc == 1 || pmc == 3) && (psel & ~7) == 0x48)
-               return event + (1 << PM_PMC_SH) - 8;
-       return -1;
-}
-
-static int power7_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       int i, j, nalt = 1;
-       s64 ae;
-
-       alt[0] = event;
-       nalt = 1;
-       i = find_alternative(event);
-       if (i >= 0) {
-               for (j = 0; j < MAX_ALT; ++j) {
-                       ae = event_alternatives[i][j];
-                       if (ae && ae != event)
-                               alt[nalt++] = ae;
-               }
-       } else {
-               ae = find_alternative_decode(event);
-               if (ae > 0)
-                       alt[nalt++] = ae;
-       }
-
-       if (flags & PPMU_ONLY_COUNT_RUN) {
-               /*
-                * We're only counting in RUN state,
-                * so PM_CYC is equivalent to PM_RUN_CYC
-                * and PM_INST_CMPL === PM_RUN_INST_CMPL.
-                * This doesn't include alternatives that don't provide
-                * any extra flexibility in assigning PMCs.
-                */
-               j = nalt;
-               for (i = 0; i < nalt; ++i) {
-                       switch (alt[i]) {
-                       case 0x1e:      /* PM_CYC */
-                               alt[j++] = 0x600f4;     /* PM_RUN_CYC */
-                               break;
-                       case 0x600f4:   /* PM_RUN_CYC */
-                               alt[j++] = 0x1e;
-                               break;
-                       case 0x2:       /* PM_PPC_CMPL */
-                               alt[j++] = 0x500fa;     /* PM_RUN_INST_CMPL */
-                               break;
-                       case 0x500fa:   /* PM_RUN_INST_CMPL */
-                               alt[j++] = 0x2; /* PM_PPC_CMPL */
-                               break;
-                       }
-               }
-               nalt = j;
-       }
-
-       return nalt;
-}
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int power7_marked_instr_event(u64 event)
-{
-       int pmc, psel;
-       int unit;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       psel = event & PM_PMCSEL_MSK & ~1;      /* trim off edge/level bit */
-       if (pmc >= 5)
-               return 0;
-
-       switch (psel >> 4) {
-       case 2:
-               return pmc == 2 || pmc == 4;
-       case 3:
-               if (psel == 0x3c)
-                       return pmc == 1;
-               if (psel == 0x3e)
-                       return pmc != 2;
-               return 1;
-       case 4:
-       case 5:
-               return unit == 0xd;
-       case 6:
-               if (psel == 0x64)
-                       return pmc >= 3;
-       case 8:
-               return unit == 0xd;
-       }
-       return 0;
-}
-
-static int power7_compute_mmcr(u64 event[], int n_ev,
-                              unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr1 = 0;
-       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
-       unsigned int pmc, unit, combine, l2sel, psel;
-       unsigned int pmc_inuse = 0;
-       int i;
-
-       /* First pass to count resource use */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc > 6)
-                               return -1;
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;
-                       pmc_inuse |= 1 << (pmc - 1);
-               }
-       }
-
-       /* Second pass: assign PMCs, set all MMCR1 fields */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               combine = (event[i] >> PM_COMBINE_SH) & PM_COMBINE_MSK;
-               l2sel = (event[i] >> PM_L2SEL_SH) & PM_L2SEL_MSK;
-               psel = event[i] & PM_PMCSEL_MSK;
-               if (!pmc) {
-                       /* Bus event or any-PMC direct event */
-                       for (pmc = 0; pmc < 4; ++pmc) {
-                               if (!(pmc_inuse & (1 << pmc)))
-                                       break;
-                       }
-                       if (pmc >= 4)
-                               return -1;
-                       pmc_inuse |= 1 << pmc;
-               } else {
-                       /* Direct or decoded event */
-                       --pmc;
-               }
-               if (pmc <= 3) {
-                       mmcr1 |= (unsigned long) unit
-                               << (MMCR1_TTM0SEL_SH - 4 * pmc);
-                       mmcr1 |= (unsigned long) combine
-                               << (MMCR1_PMC1_COMBINE_SH - pmc);
-                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
-                       if (unit == 6)  /* L2 events */
-                               mmcr1 |= (unsigned long) l2sel
-                                       << MMCR1_L2SEL_SH;
-               }
-               if (power7_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-               hwc[i] = pmc;
-       }
-
-       /* Return MMCRx values */
-       mmcr[0] = 0;
-       if (pmc_inuse & 1)
-               mmcr[0] = MMCR0_PMC1CE;
-       if (pmc_inuse & 0x3e)
-               mmcr[0] |= MMCR0_PMCjCE;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       if (pmc <= 3)
-               mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
-}
-
-static int power7_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
-       [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */
-       [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a,  /* CMPLU_STALL */
-       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
-       [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880,      /* LD_REF_L1_LSU*/
-       [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0,         /* LD_MISS_L1   */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068,  /* BRU_FIN      */
-       [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6,        /* BR_MPRED     */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0xc880,         0x400f0 },
-               [C(OP_WRITE)] = {       0,              0x300f0 },
-               [C(OP_PREFETCH)] = {    0xd8b8,         0       },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x200fc },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    0x408a,         0       },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x16080,        0x26080 },
-               [C(OP_WRITE)] = {       0x16082,        0x26082 },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x300fc },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x400fc },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x10068,        0x400f6 },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-};
-
-static struct power_pmu power7_pmu = {
-       .name                   = "POWER7",
-       .n_counter              = 6,
-       .max_alternatives       = MAX_ALT + 1,
-       .add_fields             = 0x1555ul,
-       .test_adder             = 0x3000ul,
-       .compute_mmcr           = power7_compute_mmcr,
-       .get_constraint         = power7_get_constraint,
-       .get_alternatives       = power7_get_alternatives,
-       .disable_pmc            = power7_disable_pmc,
-       .flags                  = PPMU_ALT_SIPR,
-       .n_generic              = ARRAY_SIZE(power7_generic_events),
-       .generic_events         = power7_generic_events,
-       .cache_events           = &power7_cache_events,
-};
-
-static int __init init_power7_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
-               return -ENODEV;
-
-       return register_power_pmu(&power7_pmu);
-}
-
-early_initcall(init_power7_pmu);
diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/kernel/ppc970-pmu.c
deleted file mode 100644 (file)
index 8c21902..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Performance counter support for PPC970-family processors.
- *
- * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/string.h>
-#include <linux/perf_event.h>
-#include <asm/reg.h>
-#include <asm/cputable.h>
-
-/*
- * Bits in event code for PPC970
- */
-#define PM_PMC_SH      12      /* PMC number (1-based) for direct events */
-#define PM_PMC_MSK     0xf
-#define PM_UNIT_SH     8       /* TTMMUX number and setting - unit select */
-#define PM_UNIT_MSK    0xf
-#define PM_SPCSEL_SH   6
-#define PM_SPCSEL_MSK  3
-#define PM_BYTE_SH     4       /* Byte number of event bus to use */
-#define PM_BYTE_MSK    3
-#define PM_PMCSEL_MSK  0xf
-
-/* Values in PM_UNIT field */
-#define PM_NONE                0
-#define PM_FPU         1
-#define PM_VPU         2
-#define PM_ISU         3
-#define PM_IFU         4
-#define PM_IDU         5
-#define PM_STS         6
-#define PM_LSU0                7
-#define PM_LSU1U       8
-#define PM_LSU1L       9
-#define PM_LASTUNIT    9
-
-/*
- * Bits in MMCR0 for PPC970
- */
-#define MMCR0_PMC1SEL_SH       8
-#define MMCR0_PMC2SEL_SH       1
-#define MMCR_PMCSEL_MSK                0x1f
-
-/*
- * Bits in MMCR1 for PPC970
- */
-#define MMCR1_TTM0SEL_SH       62
-#define MMCR1_TTM1SEL_SH       59
-#define MMCR1_TTM3SEL_SH       53
-#define MMCR1_TTMSEL_MSK       3
-#define MMCR1_TD_CP_DBG0SEL_SH 50
-#define MMCR1_TD_CP_DBG1SEL_SH 48
-#define MMCR1_TD_CP_DBG2SEL_SH 46
-#define MMCR1_TD_CP_DBG3SEL_SH 44
-#define MMCR1_PMC1_ADDER_SEL_SH        39
-#define MMCR1_PMC2_ADDER_SEL_SH        38
-#define MMCR1_PMC6_ADDER_SEL_SH        37
-#define MMCR1_PMC5_ADDER_SEL_SH        36
-#define MMCR1_PMC8_ADDER_SEL_SH        35
-#define MMCR1_PMC7_ADDER_SEL_SH        34
-#define MMCR1_PMC3_ADDER_SEL_SH        33
-#define MMCR1_PMC4_ADDER_SEL_SH        32
-#define MMCR1_PMC3SEL_SH       27
-#define MMCR1_PMC4SEL_SH       22
-#define MMCR1_PMC5SEL_SH       17
-#define MMCR1_PMC6SEL_SH       12
-#define MMCR1_PMC7SEL_SH       7
-#define MMCR1_PMC8SEL_SH       2
-
-static short mmcr1_adder_bits[8] = {
-       MMCR1_PMC1_ADDER_SEL_SH,
-       MMCR1_PMC2_ADDER_SEL_SH,
-       MMCR1_PMC3_ADDER_SEL_SH,
-       MMCR1_PMC4_ADDER_SEL_SH,
-       MMCR1_PMC5_ADDER_SEL_SH,
-       MMCR1_PMC6_ADDER_SEL_SH,
-       MMCR1_PMC7_ADDER_SEL_SH,
-       MMCR1_PMC8_ADDER_SEL_SH
-};
-
-/*
- * Layout of constraint bits:
- * 6666555555555544444444443333333333222222222211111111110000000000
- * 3210987654321098765432109876543210987654321098765432109876543210
- *               <><><>[  >[  >[  ><  ><  ><  ><  ><><><><><><><><>
- *               SPT0T1 UC  PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
- *
- * SP - SPCSEL constraint
- *     48-49: SPCSEL value 0x3_0000_0000_0000
- *
- * T0 - TTM0 constraint
- *     46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
- *
- * T1 - TTM1 constraint
- *     44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
- *
- * UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
- *     43: UC3 error 0x0800_0000_0000
- *     42: FPU|IFU|VPU events needed 0x0400_0000_0000
- *     41: ISU events needed 0x0200_0000_0000
- *     40: IDU|STS events needed 0x0100_0000_0000
- *
- * PS1
- *     39: PS1 error 0x0080_0000_0000
- *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
- *
- * PS2
- *     35: PS2 error 0x0008_0000_0000
- *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
- *
- * B0
- *     28-31: Byte 0 event source 0xf000_0000
- *           Encoding as for the event code
- *
- * B1, B2, B3
- *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
- *
- * P1
- *     15: P1 error 0x8000
- *     14-15: Count of events needing PMC1
- *
- * P2..P8
- *     0-13: Count of events needing PMC2..PMC8
- */
-
-static unsigned char direct_marked_event[8] = {
-       (1<<2) | (1<<3),        /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
-       (1<<3) | (1<<5),        /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
-       (1<<3) | (1<<5),        /* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
-       (1<<4) | (1<<5),        /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
-       (1<<4) | (1<<5),        /* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
-       (1<<3) | (1<<4) | (1<<5),
-               /* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
-       (1<<4) | (1<<5),        /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
-       (1<<4)                  /* PMC8: PM_MRK_LSU_FIN */
-};
-
-/*
- * Returns 1 if event counts things relating to marked instructions
- * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
- */
-static int p970_marked_instr_event(u64 event)
-{
-       int pmc, psel, unit, byte, bit;
-       unsigned int mask;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       psel = event & PM_PMCSEL_MSK;
-       if (pmc) {
-               if (direct_marked_event[pmc - 1] & (1 << psel))
-                       return 1;
-               if (psel == 0)          /* add events */
-                       bit = (pmc <= 4)? pmc - 1: 8 - pmc;
-               else if (psel == 7 || psel == 13)       /* decode events */
-                       bit = 4;
-               else
-                       return 0;
-       } else
-               bit = psel;
-
-       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       mask = 0;
-       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;
-       }
-       return (mask >> (byte * 8 + bit)) & 1;
-}
-
-/* Masks and values for using events from the various units */
-static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
-       [PM_FPU] =   { 0xc80000000000ull, 0x040000000000ull },
-       [PM_VPU] =   { 0xc80000000000ull, 0xc40000000000ull },
-       [PM_ISU] =   { 0x080000000000ull, 0x020000000000ull },
-       [PM_IFU] =   { 0xc80000000000ull, 0x840000000000ull },
-       [PM_IDU] =   { 0x380000000000ull, 0x010000000000ull },
-       [PM_STS] =   { 0x380000000000ull, 0x310000000000ull },
-};
-
-static int p970_get_constraint(u64 event, unsigned long *maskp,
-                              unsigned long *valp)
-{
-       int pmc, byte, unit, sh, spcsel;
-       unsigned long mask = 0, value = 0;
-       int grp = -1;
-
-       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
-       if (pmc) {
-               if (pmc > 8)
-                       return -1;
-               sh = (pmc - 1) * 2;
-               mask |= 2 << sh;
-               value |= 1 << sh;
-               grp = ((pmc - 1) >> 1) & 1;
-       }
-       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
-       if (unit) {
-               if (unit > PM_LASTUNIT)
-                       return -1;
-               mask |= unit_cons[unit][0];
-               value |= unit_cons[unit][1];
-               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
-               /*
-                * Bus events on bytes 0 and 2 can be counted
-                * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
-                */
-               if (!pmc)
-                       grp = byte & 1;
-               /* Set byte lane select field */
-               mask  |= 0xfULL << (28 - 4 * byte);
-               value |= (unsigned long)unit << (28 - 4 * byte);
-       }
-       if (grp == 0) {
-               /* increment PMC1/2/5/6 field */
-               mask  |= 0x8000000000ull;
-               value |= 0x1000000000ull;
-       } else if (grp == 1) {
-               /* increment PMC3/4/7/8 field */
-               mask  |= 0x800000000ull;
-               value |= 0x100000000ull;
-       }
-       spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
-       if (spcsel) {
-               mask  |= 3ull << 48;
-               value |= (unsigned long)spcsel << 48;
-       }
-       *maskp = mask;
-       *valp = value;
-       return 0;
-}
-
-static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
-{
-       alt[0] = event;
-
-       /* 2 alternatives for LSU empty */
-       if (event == 0x2002 || event == 0x3002) {
-               alt[1] = event ^ 0x1000;
-               return 2;
-       }
-               
-       return 1;
-}
-
-static int p970_compute_mmcr(u64 event[], int n_ev,
-                            unsigned int hwc[], unsigned long mmcr[])
-{
-       unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
-       unsigned int pmc, unit, byte, psel;
-       unsigned int ttm, grp;
-       unsigned int pmc_inuse = 0;
-       unsigned int pmc_grp_use[2];
-       unsigned char busbyte[4];
-       unsigned char unituse[16];
-       unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
-       unsigned char ttmuse[2];
-       unsigned char pmcsel[8];
-       int i;
-       int spcsel;
-
-       if (n_ev > 8)
-               return -1;
-
-       /* First pass to count resource use */
-       pmc_grp_use[0] = pmc_grp_use[1] = 0;
-       memset(busbyte, 0, sizeof(busbyte));
-       memset(unituse, 0, sizeof(unituse));
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               if (pmc) {
-                       if (pmc_inuse & (1 << (pmc - 1)))
-                               return -1;
-                       pmc_inuse |= 1 << (pmc - 1);
-                       /* count 1/2/5/6 vs 3/4/7/8 use */
-                       ++pmc_grp_use[((pmc - 1) >> 1) & 1];
-               }
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               if (unit) {
-                       if (unit > PM_LASTUNIT)
-                               return -1;
-                       if (!pmc)
-                               ++pmc_grp_use[byte & 1];
-                       if (busbyte[byte] && busbyte[byte] != unit)
-                               return -1;
-                       busbyte[byte] = unit;
-                       unituse[unit] = 1;
-               }
-       }
-       if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
-               return -1;
-
-       /*
-        * Assign resources and set multiplexer selects.
-        *
-        * PM_ISU can go either on TTM0 or TTM1, but that's the only
-        * choice we have to deal with.
-        */
-       if (unituse[PM_ISU] &
-           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
-               unitmap[PM_ISU] = 2 | 4;        /* move ISU to TTM1 */
-       /* Set TTM[01]SEL fields. */
-       ttmuse[0] = ttmuse[1] = 0;
-       for (i = PM_FPU; i <= PM_STS; ++i) {
-               if (!unituse[i])
-                       continue;
-               ttm = unitmap[i];
-               ++ttmuse[(ttm >> 2) & 1];
-               mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
-       }
-       /* Check only one unit per TTMx */
-       if (ttmuse[0] > 1 || ttmuse[1] > 1)
-               return -1;
-
-       /* Set byte lane select fields and TTM3SEL. */
-       for (byte = 0; byte < 4; ++byte) {
-               unit = busbyte[byte];
-               if (!unit)
-                       continue;
-               if (unit <= PM_STS)
-                       ttm = (unitmap[unit] >> 2) & 1;
-               else if (unit == PM_LSU0)
-                       ttm = 2;
-               else {
-                       ttm = 3;
-                       if (unit == PM_LSU1L && byte >= 2)
-                               mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
-               }
-               mmcr1 |= (unsigned long)ttm
-                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
-       }
-
-       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
-       memset(pmcsel, 0x8, sizeof(pmcsel));    /* 8 means don't count */
-       for (i = 0; i < n_ev; ++i) {
-               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
-               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
-               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
-               psel = event[i] & PM_PMCSEL_MSK;
-               if (!pmc) {
-                       /* Bus event or any-PMC direct event */
-                       if (unit)
-                               psel |= 0x10 | ((byte & 2) << 2);
-                       else
-                               psel |= 8;
-                       for (pmc = 0; pmc < 8; ++pmc) {
-                               if (pmc_inuse & (1 << pmc))
-                                       continue;
-                               grp = (pmc >> 1) & 1;
-                               if (unit) {
-                                       if (grp == (byte & 1))
-                                               break;
-                               } else if (pmc_grp_use[grp] < 4) {
-                                       ++pmc_grp_use[grp];
-                                       break;
-                               }
-                       }
-                       pmc_inuse |= 1 << pmc;
-               } else {
-                       /* Direct event */
-                       --pmc;
-                       if (psel == 0 && (byte & 2))
-                               /* add events on higher-numbered bus */
-                               mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
-               }
-               pmcsel[pmc] = psel;
-               hwc[i] = pmc;
-               spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
-               mmcr1 |= spcsel;
-               if (p970_marked_instr_event(event[i]))
-                       mmcra |= MMCRA_SAMPLE_ENABLE;
-       }
-       for (pmc = 0; pmc < 2; ++pmc)
-               mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
-       for (; pmc < 8; ++pmc)
-               mmcr1 |= (unsigned long)pmcsel[pmc]
-                       << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
-       if (pmc_inuse & 1)
-               mmcr0 |= MMCR0_PMC1CE;
-       if (pmc_inuse & 0xfe)
-               mmcr0 |= MMCR0_PMCjCE;
-
-       mmcra |= 0x2000;        /* mark only one IOP per PPC instruction */
-
-       /* Return MMCRx values */
-       mmcr[0] = mmcr0;
-       mmcr[1] = mmcr1;
-       mmcr[2] = mmcra;
-       return 0;
-}
-
-static void p970_disable_pmc(unsigned int pmc, unsigned long mmcr[])
-{
-       int shift, i;
-
-       if (pmc <= 1) {
-               shift = MMCR0_PMC1SEL_SH - 7 * pmc;
-               i = 0;
-       } else {
-               shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
-               i = 1;
-       }
-       /*
-        * Setting the PMCxSEL field to 0x08 disables PMC x.
-        */
-       mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
-}
-
-static int ppc970_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = 7,
-       [PERF_COUNT_HW_INSTRUCTIONS]            = 1,
-       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x8810, /* PM_LD_REF_L1 */
-       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3810, /* PM_LD_MISS_L1 */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x431,  /* PM_BR_ISSUED */
-       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x327,  /* PM_GRP_BR_MPRED */
-};
-
-#define C(x)   PERF_COUNT_HW_CACHE_##x
-
-/*
- * Table of generalized cache-related events.
- * 0 means not supported, -1 means nonsensical, other values
- * are event codes.
- */
-static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
-       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x8810,         0x3810  },
-               [C(OP_WRITE)] = {       0x7810,         0x813   },
-               [C(OP_PREFETCH)] = {    0x731,          0       },
-       },
-       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    0,              0       },
-       },
-       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0       },
-               [C(OP_WRITE)] = {       0,              0       },
-               [C(OP_PREFETCH)] = {    0x733,          0       },
-       },
-       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x704   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0,              0x700   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        0x431,          0x327   },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
-               [C(OP_READ)] = {        -1,             -1      },
-               [C(OP_WRITE)] = {       -1,             -1      },
-               [C(OP_PREFETCH)] = {    -1,             -1      },
-       },
-};
-
-static struct power_pmu ppc970_pmu = {
-       .name                   = "PPC970/FX/MP",
-       .n_counter              = 8,
-       .max_alternatives       = 2,
-       .add_fields             = 0x001100005555ull,
-       .test_adder             = 0x013300000000ull,
-       .compute_mmcr           = p970_compute_mmcr,
-       .get_constraint         = p970_get_constraint,
-       .get_alternatives       = p970_get_alternatives,
-       .disable_pmc            = p970_disable_pmc,
-       .n_generic              = ARRAY_SIZE(ppc970_generic_events),
-       .generic_events         = ppc970_generic_events,
-       .cache_events           = &ppc970_cache_events,
-};
-
-static int __init init_ppc970_pmu(void)
-{
-       if (!cur_cpu_spec->oprofile_cpu_type ||
-           (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
-            && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
-               return -ENODEV;
-
-       return register_power_pmu(&ppc970_pmu);
-}
-
-early_initcall(init_ppc970_pmu);
index d817ab0..e407070 100644 (file)
@@ -647,6 +647,9 @@ void show_regs(struct pt_regs * regs)
        printk("MSR: "REG" ", regs->msr);
        printbits(regs->msr, msr_bits);
        printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
+#ifdef CONFIG_PPC64
+       printk("SOFTE: %ld\n", regs->softe);
+#endif
        trap = TRAP(regs);
        if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR))
                printk("CFAR: "REG"\n", regs->orig_gpr3);
@@ -1220,34 +1223,32 @@ void dump_stack(void)
 EXPORT_SYMBOL(dump_stack);
 
 #ifdef CONFIG_PPC64
-void ppc64_runlatch_on(void)
+/* Called with hard IRQs off */
+void __ppc64_runlatch_on(void)
 {
+       struct thread_info *ti = current_thread_info();
        unsigned long ctrl;
 
-       if (cpu_has_feature(CPU_FTR_CTRL) && !test_thread_flag(TIF_RUNLATCH)) {
-               HMT_medium();
-
-               ctrl = mfspr(SPRN_CTRLF);
-               ctrl |= CTRL_RUNLATCH;
-               mtspr(SPRN_CTRLT, ctrl);
+       ctrl = mfspr(SPRN_CTRLF);
+       ctrl |= CTRL_RUNLATCH;
+       mtspr(SPRN_CTRLT, ctrl);
 
-               set_thread_flag(TIF_RUNLATCH);
-       }
+       ti->local_flags |= TLF_RUNLATCH;
 }
 
+/* Called with hard IRQs off */
 void __ppc64_runlatch_off(void)
 {
+       struct thread_info *ti = current_thread_info();
        unsigned long ctrl;
 
-       HMT_medium();
-
-       clear_thread_flag(TIF_RUNLATCH);
+       ti->local_flags &= ~TLF_RUNLATCH;
 
        ctrl = mfspr(SPRN_CTRLF);
        ctrl &= ~CTRL_RUNLATCH;
        mtspr(SPRN_CTRLT, ctrl);
 }
-#endif
+#endif /* CONFIG_PPC64 */
 
 #if THREAD_SHIFT < PAGE_SHIFT
 
index abe405d..89e850a 100644 (file)
@@ -52,9 +52,9 @@
 #include <asm/machdep.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/pci-bridge.h>
-#include <asm/phyp_dump.h>
 #include <asm/kexec.h>
 #include <asm/opal.h>
+#include <asm/fadump.h>
 
 #include <mm/mmu_decl.h>
 
@@ -615,86 +615,6 @@ static void __init early_reserve_mem(void)
        }
 }
 
-#ifdef CONFIG_PHYP_DUMP
-/**
- * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg
- *
- * Function to find the largest size we need to reserve
- * during early boot process.
- *
- * It either looks for boot param and returns that OR
- * returns larger of 256 or 5% rounded down to multiples of 256MB.
- *
- */
-static inline unsigned long phyp_dump_calculate_reserve_size(void)
-{
-       unsigned long tmp;
-
-       if (phyp_dump_info->reserve_bootvar)
-               return phyp_dump_info->reserve_bootvar;
-
-       /* divide by 20 to get 5% of value */
-       tmp = memblock_end_of_DRAM();
-       do_div(tmp, 20);
-
-       /* round it down in multiples of 256 */
-       tmp = tmp & ~0x0FFFFFFFUL;
-
-       return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END);
-}
-
-/**
- * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
- *
- * This routine may reserve memory regions in the kernel only
- * if the system is supported and a dump was taken in last
- * boot instance or if the hardware is supported and the
- * scratch area needs to be setup. In other instances it returns
- * without reserving anything. The memory in case of dump being
- * active is freed when the dump is collected (by userland tools).
- */
-static void __init phyp_dump_reserve_mem(void)
-{
-       unsigned long base, size;
-       unsigned long variable_reserve_size;
-
-       if (!phyp_dump_info->phyp_dump_configured) {
-               printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
-               return;
-       }
-
-       if (!phyp_dump_info->phyp_dump_at_boot) {
-               printk(KERN_INFO "Phyp-dump disabled at boot time\n");
-               return;
-       }
-
-       variable_reserve_size = phyp_dump_calculate_reserve_size();
-
-       if (phyp_dump_info->phyp_dump_is_active) {
-               /* Reserve *everything* above RMR.Area freed by userland tools*/
-               base = variable_reserve_size;
-               size = memblock_end_of_DRAM() - base;
-
-               /* XXX crashed_ram_end is wrong, since it may be beyond
-                * the memory_limit, it will need to be adjusted. */
-               memblock_reserve(base, size);
-
-               phyp_dump_info->init_reserve_start = base;
-               phyp_dump_info->init_reserve_size = size;
-       } else {
-               size = phyp_dump_info->cpu_state_size +
-                       phyp_dump_info->hpte_region_size +
-                       variable_reserve_size;
-               base = memblock_end_of_DRAM() - size;
-               memblock_reserve(base, size);
-               phyp_dump_info->init_reserve_start = base;
-               phyp_dump_info->init_reserve_size = size;
-       }
-}
-#else
-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;
@@ -714,9 +634,9 @@ void __init early_init_devtree(void *params)
        of_scan_flat_dt(early_init_dt_scan_opal, NULL);
 #endif
 
-#ifdef CONFIG_PHYP_DUMP
-       /* scan tree to see if dump occurred during last boot */
-       of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
+#ifdef CONFIG_FA_DUMP
+       /* scan tree to see if dump is active during last boot */
+       of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL);
 #endif
 
        /* Pre-initialize the cmd_line with the content of boot_commmand_line,
@@ -750,9 +670,15 @@ void __init early_init_devtree(void *params)
        if (PHYSICAL_START > MEMORY_START)
                memblock_reserve(MEMORY_START, 0x8000);
        reserve_kdump_trampoline();
-       reserve_crashkernel();
+#ifdef CONFIG_FA_DUMP
+       /*
+        * If we fail to reserve memory for firmware-assisted dump then
+        * fallback to kexec based kdump.
+        */
+       if (fadump_reserve_mem() == 0)
+#endif
+               reserve_crashkernel();
        early_reserve_mem();
-       phyp_dump_reserve_mem();
 
        /*
         * Ensure that total memory size is page-aligned, because otherwise
index eca626e..e2d5990 100644 (file)
 
 #include <linux/linux_logo.h>
 
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree. This value does need to be big enough to
- * ensure that we don't lose things like the interrupt-map property
- * on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH    (1UL * 1024 * 1024)
-
 /*
  * Eventually bump that one up
  */
@@ -2273,13 +2265,6 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                /* sanity checks */
                if (l == PROM_ERROR)
                        continue;
-               if (l > MAX_PROPERTY_LENGTH) {
-                       prom_printf("WARNING: ignoring large property ");
-                       /* It seems OF doesn't null-terminate the path :-( */
-                       prom_printf("[%s] ", path);
-                       prom_printf("%s length 0x%x\n", RELOC(pname), l);
-                       continue;
-               }
 
                /* push property head */
                dt_push_token(OF_DT_PROP, mem_start, mem_end);
index 6cd8f01..517bd86 100644 (file)
@@ -275,6 +275,9 @@ void __init find_and_init_phbs(void)
        of_node_put(root);
        pci_devs_phb_init();
 
+       /* Create EEH devices for all PHBs */
+       eeh_dev_phb_init();
+
        /*
         * pci_probe_only and pci_assign_all_buses can be set via properties
         * in chosen.
index 77bb77d..b0ebdea 100644 (file)
@@ -61,6 +61,7 @@
 #include <asm/xmon.h>
 #include <asm/cputhreads.h>
 #include <mm/mmu_decl.h>
+#include <asm/fadump.h>
 
 #include "setup.h"
 
@@ -109,6 +110,14 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
 /* also used by kexec */
 void machine_shutdown(void)
 {
+#ifdef CONFIG_FA_DUMP
+       /*
+        * if fadump is active, cleanup the fadump registration before we
+        * shutdown.
+        */
+       fadump_cleanup();
+#endif
+
        if (ppc_md.machine_shutdown)
                ppc_md.machine_shutdown();
 }
@@ -639,6 +648,11 @@ EXPORT_SYMBOL(check_legacy_ioport);
 static int ppc_panic_event(struct notifier_block *this,
                              unsigned long event, void *ptr)
 {
+       /*
+        * If firmware-assisted dump has been registered then trigger
+        * firmware-assisted dump and let firmware handle everything else.
+        */
+       crash_fadump(NULL, ptr);
        ppc_md.panic(ptr);  /* May not return */
        return NOTIFY_DONE;
 }
index ac6e437..7006b7f 100644 (file)
@@ -57,10 +57,7 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
 void restore_sigmask(sigset_t *set)
 {
        sigdelsetmask(set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = *set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(set);
 }
 
 static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
@@ -169,13 +166,7 @@ static int do_signal(struct pt_regs *regs)
 
        regs->trap = 0;
        if (ret) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked,
-                         &ka.sa.sa_mask);
-               if (!(ka.sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+               block_sigmask(&ka, signr);
 
                /*
                 * A signal was successfully delivered; the saved sigmask is in
index 836a5a1..e061ef5 100644 (file)
@@ -242,12 +242,13 @@ static inline int restore_general_regs(struct pt_regs *regs,
  */
 long sys_sigsuspend(old_sigset_t mask)
 {
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
+       sigset_t blocked;
+
        current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+
+       mask &= _BLOCKABLE;
+       siginitset(&blocked, mask);
+       set_current_blocked(&blocked);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
index 883e74c..0c683d3 100644 (file)
@@ -12,7 +12,6 @@
 #include <asm/current.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include <asm/firmware.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
@@ -341,8 +340,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
        int i, nattrs;
 
 #ifdef CONFIG_PPC64
-       if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
-                       cpu_has_feature(CPU_FTR_SMT))
+       if (cpu_has_feature(CPU_FTR_SMT))
                device_create_file(s, &dev_attr_smt_snooze_delay);
 #endif
 
@@ -414,8 +412,7 @@ static void unregister_cpu_online(unsigned int cpu)
        BUG_ON(!c->hotpluggable);
 
 #ifdef CONFIG_PPC64
-       if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
-                       cpu_has_feature(CPU_FTR_SMT))
+       if (cpu_has_feature(CPU_FTR_SMT))
                device_remove_file(s, &dev_attr_smt_snooze_delay);
 #endif
 
index 567dd7c..2c42cd7 100644 (file)
@@ -17,8 +17,7 @@
  *
  * TODO (not necessarily in this file):
  * - improve precision and reproducibility of timebase frequency
- * measurement at boot time. (for iSeries, we calibrate the timebase
- * against the Titan chip's clock.)
+ * measurement at boot time.
  * - for astronomical applications: add a new function to get
  * non ambiguous timestamps even around leap seconds. This needs
  * a new timestamp format and a good name.
 #include <asm/vdso_datapage.h>
 #include <asm/firmware.h>
 #include <asm/cputime.h>
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/hv_call_xm.h>
-#endif
 
 /* powerpc clocksource/clockevent code */
 
@@ -117,14 +112,6 @@ static struct clock_event_device decrementer_clockevent = {
 DEFINE_PER_CPU(u64, decrementers_next_tb);
 static DEFINE_PER_CPU(struct clock_event_device, decrementers);
 
-#ifdef CONFIG_PPC_ISERIES
-static unsigned long __initdata iSeries_recal_titan;
-static signed long __initdata iSeries_recal_tb;
-
-/* Forward declaration is only needed for iSereis compiles */
-static void __init clocksource_init(void);
-#endif
-
 #define XSEC_PER_SEC (1024*1024)
 
 #ifdef CONFIG_PPC64
@@ -259,7 +246,6 @@ void accumulate_stolen_time(void)
        u64 sst, ust;
 
        u8 save_soft_enabled = local_paca->soft_enabled;
-       u8 save_hard_enabled = local_paca->hard_enabled;
 
        /* We are called early in the exception entry, before
         * soft/hard_enabled are sync'ed to the expected state
@@ -268,7 +254,6 @@ void accumulate_stolen_time(void)
         * complain
         */
        local_paca->soft_enabled = 0;
-       local_paca->hard_enabled = 0;
 
        sst = scan_dispatch_log(local_paca->starttime_user);
        ust = scan_dispatch_log(local_paca->starttime);
@@ -277,7 +262,6 @@ void accumulate_stolen_time(void)
        local_paca->stolen_time += ust + sst;
 
        local_paca->soft_enabled = save_soft_enabled;
-       local_paca->hard_enabled = save_hard_enabled;
 }
 
 static inline u64 calculate_stolen_time(u64 stop_tb)
@@ -426,74 +410,6 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 #endif
 
-#ifdef CONFIG_PPC_ISERIES
-
-/* 
- * This function recalibrates the timebase based on the 49-bit time-of-day
- * value in the Titan chip.  The Titan is much more accurate than the value
- * returned by the service processor for the timebase frequency.
- */
-
-static int __init iSeries_tb_recal(void)
-{
-       unsigned long titan, tb;
-
-       /* Make sure we only run on iSeries */
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return -ENODEV;
-
-       tb = get_tb();
-       titan = HvCallXm_loadTod();
-       if ( iSeries_recal_titan ) {
-               unsigned long tb_ticks = tb - iSeries_recal_tb;
-               unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12;
-               unsigned long new_tb_ticks_per_sec   = (tb_ticks * USEC_PER_SEC)/titan_usec;
-               unsigned long new_tb_ticks_per_jiffy =
-                       DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ);
-               long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy;
-               char sign = '+';                
-               /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */
-               new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ;
-
-               if ( tick_diff < 0 ) {
-                       tick_diff = -tick_diff;
-                       sign = '-';
-               }
-               if ( tick_diff ) {
-                       if ( tick_diff < tb_ticks_per_jiffy/25 ) {
-                               printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n",
-                                               new_tb_ticks_per_jiffy, sign, tick_diff );
-                               tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
-                               tb_ticks_per_sec   = new_tb_ticks_per_sec;
-                               calc_cputime_factors();
-                               vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
-                               setup_cputime_one_jiffy();
-                       }
-                       else {
-                               printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
-                                       "                   new tb_ticks_per_jiffy = %lu\n"
-                                       "                   old tb_ticks_per_jiffy = %lu\n",
-                                       new_tb_ticks_per_jiffy, tb_ticks_per_jiffy );
-                       }
-               }
-       }
-       iSeries_recal_titan = titan;
-       iSeries_recal_tb = tb;
-
-       /* Called here as now we know accurate values for the timebase */
-       clocksource_init();
-       return 0;
-}
-late_initcall(iSeries_tb_recal);
-
-/* Called from platform early init */
-void __init iSeries_time_init_early(void)
-{
-       iSeries_recal_tb = get_tb();
-       iSeries_recal_titan = HvCallXm_loadTod();
-}
-#endif /* CONFIG_PPC_ISERIES */
-
 #ifdef CONFIG_IRQ_WORK
 
 /*
@@ -549,16 +465,6 @@ void arch_irq_work_raise(void)
 
 #endif /* CONFIG_IRQ_WORK */
 
-/*
- * For iSeries shared processors, we have to let the hypervisor
- * set the hardware decrementer.  We set a virtual decrementer
- * in the lppaca and call the hypervisor if the virtual
- * decrementer is less than the current value in the hardware
- * decrementer. (almost always the new decrementer value will
- * be greater than the current hardware decementer so the hypervisor
- * call will not be needed)
- */
-
 /*
  * timer_interrupt - gets called when the decrementer overflows,
  * with interrupts disabled.
@@ -580,6 +486,11 @@ void timer_interrupt(struct pt_regs * regs)
        if (!cpu_online(smp_processor_id()))
                return;
 
+       /* Conditionally hard-enable interrupts now that the DEC has been
+        * bumped to its maximum value
+        */
+       may_hard_irq_enable();
+
        trace_timer_interrupt_entry(regs);
 
        __get_cpu_var(irq_stat).timer_irqs++;
@@ -597,20 +508,10 @@ void timer_interrupt(struct pt_regs * regs)
                irq_work_run();
        }
 
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               get_lppaca()->int_dword.fields.decr_int = 0;
-#endif
-
        *next_tb = ~(u64)0;
        if (evt->event_handler)
                evt->event_handler(evt);
 
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending())
-               process_hvlpevents();
-#endif
-
 #ifdef CONFIG_PPC64
        /* collect purr register values often, for accurate calculations */
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
@@ -982,9 +883,8 @@ void __init time_init(void)
         */
        start_cpu_decrementer();
 
-       /* Register the clocksource, if we're not running on iSeries */
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               clocksource_init();
+       /* Register the clocksource */
+       clocksource_init();
 
        init_decrementer_clockevent();
 }
index c091527..a750409 100644 (file)
@@ -57,6 +57,7 @@
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
 #include <asm/rio.h>
+#include <asm/fadump.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -145,6 +146,8 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
                arch_spin_unlock(&die_lock);
        raw_local_irq_restore(flags);
 
+       crash_fadump(regs, "die oops");
+
        /*
         * A system reset (0x100) is a request to dump, so we always send
         * it through the crashdump code.
@@ -244,6 +247,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
                                   addr, regs->nip, regs->link, code);
        }
 
+       if (!arch_irq_disabled_regs(regs))
+               local_irq_enable();
+
        memset(&info, 0, sizeof(info));
        info.si_signo = signr;
        info.si_code = code;
index 8b08629..bca3fc4 100644 (file)
 #include <asm/abs_addr.h>
 #include <asm/page.h>
 #include <asm/hvcall.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/iommu.h>
 
 static struct bus_type vio_bus_type;
 
@@ -1042,7 +1037,6 @@ static void vio_cmo_sysfs_init(void)
        vio_bus_type.bus_attrs = vio_cmo_bus_attrs;
 }
 #else /* CONFIG_PPC_SMLPAR */
-/* Dummy functions for iSeries platform */
 int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; }
 void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {}
 static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; }
@@ -1060,9 +1054,6 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
        struct iommu_table *tbl;
        unsigned long offset, size;
 
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return vio_build_iommu_table_iseries(dev);
-
        dma_window = of_get_property(dev->dev.of_node,
                                  "ibm,my-dma-window", NULL);
        if (!dma_window)
@@ -1195,8 +1186,7 @@ static void __devinit vio_dev_release(struct device *dev)
 {
        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)
+       if (tbl)
                iommu_free_table(tbl, dev->of_node ?
                        dev->of_node->full_name : dev_name(dev));
        of_node_put(dev->of_node);
@@ -1244,12 +1234,6 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
        viodev->name = of_node->name;
        viodev->type = of_node->type;
        viodev->unit_address = *unit_address;
-       if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-               unit_address = of_get_property(of_node,
-                               "linux,unit_address", NULL);
-               if (unit_address != NULL)
-                       viodev->unit_address = *unit_address;
-       }
        viodev->dev.of_node = of_node_get(of_node);
 
        if (firmware_has_feature(FW_FEATURE_CMO))
index 710a540..65d1c08 100644 (file)
@@ -109,11 +109,6 @@ SECTIONS
                __ptov_table_begin = .;
                *(.ptov_fixup);
                __ptov_table_end = .;
-#ifdef CONFIG_PPC_ISERIES
-               __dt_strings_start = .;
-               *(.dt_strings);
-               __dt_strings_end = .;
-#endif
        }
 
        .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
index 336983d..a726716 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/page.h>
 #include <asm/hvcall.h>
 #include <linux/gfp.h>
-#include <linux/sched.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 
index a6ebba5..bb7cfec 100644 (file)
 #include <linux/smp.h>
 
 /* waiting for a spinlock... */
-#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
+#if defined(CONFIG_PPC_SPLPAR)
 #include <asm/hvcall.h>
-#include <asm/iseries/hv_call.h>
 #include <asm/smp.h>
-#include <asm/firmware.h>
 
 void __spin_yield(arch_spinlock_t *lock)
 {
@@ -40,14 +38,8 @@ void __spin_yield(arch_spinlock_t *lock)
        rmb();
        if (lock->slock != lock_value)
                return;         /* something has changed */
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
-                       ((u64)holder_cpu << 32) | yield_count);
-#ifdef CONFIG_PPC_SPLPAR
-       else
-               plpar_hcall_norets(H_CONFER,
-                       get_hard_smp_processor_id(holder_cpu), yield_count);
-#endif
+       plpar_hcall_norets(H_CONFER,
+               get_hard_smp_processor_id(holder_cpu), yield_count);
 }
 
 /*
@@ -71,14 +63,8 @@ void __rw_yield(arch_rwlock_t *rw)
        rmb();
        if (rw->lock != lock_value)
                return;         /* something has changed */
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
-                       ((u64)holder_cpu << 32) | yield_count);
-#ifdef CONFIG_PPC_SPLPAR
-       else
-               plpar_hcall_norets(H_CONFER,
-                       get_hard_smp_processor_id(holder_cpu), yield_count);
-#endif
+       plpar_hcall_norets(H_CONFER,
+               get_hard_smp_processor_id(holder_cpu), yield_count);
 }
 #endif
 
index 2f0d1b0..19f2f94 100644 (file)
@@ -105,6 +105,82 @@ static int store_updates_sp(struct pt_regs *regs)
        }
        return 0;
 }
+/*
+ * do_page_fault error handling helpers
+ */
+
+#define MM_FAULT_RETURN                0
+#define MM_FAULT_CONTINUE      -1
+#define MM_FAULT_ERR(sig)      (sig)
+
+static int out_of_memory(struct pt_regs *regs)
+{
+       /*
+        * We ran out of memory, or some other thing happened to us that made
+        * us unable to handle the page fault gracefully.
+        */
+       up_read(&current->mm->mmap_sem);
+       if (!user_mode(regs))
+               return MM_FAULT_ERR(SIGKILL);
+       pagefault_out_of_memory();
+       return MM_FAULT_RETURN;
+}
+
+static int do_sigbus(struct pt_regs *regs, unsigned long address)
+{
+       siginfo_t info;
+
+       up_read(&current->mm->mmap_sem);
+
+       if (user_mode(regs)) {
+               info.si_signo = SIGBUS;
+               info.si_errno = 0;
+               info.si_code = BUS_ADRERR;
+               info.si_addr = (void __user *)address;
+               force_sig_info(SIGBUS, &info, current);
+               return MM_FAULT_RETURN;
+       }
+       return MM_FAULT_ERR(SIGBUS);
+}
+
+static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
+{
+       /*
+        * Pagefault was interrupted by SIGKILL. We have no reason to
+        * continue the pagefault.
+        */
+       if (fatal_signal_pending(current)) {
+               /*
+                * If we have retry set, the mmap semaphore will have
+                * alrady been released in __lock_page_or_retry(). Else
+                * we release it now.
+                */
+               if (!(fault & VM_FAULT_RETRY))
+                       up_read(&current->mm->mmap_sem);
+               /* Coming from kernel, we need to deal with uaccess fixups */
+               if (user_mode(regs))
+                       return MM_FAULT_RETURN;
+               return MM_FAULT_ERR(SIGKILL);
+       }
+
+       /* No fault: be happy */
+       if (!(fault & VM_FAULT_ERROR))
+               return MM_FAULT_CONTINUE;
+
+       /* Out of memory */
+       if (fault & VM_FAULT_OOM)
+               return out_of_memory(regs);
+
+       /* Bus error. x86 handles HWPOISON here, we'll add this if/when
+        * we support the feature in HW
+        */
+       if (fault & VM_FAULT_SIGBUS)
+               return do_sigbus(regs, addr);
+
+       /* We don't understand the fault code, this is fatal */
+       BUG();
+       return MM_FAULT_CONTINUE;
+}
 
 /*
  * For 600- and 800-family processors, the error_code parameter is DSISR
@@ -124,11 +200,12 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 {
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
-       siginfo_t info;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
        int code = SEGV_MAPERR;
-       int is_write = 0, ret;
+       int is_write = 0;
        int trap = TRAP(regs);
        int is_exec = trap == 0x400;
+       int fault;
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
        /*
@@ -145,6 +222,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
+       if (is_write)
+               flags |= FAULT_FLAG_WRITE;
+
 #ifdef CONFIG_PPC_ICSWX
        /*
         * we need to do this early because this "data storage
@@ -152,13 +232,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
         * look at it
         */
        if (error_code & ICSWX_DSI_UCT) {
-               int ret;
-
-               ret = acop_handle_fault(regs, address, error_code);
-               if (ret)
-                       return ret;
+               int rc = acop_handle_fault(regs, address, error_code);
+               if (rc)
+                       return rc;
        }
-#endif
+#endif /* CONFIG_PPC_ICSWX */
 
        if (notify_page_fault(regs))
                return 0;
@@ -179,6 +257,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        }
 #endif
 
+       /* We restore the interrupt state now */
+       if (!arch_irq_disabled_regs(regs))
+               local_irq_enable();
+
        if (in_atomic() || mm == NULL) {
                if (!user_mode(regs))
                        return SIGSEGV;
@@ -212,7 +294,15 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
                if (!user_mode(regs) && !search_exception_tables(regs->nip))
                        goto bad_area_nosemaphore;
 
+retry:
                down_read(&mm->mmap_sem);
+       } else {
+               /*
+                * The above down_read_trylock() might have succeeded in
+                * which case we'll have missed the might_sleep() from
+                * down_read():
+                */
+               might_sleep();
        }
 
        vma = find_vma(mm, address);
@@ -327,30 +417,43 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
-       if (unlikely(ret & VM_FAULT_ERROR)) {
-               if (ret & VM_FAULT_OOM)
-                       goto out_of_memory;
-               else if (ret & VM_FAULT_SIGBUS)
-                       goto do_sigbus;
-               BUG();
+       fault = handle_mm_fault(mm, vma, address, flags);
+       if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
+               int rc = mm_fault_error(regs, address, fault);
+               if (rc >= MM_FAULT_RETURN)
+                       return rc;
        }
-       if (ret & VM_FAULT_MAJOR) {
-               current->maj_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
-                                    regs, address);
+
+       /*
+        * Major/minor page fault accounting is only done on the
+        * initial attempt. If we go through a retry, it is extremely
+        * likely that the page will be found in page cache at that point.
+        */
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR) {
+                       current->maj_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+                                     regs, address);
 #ifdef CONFIG_PPC_SMLPAR
-               if (firmware_has_feature(FW_FEATURE_CMO)) {
-                       preempt_disable();
-                       get_lppaca()->page_ins += (1 << PAGE_FACTOR);
-                       preempt_enable();
+                       if (firmware_has_feature(FW_FEATURE_CMO)) {
+                               preempt_disable();
+                               get_lppaca()->page_ins += (1 << PAGE_FACTOR);
+                               preempt_enable();
+                       }
+#endif /* CONFIG_PPC_SMLPAR */
+               } else {
+                       current->min_flt++;
+                       perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+                                     regs, address);
+               }
+               if (fault & VM_FAULT_RETRY) {
+                       /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+                        * of starvation. */
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                       goto retry;
                }
-#endif
-       } else {
-               current->min_flt++;
-               perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
-                                    regs, address);
        }
+
        up_read(&mm->mmap_sem);
        return 0;
 
@@ -371,28 +474,6 @@ bad_area_nosemaphore:
 
        return SIGSEGV;
 
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-       up_read(&mm->mmap_sem);
-       if (!user_mode(regs))
-               return SIGKILL;
-       pagefault_out_of_memory();
-       return 0;
-
-do_sigbus:
-       up_read(&mm->mmap_sem);
-       if (user_mode(regs)) {
-               info.si_signo = SIGBUS;
-               info.si_errno = 0;
-               info.si_code = BUS_ADRERR;
-               info.si_addr = (void __user *)address;
-               force_sig_info(SIGBUS, &info, current);
-               return 0;
-       }
-       return SIGBUS;
 }
 
 /*
index 66a6fd3..07ba45b 100644 (file)
@@ -149,12 +149,19 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
 unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
                          phys_addr_t phys)
 {
-       unsigned int camsize = __ilog2(ram) & ~1U;
-       unsigned int align = __ffs(virt | phys) & ~1U;
-       unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf;
-
-       /* Convert (4^max) kB to (2^max) bytes */
-       max_cam = max_cam * 2 + 10;
+       unsigned int camsize = __ilog2(ram);
+       unsigned int align = __ffs(virt | phys);
+       unsigned long max_cam;
+
+       if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
+               /* Convert (4^max) kB to (2^max) bytes */
+               max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10;
+               camsize &= ~1U;
+               align &= ~1U;
+       } else {
+               /* Convert (2^max) kB to (2^max) bytes */
+               max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10;
+       }
 
        if (camsize > align)
                camsize = align;
index 2d28218..3e8c37a 100644 (file)
@@ -55,6 +55,8 @@
 #include <asm/spu.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
+#include <asm/fadump.h>
+#include <asm/firmware.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -625,6 +627,16 @@ static void __init htab_initialize(void)
                /* Using a hypervisor which owns the htab */
                htab_address = NULL;
                _SDR1 = 0; 
+#ifdef CONFIG_FA_DUMP
+               /*
+                * If firmware assisted dump is active firmware preserves
+                * the contents of htab along with entire partition memory.
+                * Clear the htab if firmware assisted dump is active so
+                * that we dont end up using old mappings.
+                */
+               if (is_fadump_active() && ppc_md.hpte_clear_all)
+                       ppc_md.hpte_clear_all();
+#endif
        } else {
                /* Find storage for the HPT.  Must be contiguous in
                 * the absolute address space. On cell we want it to be
@@ -745,12 +757,9 @@ void __init early_init_mmu(void)
         */
        htab_initialize();
 
-       /* Initialize stab / SLB management except on iSeries
-        */
+       /* Initialize stab / SLB management */
        if (mmu_has_feature(MMU_FTR_SLB))
                slb_initialize();
-       else if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               stab_initialize(get_paca()->stab_real);
 }
 
 #ifdef CONFIG_SMP
@@ -761,8 +770,7 @@ void __cpuinit early_init_mmu_secondary(void)
                mtspr(SPRN_SDR1, _SDR1);
 
        /* Initialize STAB/SLB. We use a virtual address as it works
-        * in real mode on pSeries and we want a virtual address on
-        * iSeries anyway
+        * in real mode on pSeries.
         */
        if (mmu_has_feature(MMU_FTR_SLB))
                slb_initialize();
index 5d9a59e..8cdbd86 100644 (file)
@@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop);
 
 static int acop_use_cop(int ct)
 {
-       /* todo */
+       /* There is no alternate policy, yet */
        return -1;
 }
 
@@ -227,11 +227,30 @@ int acop_handle_fault(struct pt_regs *regs, unsigned long address,
                ct = (ccw >> 16) & 0x3f;
        }
 
+       /*
+        * We could be here because another thread has enabled acop
+        * but the ACOP register has yet to be updated.
+        *
+        * This should have been taken care of by the IPI to sync all
+        * the threads (see smp_call_function(sync_cop, mm, 1)), but
+        * that could take forever if there are a significant amount
+        * of threads.
+        *
+        * Given the number of threads on some of these systems,
+        * perhaps this is the best way to sync ACOP rather than whack
+        * every thread with an IPI.
+        */
+       if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) {
+               sync_cop(current->active_mm);
+               return 0;
+       }
+
+       /* check for alternate policy */
        if (!acop_use_cop(ct))
                return 0;
 
        /* at this point the CT is unknown to the system */
-       pr_warn("%s[%d]: Coprocessor %d is unavailable",
+       pr_warn("%s[%d]: Coprocessor %d is unavailable\n",
                current->comm, current->pid, ct);
 
        /* get inst if we don't already have it */
index 42176bd..6dedc08 100644 (file)
@@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid);
 
 extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
                             unsigned long error_code);
+
+static inline u64 acop_copro_type_bit(unsigned int type)
+{
+       return 1ULL << (63 - type);
+}
+
 #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
index 51f8795..0907f92 100644 (file)
@@ -207,7 +207,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags,
         */
        if (mem_init_done && (p < virt_to_phys(high_memory)) &&
            !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) {
-               printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+               printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n",
                       (unsigned long long)p, __builtin_return_address(0));
                return NULL;
        }
index e22276c..a538c80 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/cputable.h>
 #include <asm/cacheflush.h>
 #include <asm/smp.h>
-#include <asm/firmware.h>
 #include <linux/compiler.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
@@ -307,11 +306,6 @@ void slb_initialize(void)
 
        get_paca()->stab_rr = SLB_NUM_BOLTED;
 
-       /* On iSeries the bolted entries have already been set up by
-        * the hypervisor from the lparMap data in head.S */
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return;
-
        lflags = SLB_VSID_KERNEL | linear_llp;
        vflags = SLB_VSID_KERNEL | vmalloc_llp;
 
index ef653dc..b9ee79c 100644 (file)
@@ -217,21 +217,6 @@ slb_finish_load:
         * free slot first but that took too long. Unfortunately we
         * dont have any LRU information to help us choose a slot.
         */
-#ifdef CONFIG_PPC_ISERIES
-BEGIN_FW_FTR_SECTION
-       /*
-        * On iSeries, the "bolted" stack segment can be cast out on
-        * shared processor switch so we need to check for a miss on
-        * it and restore it to the right slot.
-        */
-       ld      r9,PACAKSAVE(r13)
-       clrrdi  r9,r9,28
-       clrrdi  r3,r3,28
-       li      r10,SLB_NUM_BOLTED-1    /* Stack goes in last bolted slot */
-       cmpld   r9,r3
-       beq     3f
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif /* CONFIG_PPC_ISERIES */
 
 7:     ld      r10,PACASTABRR(r13)
        addi    r10,r10,1
@@ -282,7 +267,6 @@ _GLOBAL(slb_compare_rr_to_size)
 
 /*
  * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return.
- * We assume legacy iSeries will never have 1T segments.
  *
  * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9
  */
index 41e3164..9106ebb 100644 (file)
@@ -21,8 +21,6 @@
 #include <asm/cputable.h>
 #include <asm/prom.h>
 #include <asm/abs_addr.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call.h>
 
 struct stab_entry {
        unsigned long esid_data;
@@ -285,12 +283,5 @@ void stab_initialize(unsigned long stab)
        /* Set ASR */
        stabreal = get_paca()->stab_real | 0x1ul;
 
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-               HvCall1(HvCallBaseSetASR, stabreal);
-               return;
-       }
-#endif /* CONFIG_PPC_ISERIES */
-
        mtspr(SPRN_ASR, stabreal);
 }
index d65e68f..6f01624 100644 (file)
@@ -195,9 +195,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        if (!cur_cpu_spec->oprofile_cpu_type)
                return -ENODEV;
 
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return -ENODEV;
-
        switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC_BOOK3S_64
 #ifdef CONFIG_OPROFILE_CELL
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
new file mode 100644 (file)
index 0000000..af3fac2
--- /dev/null
@@ -0,0 +1,14 @@
+subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
+
+obj-$(CONFIG_PERF_EVENTS)      += callchain.o
+
+obj-$(CONFIG_PPC_PERF_CTRS)    += core-book3s.o
+obj64-$(CONFIG_PPC_PERF_CTRS)  += power4-pmu.o ppc970-pmu.o power5-pmu.o \
+                                  power5+-pmu.o power6-pmu.o power7-pmu.o
+obj32-$(CONFIG_PPC_PERF_CTRS)  += mpc7450-pmu.o
+
+obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
+obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
+
+obj-$(CONFIG_PPC64)            += $(obj64-y)
+obj-$(CONFIG_PPC32)            += $(obj32-y)
diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c
new file mode 100644 (file)
index 0000000..e8a18d1
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * Performance counter callchain support - powerpc architecture code
+ *
+ * Copyright Â© 2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/vdso.h>
+#ifdef CONFIG_PPC64
+#include "../kernel/ppc32.h"
+#endif
+
+
+/*
+ * Is sp valid as the address of the next kernel stack frame after prev_sp?
+ * The next frame may be in a different stack area but should not go
+ * back down in the same stack area.
+ */
+static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
+{
+       if (sp & 0xf)
+               return 0;               /* must be 16-byte aligned */
+       if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+               return 0;
+       if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
+               return 1;
+       /*
+        * sp could decrease when we jump off an interrupt stack
+        * back to the regular process stack.
+        */
+       if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
+               return 1;
+       return 0;
+}
+
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+       unsigned long sp, next_sp;
+       unsigned long next_ip;
+       unsigned long lr;
+       long level = 0;
+       unsigned long *fp;
+
+       lr = regs->link;
+       sp = regs->gpr[1];
+       perf_callchain_store(entry, regs->nip);
+
+       if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+               return;
+
+       for (;;) {
+               fp = (unsigned long *) sp;
+               next_sp = fp[0];
+
+               if (next_sp == sp + STACK_INT_FRAME_SIZE &&
+                   fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
+                       /*
+                        * This looks like an interrupt frame for an
+                        * interrupt that occurred in the kernel
+                        */
+                       regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
+                       next_ip = regs->nip;
+                       lr = regs->link;
+                       level = 0;
+                       perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
+
+               } else {
+                       if (level == 0)
+                               next_ip = lr;
+                       else
+                               next_ip = fp[STACK_FRAME_LR_SAVE];
+
+                       /*
+                        * We can't tell which of the first two addresses
+                        * we get are valid, but we can filter out the
+                        * obviously bogus ones here.  We replace them
+                        * with 0 rather than removing them entirely so
+                        * that userspace can tell which is which.
+                        */
+                       if ((level == 1 && next_ip == lr) ||
+                           (level <= 1 && !kernel_text_address(next_ip)))
+                               next_ip = 0;
+
+                       ++level;
+               }
+
+               perf_callchain_store(entry, next_ip);
+               if (!valid_next_sp(next_sp, sp))
+                       return;
+               sp = next_sp;
+       }
+}
+
+#ifdef CONFIG_PPC64
+/*
+ * On 64-bit we don't want to invoke hash_page on user addresses from
+ * interrupt context, so if the access faults, we read the page tables
+ * to find which page (if any) is mapped and access it directly.
+ */
+static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
+{
+       pgd_t *pgdir;
+       pte_t *ptep, pte;
+       unsigned shift;
+       unsigned long addr = (unsigned long) ptr;
+       unsigned long offset;
+       unsigned long pfn;
+       void *kaddr;
+
+       pgdir = current->mm->pgd;
+       if (!pgdir)
+               return -EFAULT;
+
+       ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
+       if (!shift)
+               shift = PAGE_SHIFT;
+
+       /* align address to page boundary */
+       offset = addr & ((1UL << shift) - 1);
+       addr -= offset;
+
+       if (ptep == NULL)
+               return -EFAULT;
+       pte = *ptep;
+       if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
+               return -EFAULT;
+       pfn = pte_pfn(pte);
+       if (!page_is_ram(pfn))
+               return -EFAULT;
+
+       /* no highmem to worry about here */
+       kaddr = pfn_to_kaddr(pfn);
+       memcpy(ret, kaddr + offset, nb);
+       return 0;
+}
+
+static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
+{
+       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
+           ((unsigned long)ptr & 7))
+               return -EFAULT;
+
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
+               return 0;
+       }
+       pagefault_enable();
+
+       return read_user_stack_slow(ptr, ret, 8);
+}
+
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
+{
+       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+           ((unsigned long)ptr & 3))
+               return -EFAULT;
+
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
+               return 0;
+       }
+       pagefault_enable();
+
+       return read_user_stack_slow(ptr, ret, 4);
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+       if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
+               return 0;
+       return 1;
+}
+
+/*
+ * 64-bit user processes use the same stack frame for RT and non-RT signals.
+ */
+struct signal_frame_64 {
+       char            dummy[__SIGNAL_FRAMESIZE];
+       struct ucontext uc;
+       unsigned long   unused[2];
+       unsigned int    tramp[6];
+       struct siginfo  *pinfo;
+       void            *puc;
+       struct siginfo  info;
+       char            abigap[288];
+};
+
+static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
+{
+       if (nip == fp + offsetof(struct signal_frame_64, tramp))
+               return 1;
+       if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
+               return 1;
+       return 0;
+}
+
+/*
+ * Do some sanity checking on the signal frame pointed to by sp.
+ * We check the pinfo and puc pointers in the frame.
+ */
+static int sane_signal_64_frame(unsigned long sp)
+{
+       struct signal_frame_64 __user *sf;
+       unsigned long pinfo, puc;
+
+       sf = (struct signal_frame_64 __user *) sp;
+       if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
+           read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
+               return 0;
+       return pinfo == (unsigned long) &sf->info &&
+               puc == (unsigned long) &sf->uc;
+}
+
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
+{
+       unsigned long sp, next_sp;
+       unsigned long next_ip;
+       unsigned long lr;
+       long level = 0;
+       struct signal_frame_64 __user *sigframe;
+       unsigned long __user *fp, *uregs;
+
+       next_ip = regs->nip;
+       lr = regs->link;
+       sp = regs->gpr[1];
+       perf_callchain_store(entry, next_ip);
+
+       for (;;) {
+               fp = (unsigned long __user *) sp;
+               if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
+                       return;
+               if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
+                       return;
+
+               /*
+                * Note: the next_sp - sp >= signal frame size check
+                * is true when next_sp < sp, which can happen when
+                * transitioning from an alternate signal stack to the
+                * normal stack.
+                */
+               if (next_sp - sp >= sizeof(struct signal_frame_64) &&
+                   (is_sigreturn_64_address(next_ip, sp) ||
+                    (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
+                   sane_signal_64_frame(sp)) {
+                       /*
+                        * This looks like an signal frame
+                        */
+                       sigframe = (struct signal_frame_64 __user *) sp;
+                       uregs = sigframe->uc.uc_mcontext.gp_regs;
+                       if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
+                           read_user_stack_64(&uregs[PT_LNK], &lr) ||
+                           read_user_stack_64(&uregs[PT_R1], &sp))
+                               return;
+                       level = 0;
+                       perf_callchain_store(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
+                       continue;
+               }
+
+               if (level == 0)
+                       next_ip = lr;
+               perf_callchain_store(entry, next_ip);
+               ++level;
+               sp = next_sp;
+       }
+}
+
+static inline int current_is_64bit(void)
+{
+       /*
+        * We can't use test_thread_flag() here because we may be on an
+        * interrupt stack, and the thread flags don't get copied over
+        * from the thread_info on the main stack to the interrupt stack.
+        */
+       return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
+}
+
+#else  /* CONFIG_PPC64 */
+/*
+ * On 32-bit we just access the address and let hash_page create a
+ * HPTE if necessary, so there is no need to fall back to reading
+ * the page tables.  Since this is called at interrupt level,
+ * do_page_fault() won't treat a DSI as a page fault.
+ */
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
+{
+       int rc;
+
+       if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+           ((unsigned long)ptr & 3))
+               return -EFAULT;
+
+       pagefault_disable();
+       rc = __get_user_inatomic(*ret, ptr);
+       pagefault_enable();
+
+       return rc;
+}
+
+static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
+                                         struct pt_regs *regs)
+{
+}
+
+static inline int current_is_64bit(void)
+{
+       return 0;
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+       if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
+               return 0;
+       return 1;
+}
+
+#define __SIGNAL_FRAMESIZE32   __SIGNAL_FRAMESIZE
+#define sigcontext32           sigcontext
+#define mcontext32             mcontext
+#define ucontext32             ucontext
+#define compat_siginfo_t       struct siginfo
+
+#endif /* CONFIG_PPC64 */
+
+/*
+ * Layout for non-RT signal frames
+ */
+struct signal_frame_32 {
+       char                    dummy[__SIGNAL_FRAMESIZE32];
+       struct sigcontext32     sctx;
+       struct mcontext32       mctx;
+       int                     abigap[56];
+};
+
+/*
+ * Layout for RT signal frames
+ */
+struct rt_signal_frame_32 {
+       char                    dummy[__SIGNAL_FRAMESIZE32 + 16];
+       compat_siginfo_t        info;
+       struct ucontext32       uc;
+       int                     abigap[56];
+};
+
+static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+       if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
+               return 1;
+       if (vdso32_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso32_sigtramp)
+               return 1;
+       return 0;
+}
+
+static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+       if (nip == fp + offsetof(struct rt_signal_frame_32,
+                                uc.uc_mcontext.mc_pad))
+               return 1;
+       if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
+           nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
+               return 1;
+       return 0;
+}
+
+static int sane_signal_32_frame(unsigned int sp)
+{
+       struct signal_frame_32 __user *sf;
+       unsigned int regs;
+
+       sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+       if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
+               return 0;
+       return regs == (unsigned long) &sf->mctx;
+}
+
+static int sane_rt_signal_32_frame(unsigned int sp)
+{
+       struct rt_signal_frame_32 __user *sf;
+       unsigned int regs;
+
+       sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+       if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
+               return 0;
+       return regs == (unsigned long) &sf->uc.uc_mcontext;
+}
+
+static unsigned int __user *signal_frame_32_regs(unsigned int sp,
+                               unsigned int next_sp, unsigned int next_ip)
+{
+       struct mcontext32 __user *mctx = NULL;
+       struct signal_frame_32 __user *sf;
+       struct rt_signal_frame_32 __user *rt_sf;
+
+       /*
+        * Note: the next_sp - sp >= signal frame size check
+        * is true when next_sp < sp, for example, when
+        * transitioning from an alternate signal stack to the
+        * normal stack.
+        */
+       if (next_sp - sp >= sizeof(struct signal_frame_32) &&
+           is_sigreturn_32_address(next_ip, sp) &&
+           sane_signal_32_frame(sp)) {
+               sf = (struct signal_frame_32 __user *) (unsigned long) sp;
+               mctx = &sf->mctx;
+       }
+
+       if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
+           is_rt_sigreturn_32_address(next_ip, sp) &&
+           sane_rt_signal_32_frame(sp)) {
+               rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+               mctx = &rt_sf->uc.uc_mcontext;
+       }
+
+       if (!mctx)
+               return NULL;
+       return mctx->mc_gregs;
+}
+
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
+{
+       unsigned int sp, next_sp;
+       unsigned int next_ip;
+       unsigned int lr;
+       long level = 0;
+       unsigned int __user *fp, *uregs;
+
+       next_ip = regs->nip;
+       lr = regs->link;
+       sp = regs->gpr[1];
+       perf_callchain_store(entry, next_ip);
+
+       while (entry->nr < PERF_MAX_STACK_DEPTH) {
+               fp = (unsigned int __user *) (unsigned long) sp;
+               if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
+                       return;
+               if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
+                       return;
+
+               uregs = signal_frame_32_regs(sp, next_sp, next_ip);
+               if (!uregs && level <= 1)
+                       uregs = signal_frame_32_regs(sp, next_sp, lr);
+               if (uregs) {
+                       /*
+                        * This looks like an signal frame, so restart
+                        * the stack trace with the values in it.
+                        */
+                       if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
+                           read_user_stack_32(&uregs[PT_LNK], &lr) ||
+                           read_user_stack_32(&uregs[PT_R1], &sp))
+                               return;
+                       level = 0;
+                       perf_callchain_store(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
+                       continue;
+               }
+
+               if (level == 0)
+                       next_ip = lr;
+               perf_callchain_store(entry, next_ip);
+               ++level;
+               sp = next_sp;
+       }
+}
+
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+       if (current_is_64bit())
+               perf_callchain_user_64(entry, regs);
+       else
+               perf_callchain_user_32(entry, regs);
+}
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
new file mode 100644 (file)
index 0000000..c2e27ed
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ * Performance event support - powerpc architecture code
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/reg.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/ptrace.h>
+
+struct cpu_hw_events {
+       int n_events;
+       int n_percpu;
+       int disabled;
+       int n_added;
+       int n_limited;
+       u8  pmcs_enabled;
+       struct perf_event *event[MAX_HWEVENTS];
+       u64 events[MAX_HWEVENTS];
+       unsigned int flags[MAX_HWEVENTS];
+       unsigned long mmcr[3];
+       struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
+       u8  limited_hwidx[MAX_LIMITED_HWCOUNTERS];
+       u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+       unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+       unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
+
+       unsigned int group_flag;
+       int n_txn_start;
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+struct power_pmu *ppmu;
+
+/*
+ * Normally, to ignore kernel events we set the FCS (freeze counters
+ * in supervisor mode) bit in MMCR0, but if the kernel runs with the
+ * hypervisor bit set in the MSR, or if we are running on a processor
+ * where the hypervisor bit is forced to 1 (as on Apple G5 processors),
+ * then we need to use the FCHV bit to ignore kernel events.
+ */
+static unsigned int freeze_events_kernel = MMCR0_FCS;
+
+/*
+ * 32-bit doesn't have MMCRA but does have an MMCR2,
+ * and a few other names are different.
+ */
+#ifdef CONFIG_PPC32
+
+#define MMCR0_FCHV             0
+#define MMCR0_PMCjCE           MMCR0_PMCnCE
+
+#define SPRN_MMCRA             SPRN_MMCR2
+#define MMCRA_SAMPLE_ENABLE    0
+
+static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
+{
+       return 0;
+}
+static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
+static inline u32 perf_get_misc_flags(struct pt_regs *regs)
+{
+       return 0;
+}
+static inline void perf_read_regs(struct pt_regs *regs) { }
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+       return 0;
+}
+
+#endif /* CONFIG_PPC32 */
+
+/*
+ * Things that are specific to 64-bit implementations.
+ */
+#ifdef CONFIG_PPC64
+
+static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
+{
+       unsigned long mmcra = regs->dsisr;
+
+       if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
+               unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
+               if (slot > 1)
+                       return 4 * (slot - 1);
+       }
+       return 0;
+}
+
+/*
+ * The user wants a data address recorded.
+ * If we're not doing instruction sampling, give them the SDAR
+ * (sampled data address).  If we are doing instruction sampling, then
+ * only give them the SDAR if it corresponds to the instruction
+ * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
+ * bit in MMCRA.
+ */
+static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
+{
+       unsigned long mmcra = regs->dsisr;
+       unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
+               POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
+
+       if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
+               *addrp = mfspr(SPRN_SDAR);
+}
+
+static inline u32 perf_get_misc_flags(struct pt_regs *regs)
+{
+       unsigned long mmcra = regs->dsisr;
+       unsigned long sihv = MMCRA_SIHV;
+       unsigned long sipr = MMCRA_SIPR;
+
+       if (TRAP(regs) != 0xf00)
+               return 0;       /* not a PMU interrupt */
+
+       if (ppmu->flags & PPMU_ALT_SIPR) {
+               sihv = POWER6_MMCRA_SIHV;
+               sipr = POWER6_MMCRA_SIPR;
+       }
+
+       /* PR has priority over HV, so order below is important */
+       if (mmcra & sipr)
+               return PERF_RECORD_MISC_USER;
+       if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
+               return PERF_RECORD_MISC_HYPERVISOR;
+       return PERF_RECORD_MISC_KERNEL;
+}
+
+/*
+ * Overload regs->dsisr to store MMCRA so we only need to read it once
+ * on each interrupt.
+ */
+static inline void perf_read_regs(struct pt_regs *regs)
+{
+       regs->dsisr = mfspr(SPRN_MMCRA);
+}
+
+/*
+ * If interrupts were soft-disabled when a PMU interrupt occurs, treat
+ * it as an NMI.
+ */
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+       return !regs->softe;
+}
+
+#endif /* CONFIG_PPC64 */
+
+static void perf_event_interrupt(struct pt_regs *regs);
+
+void perf_event_print_debug(void)
+{
+}
+
+/*
+ * Read one performance monitor counter (PMC).
+ */
+static unsigned long read_pmc(int idx)
+{
+       unsigned long val;
+
+       switch (idx) {
+       case 1:
+               val = mfspr(SPRN_PMC1);
+               break;
+       case 2:
+               val = mfspr(SPRN_PMC2);
+               break;
+       case 3:
+               val = mfspr(SPRN_PMC3);
+               break;
+       case 4:
+               val = mfspr(SPRN_PMC4);
+               break;
+       case 5:
+               val = mfspr(SPRN_PMC5);
+               break;
+       case 6:
+               val = mfspr(SPRN_PMC6);
+               break;
+#ifdef CONFIG_PPC64
+       case 7:
+               val = mfspr(SPRN_PMC7);
+               break;
+       case 8:
+               val = mfspr(SPRN_PMC8);
+               break;
+#endif /* CONFIG_PPC64 */
+       default:
+               printk(KERN_ERR "oops trying to read PMC%d\n", idx);
+               val = 0;
+       }
+       return val;
+}
+
+/*
+ * Write one PMC.
+ */
+static void write_pmc(int idx, unsigned long val)
+{
+       switch (idx) {
+       case 1:
+               mtspr(SPRN_PMC1, val);
+               break;
+       case 2:
+               mtspr(SPRN_PMC2, val);
+               break;
+       case 3:
+               mtspr(SPRN_PMC3, val);
+               break;
+       case 4:
+               mtspr(SPRN_PMC4, val);
+               break;
+       case 5:
+               mtspr(SPRN_PMC5, val);
+               break;
+       case 6:
+               mtspr(SPRN_PMC6, val);
+               break;
+#ifdef CONFIG_PPC64
+       case 7:
+               mtspr(SPRN_PMC7, val);
+               break;
+       case 8:
+               mtspr(SPRN_PMC8, val);
+               break;
+#endif /* CONFIG_PPC64 */
+       default:
+               printk(KERN_ERR "oops trying to write PMC%d\n", idx);
+       }
+}
+
+/*
+ * Check if a set of events can all go on the PMU at once.
+ * If they can't, this will look at alternative codes for the events
+ * and see if any combination of alternative codes is feasible.
+ * The feasible set is returned in event_id[].
+ */
+static int power_check_constraints(struct cpu_hw_events *cpuhw,
+                                  u64 event_id[], unsigned int cflags[],
+                                  int n_ev)
+{
+       unsigned long mask, value, nv;
+       unsigned long smasks[MAX_HWEVENTS], svalues[MAX_HWEVENTS];
+       int n_alt[MAX_HWEVENTS], choice[MAX_HWEVENTS];
+       int i, j;
+       unsigned long addf = ppmu->add_fields;
+       unsigned long tadd = ppmu->test_adder;
+
+       if (n_ev > ppmu->n_counter)
+               return -1;
+
+       /* First see if the events will go on as-is */
+       for (i = 0; i < n_ev; ++i) {
+               if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
+                   && !ppmu->limited_pmc_event(event_id[i])) {
+                       ppmu->get_alternatives(event_id[i], cflags[i],
+                                              cpuhw->alternatives[i]);
+                       event_id[i] = cpuhw->alternatives[i][0];
+               }
+               if (ppmu->get_constraint(event_id[i], &cpuhw->amasks[i][0],
+                                        &cpuhw->avalues[i][0]))
+                       return -1;
+       }
+       value = mask = 0;
+       for (i = 0; i < n_ev; ++i) {
+               nv = (value | cpuhw->avalues[i][0]) +
+                       (value & cpuhw->avalues[i][0] & addf);
+               if ((((nv + tadd) ^ value) & mask) != 0 ||
+                   (((nv + tadd) ^ cpuhw->avalues[i][0]) &
+                    cpuhw->amasks[i][0]) != 0)
+                       break;
+               value = nv;
+               mask |= cpuhw->amasks[i][0];
+       }
+       if (i == n_ev)
+               return 0;       /* all OK */
+
+       /* doesn't work, gather alternatives... */
+       if (!ppmu->get_alternatives)
+               return -1;
+       for (i = 0; i < n_ev; ++i) {
+               choice[i] = 0;
+               n_alt[i] = ppmu->get_alternatives(event_id[i], cflags[i],
+                                                 cpuhw->alternatives[i]);
+               for (j = 1; j < n_alt[i]; ++j)
+                       ppmu->get_constraint(cpuhw->alternatives[i][j],
+                                            &cpuhw->amasks[i][j],
+                                            &cpuhw->avalues[i][j]);
+       }
+
+       /* enumerate all possibilities and see if any will work */
+       i = 0;
+       j = -1;
+       value = mask = nv = 0;
+       while (i < n_ev) {
+               if (j >= 0) {
+                       /* we're backtracking, restore context */
+                       value = svalues[i];
+                       mask = smasks[i];
+                       j = choice[i];
+               }
+               /*
+                * See if any alternative k for event_id i,
+                * where k > j, will satisfy the constraints.
+                */
+               while (++j < n_alt[i]) {
+                       nv = (value | cpuhw->avalues[i][j]) +
+                               (value & cpuhw->avalues[i][j] & addf);
+                       if ((((nv + tadd) ^ value) & mask) == 0 &&
+                           (((nv + tadd) ^ cpuhw->avalues[i][j])
+                            & cpuhw->amasks[i][j]) == 0)
+                               break;
+               }
+               if (j >= n_alt[i]) {
+                       /*
+                        * No feasible alternative, backtrack
+                        * to event_id i-1 and continue enumerating its
+                        * alternatives from where we got up to.
+                        */
+                       if (--i < 0)
+                               return -1;
+               } else {
+                       /*
+                        * Found a feasible alternative for event_id i,
+                        * remember where we got up to with this event_id,
+                        * go on to the next event_id, and start with
+                        * the first alternative for it.
+                        */
+                       choice[i] = j;
+                       svalues[i] = value;
+                       smasks[i] = mask;
+                       value = nv;
+                       mask |= cpuhw->amasks[i][j];
+                       ++i;
+                       j = -1;
+               }
+       }
+
+       /* OK, we have a feasible combination, tell the caller the solution */
+       for (i = 0; i < n_ev; ++i)
+               event_id[i] = cpuhw->alternatives[i][choice[i]];
+       return 0;
+}
+
+/*
+ * Check if newly-added events have consistent settings for
+ * exclude_{user,kernel,hv} with each other and any previously
+ * added events.
+ */
+static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
+                         int n_prev, int n_new)
+{
+       int eu = 0, ek = 0, eh = 0;
+       int i, n, first;
+       struct perf_event *event;
+
+       n = n_prev + n_new;
+       if (n <= 1)
+               return 0;
+
+       first = 1;
+       for (i = 0; i < n; ++i) {
+               if (cflags[i] & PPMU_LIMITED_PMC_OK) {
+                       cflags[i] &= ~PPMU_LIMITED_PMC_REQD;
+                       continue;
+               }
+               event = ctrs[i];
+               if (first) {
+                       eu = event->attr.exclude_user;
+                       ek = event->attr.exclude_kernel;
+                       eh = event->attr.exclude_hv;
+                       first = 0;
+               } else if (event->attr.exclude_user != eu ||
+                          event->attr.exclude_kernel != ek ||
+                          event->attr.exclude_hv != eh) {
+                       return -EAGAIN;
+               }
+       }
+
+       if (eu || ek || eh)
+               for (i = 0; i < n; ++i)
+                       if (cflags[i] & PPMU_LIMITED_PMC_OK)
+                               cflags[i] |= PPMU_LIMITED_PMC_REQD;
+
+       return 0;
+}
+
+static u64 check_and_compute_delta(u64 prev, u64 val)
+{
+       u64 delta = (val - prev) & 0xfffffffful;
+
+       /*
+        * POWER7 can roll back counter values, if the new value is smaller
+        * than the previous value it will cause the delta and the counter to
+        * have bogus values unless we rolled a counter over.  If a coutner is
+        * rolled back, it will be smaller, but within 256, which is the maximum
+        * number of events to rollback at once.  If we dectect a rollback
+        * return 0.  This can lead to a small lack of precision in the
+        * counters.
+        */
+       if (prev > val && (prev - val) < 256)
+               delta = 0;
+
+       return delta;
+}
+
+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;
+       /*
+        * Performance monitor interrupts come even when interrupts
+        * are soft-disabled, as long as interrupts are hard-enabled.
+        * Therefore we treat them like NMIs.
+        */
+       do {
+               prev = local64_read(&event->hw.prev_count);
+               barrier();
+               val = read_pmc(event->hw.idx);
+               delta = check_and_compute_delta(prev, val);
+               if (!delta)
+                       return;
+       } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+
+       local64_add(delta, &event->count);
+       local64_sub(delta, &event->hw.period_left);
+}
+
+/*
+ * On some machines, PMC5 and PMC6 can't be written, don't respect
+ * the freeze conditions, and don't generate interrupts.  This tells
+ * us if `event' is using such a PMC.
+ */
+static int is_limited_pmc(int pmcnum)
+{
+       return (ppmu->flags & PPMU_LIMITED_PMC5_6)
+               && (pmcnum == 5 || pmcnum == 6);
+}
+
+static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
+                                   unsigned long pmc5, unsigned long pmc6)
+{
+       struct perf_event *event;
+       u64 val, prev, delta;
+       int i;
+
+       for (i = 0; i < cpuhw->n_limited; ++i) {
+               event = cpuhw->limited_counter[i];
+               if (!event->hw.idx)
+                       continue;
+               val = (event->hw.idx == 5) ? pmc5 : pmc6;
+               prev = local64_read(&event->hw.prev_count);
+               event->hw.idx = 0;
+               delta = check_and_compute_delta(prev, val);
+               if (delta)
+                       local64_add(delta, &event->count);
+       }
+}
+
+static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
+                                 unsigned long pmc5, unsigned long pmc6)
+{
+       struct perf_event *event;
+       u64 val, prev;
+       int i;
+
+       for (i = 0; i < cpuhw->n_limited; ++i) {
+               event = cpuhw->limited_counter[i];
+               event->hw.idx = cpuhw->limited_hwidx[i];
+               val = (event->hw.idx == 5) ? pmc5 : pmc6;
+               prev = local64_read(&event->hw.prev_count);
+               if (check_and_compute_delta(prev, val))
+                       local64_set(&event->hw.prev_count, val);
+               perf_event_update_userpage(event);
+       }
+}
+
+/*
+ * Since limited events don't respect the freeze conditions, we
+ * have to read them immediately after freezing or unfreezing the
+ * other events.  We try to keep the values from the limited
+ * events as consistent as possible by keeping the delay (in
+ * cycles and instructions) between freezing/unfreezing and reading
+ * the limited events as small and consistent as possible.
+ * Therefore, if any limited events are in use, we read them
+ * both, and always in the same order, to minimize variability,
+ * and do it inside the same asm that writes MMCR0.
+ */
+static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
+{
+       unsigned long pmc5, pmc6;
+
+       if (!cpuhw->n_limited) {
+               mtspr(SPRN_MMCR0, mmcr0);
+               return;
+       }
+
+       /*
+        * Write MMCR0, then read PMC5 and PMC6 immediately.
+        * To ensure we don't get a performance monitor interrupt
+        * between writing MMCR0 and freezing/thawing the limited
+        * events, we first write MMCR0 with the event overflow
+        * interrupt enable bits turned off.
+        */
+       asm volatile("mtspr %3,%2; mfspr %0,%4; mfspr %1,%5"
+                    : "=&r" (pmc5), "=&r" (pmc6)
+                    : "r" (mmcr0 & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)),
+                      "i" (SPRN_MMCR0),
+                      "i" (SPRN_PMC5), "i" (SPRN_PMC6));
+
+       if (mmcr0 & MMCR0_FC)
+               freeze_limited_counters(cpuhw, pmc5, pmc6);
+       else
+               thaw_limited_counters(cpuhw, pmc5, pmc6);
+
+       /*
+        * Write the full MMCR0 including the event overflow interrupt
+        * enable bits, if necessary.
+        */
+       if (mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE))
+               mtspr(SPRN_MMCR0, mmcr0);
+}
+
+/*
+ * Disable all events to prevent PMU interrupts and to allow
+ * events to be added or removed.
+ */
+static void power_pmu_disable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw;
+       unsigned long flags;
+
+       if (!ppmu)
+               return;
+       local_irq_save(flags);
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       if (!cpuhw->disabled) {
+               cpuhw->disabled = 1;
+               cpuhw->n_added = 0;
+
+               /*
+                * Check if we ever enabled the PMU on this cpu.
+                */
+               if (!cpuhw->pmcs_enabled) {
+                       ppc_enable_pmcs();
+                       cpuhw->pmcs_enabled = 1;
+               }
+
+               /*
+                * Disable instruction sampling if it was enabled
+                */
+               if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
+                       mtspr(SPRN_MMCRA,
+                             cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+                       mb();
+               }
+
+               /*
+                * Set the 'freeze counters' bit.
+                * The barrier is to make sure the mtspr has been
+                * executed and the PMU has frozen the events
+                * before we return.
+                */
+               write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
+               mb();
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Re-enable all events if disable == 0.
+ * If we were previously disabled and events were added, then
+ * put the new config on the PMU.
+ */
+static void power_pmu_enable(struct pmu *pmu)
+{
+       struct perf_event *event;
+       struct cpu_hw_events *cpuhw;
+       unsigned long flags;
+       long i;
+       unsigned long val;
+       s64 left;
+       unsigned int hwc_index[MAX_HWEVENTS];
+       int n_lim;
+       int idx;
+
+       if (!ppmu)
+               return;
+       local_irq_save(flags);
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+       if (!cpuhw->disabled) {
+               local_irq_restore(flags);
+               return;
+       }
+       cpuhw->disabled = 0;
+
+       /*
+        * If we didn't change anything, or only removed events,
+        * no need to recalculate MMCR* settings and reset the PMCs.
+        * Just reenable the PMU with the current MMCR* settings
+        * (possibly updated for removal of events).
+        */
+       if (!cpuhw->n_added) {
+               mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+               mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
+               if (cpuhw->n_events == 0)
+                       ppc_set_pmu_inuse(0);
+               goto out_enable;
+       }
+
+       /*
+        * Compute MMCR* values for the new set of events
+        */
+       if (ppmu->compute_mmcr(cpuhw->events, cpuhw->n_events, hwc_index,
+                              cpuhw->mmcr)) {
+               /* shouldn't ever get here */
+               printk(KERN_ERR "oops compute_mmcr failed\n");
+               goto out;
+       }
+
+       /*
+        * Add in MMCR0 freeze bits corresponding to the
+        * attr.exclude_* bits for the first event.
+        * We have already checked that all events have the
+        * same values for these bits as the first event.
+        */
+       event = cpuhw->event[0];
+       if (event->attr.exclude_user)
+               cpuhw->mmcr[0] |= MMCR0_FCP;
+       if (event->attr.exclude_kernel)
+               cpuhw->mmcr[0] |= freeze_events_kernel;
+       if (event->attr.exclude_hv)
+               cpuhw->mmcr[0] |= MMCR0_FCHV;
+
+       /*
+        * Write the new configuration to MMCR* with the freeze
+        * bit set and set the hardware events to their initial values.
+        * Then unfreeze the events.
+        */
+       ppc_set_pmu_inuse(1);
+       mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
+       mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
+       mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
+                               | MMCR0_FC);
+
+       /*
+        * Read off any pre-existing events that need to move
+        * to another PMC.
+        */
+       for (i = 0; i < cpuhw->n_events; ++i) {
+               event = cpuhw->event[i];
+               if (event->hw.idx && event->hw.idx != hwc_index[i] + 1) {
+                       power_pmu_read(event);
+                       write_pmc(event->hw.idx, 0);
+                       event->hw.idx = 0;
+               }
+       }
+
+       /*
+        * Initialize the PMCs for all the new and moved events.
+        */
+       cpuhw->n_limited = n_lim = 0;
+       for (i = 0; i < cpuhw->n_events; ++i) {
+               event = cpuhw->event[i];
+               if (event->hw.idx)
+                       continue;
+               idx = hwc_index[i] + 1;
+               if (is_limited_pmc(idx)) {
+                       cpuhw->limited_counter[n_lim] = event;
+                       cpuhw->limited_hwidx[n_lim] = idx;
+                       ++n_lim;
+                       continue;
+               }
+               val = 0;
+               if (event->hw.sample_period) {
+                       left = local64_read(&event->hw.period_left);
+                       if (left < 0x80000000L)
+                               val = 0x80000000L - left;
+               }
+               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);
+       }
+       cpuhw->n_limited = n_lim;
+       cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
+
+ out_enable:
+       mb();
+       write_mmcr0(cpuhw, cpuhw->mmcr[0]);
+
+       /*
+        * Enable instruction sampling if necessary
+        */
+       if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
+               mb();
+               mtspr(SPRN_MMCRA, cpuhw->mmcr[2]);
+       }
+
+ out:
+       local_irq_restore(flags);
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+                         struct perf_event *ctrs[], u64 *events,
+                         unsigned int *flags)
+{
+       int n = 0;
+       struct perf_event *event;
+
+       if (!is_software_event(group)) {
+               if (n >= max_count)
+                       return -1;
+               ctrs[n] = group;
+               flags[n] = group->hw.event_base;
+               events[n++] = group->hw.config;
+       }
+       list_for_each_entry(event, &group->sibling_list, group_entry) {
+               if (!is_software_event(event) &&
+                   event->state != PERF_EVENT_STATE_OFF) {
+                       if (n >= max_count)
+                               return -1;
+                       ctrs[n] = event;
+                       flags[n] = event->hw.event_base;
+                       events[n++] = event->hw.config;
+               }
+       }
+       return n;
+}
+
+/*
+ * Add a event to the PMU.
+ * If all events are not already frozen, then we disable and
+ * re-enable the PMU in order to get hw_perf_enable to do the
+ * actual work of reconfiguring the PMU.
+ */
+static int power_pmu_add(struct perf_event *event, int ef_flags)
+{
+       struct cpu_hw_events *cpuhw;
+       unsigned long flags;
+       int n0;
+       int ret = -EAGAIN;
+
+       local_irq_save(flags);
+       perf_pmu_disable(event->pmu);
+
+       /*
+        * Add the event to the list (if there is room)
+        * and check whether the total set is still feasible.
+        */
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+       n0 = cpuhw->n_events;
+       if (n0 >= ppmu->n_counter)
+               goto out;
+       cpuhw->event[n0] = 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 performed
+        * at commit time(->commit_txn) as a whole
+        */
+       if (cpuhw->group_flag & PERF_EVENT_TXN)
+               goto nocheck;
+
+       if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
+               goto out;
+       if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
+               goto out;
+       event->hw.config = cpuhw->events[n0];
+
+nocheck:
+       ++cpuhw->n_events;
+       ++cpuhw->n_added;
+
+       ret = 0;
+ out:
+       perf_pmu_enable(event->pmu);
+       local_irq_restore(flags);
+       return ret;
+}
+
+/*
+ * Remove a event from the PMU.
+ */
+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_pmu_disable(event->pmu);
+
+       power_pmu_read(event);
+
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+       for (i = 0; i < cpuhw->n_events; ++i) {
+               if (event == cpuhw->event[i]) {
+                       while (++i < cpuhw->n_events) {
+                               cpuhw->event[i-1] = cpuhw->event[i];
+                               cpuhw->events[i-1] = cpuhw->events[i];
+                               cpuhw->flags[i-1] = cpuhw->flags[i];
+                       }
+                       --cpuhw->n_events;
+                       ppmu->disable_pmc(event->hw.idx - 1, cpuhw->mmcr);
+                       if (event->hw.idx) {
+                               write_pmc(event->hw.idx, 0);
+                               event->hw.idx = 0;
+                       }
+                       perf_event_update_userpage(event);
+                       break;
+               }
+       }
+       for (i = 0; i < cpuhw->n_limited; ++i)
+               if (event == cpuhw->limited_counter[i])
+                       break;
+       if (i < cpuhw->n_limited) {
+               while (++i < cpuhw->n_limited) {
+                       cpuhw->limited_counter[i-1] = cpuhw->limited_counter[i];
+                       cpuhw->limited_hwidx[i-1] = cpuhw->limited_hwidx[i];
+               }
+               --cpuhw->n_limited;
+       }
+       if (cpuhw->n_events == 0) {
+               /* disable exceptions if no events are running */
+               cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
+       }
+
+       perf_pmu_enable(event->pmu);
+       local_irq_restore(flags);
+}
+
+/*
+ * 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_start(struct perf_event *event, int ef_flags)
+{
+       unsigned long flags;
+       s64 left;
+       unsigned long val;
+
+       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);
+
+       val = 0;
+       if (left < 0x80000000L)
+               val = 0x80000000L - left;
+
+       write_pmc(event->hw.idx, val);
+
+       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)
+{
+       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_pmu_disable(event->pmu);
+
+       power_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);
+}
+
+/*
+ * Start group events scheduling transaction
+ * Set the flag to make pmu::enable() not perform the
+ * schedulability test, it will be performed at commit time
+ */
+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;
+}
+
+/*
+ * Stop group events scheduling transaction
+ * Clear the flag and pmu::enable() will perform the
+ * schedulability test.
+ */
+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);
+}
+
+/*
+ * Commit group events scheduling transaction
+ * Perform the group schedulability test as a whole
+ * Return 0 if success
+ */
+int power_pmu_commit_txn(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw;
+       long i, n;
+
+       if (!ppmu)
+               return -EAGAIN;
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+       n = cpuhw->n_events;
+       if (check_excludes(cpuhw->event, cpuhw->flags, 0, n))
+               return -EAGAIN;
+       i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n);
+       if (i < 0)
+               return -EAGAIN;
+
+       for (i = cpuhw->n_txn_start; i < n; ++i)
+               cpuhw->event[i]->hw.config = cpuhw->events[i];
+
+       cpuhw->group_flag &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
+       return 0;
+}
+
+/*
+ * Return 1 if we might be able to put event on a limited PMC,
+ * or 0 if not.
+ * A event can only go on a limited PMC if it counts something
+ * that a limited PMC can count, doesn't require interrupts, and
+ * doesn't exclude any processor mode.
+ */
+static int can_go_on_limited_pmc(struct perf_event *event, u64 ev,
+                                unsigned int flags)
+{
+       int n;
+       u64 alt[MAX_EVENT_ALTERNATIVES];
+
+       if (event->attr.exclude_user
+           || event->attr.exclude_kernel
+           || event->attr.exclude_hv
+           || event->attr.sample_period)
+               return 0;
+
+       if (ppmu->limited_pmc_event(ev))
+               return 1;
+
+       /*
+        * The requested event_id isn't on a limited PMC already;
+        * see if any alternative code goes on a limited PMC.
+        */
+       if (!ppmu->get_alternatives)
+               return 0;
+
+       flags |= PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD;
+       n = ppmu->get_alternatives(ev, flags, alt);
+
+       return n > 0;
+}
+
+/*
+ * Find an alternative event_id that goes on a normal PMC, if possible,
+ * and return the event_id code, or 0 if there is no such alternative.
+ * (Note: event_id code 0 is "don't count" on all machines.)
+ */
+static u64 normal_pmc_alternative(u64 ev, unsigned long flags)
+{
+       u64 alt[MAX_EVENT_ALTERNATIVES];
+       int n;
+
+       flags &= ~(PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD);
+       n = ppmu->get_alternatives(ev, flags, alt);
+       if (!n)
+               return 0;
+       return alt[0];
+}
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * Release the PMU if this is the last perf_event.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+       if (!atomic_add_unless(&num_events, -1, 1)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_dec_return(&num_events) == 0)
+                       release_pmc_hardware();
+               mutex_unlock(&pmc_reserve_mutex);
+       }
+}
+
+/*
+ * Translate a generic cache event_id config to a raw event_id code.
+ */
+static int hw_perf_cache_event(u64 config, u64 *eventp)
+{
+       unsigned long type, op, result;
+       int ev;
+
+       if (!ppmu->cache_events)
+               return -EINVAL;
+
+       /* unpack config */
+       type = config & 0xff;
+       op = (config >> 8) & 0xff;
+       result = (config >> 16) & 0xff;
+
+       if (type >= PERF_COUNT_HW_CACHE_MAX ||
+           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       ev = (*ppmu->cache_events)[type][op][result];
+       if (ev == 0)
+               return -EOPNOTSUPP;
+       if (ev == -1)
+               return -EINVAL;
+       *eventp = ev;
+       return 0;
+}
+
+static int power_pmu_event_init(struct perf_event *event)
+{
+       u64 ev;
+       unsigned long flags;
+       struct perf_event *ctrs[MAX_HWEVENTS];
+       u64 events[MAX_HWEVENTS];
+       unsigned int cflags[MAX_HWEVENTS];
+       int n;
+       int err;
+       struct cpu_hw_events *cpuhw;
+
+       if (!ppmu)
+               return -ENOENT;
+
+       /* does not support taken branch sampling */
+       if (has_branch_stack(event))
+               return -EOPNOTSUPP;
+
+       switch (event->attr.type) {
+       case PERF_TYPE_HARDWARE:
+               ev = event->attr.config;
+               if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
+                       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;
+               break;
+       case PERF_TYPE_RAW:
+               ev = event->attr.config;
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       event->hw.config_base = ev;
+       event->hw.idx = 0;
+
+       /*
+        * If we are not running on a hypervisor, force the
+        * exclude_hv bit to 0 so that we don't care what
+        * the user set it to.
+        */
+       if (!firmware_has_feature(FW_FEATURE_LPAR))
+               event->attr.exclude_hv = 0;
+
+       /*
+        * If this is a per-task event, then we can use
+        * PM_RUN_* events interchangeably with their non RUN_*
+        * equivalents, e.g. PM_RUN_CYC instead of PM_CYC.
+        * XXX we should check if the task is an idle task.
+        */
+       flags = 0;
+       if (event->attach_state & PERF_ATTACH_TASK)
+               flags |= PPMU_ONLY_COUNT_RUN;
+
+       /*
+        * If this machine has limited events, check whether this
+        * event_id could go on a limited event.
+        */
+       if (ppmu->flags & PPMU_LIMITED_PMC5_6) {
+               if (can_go_on_limited_pmc(event, ev, flags)) {
+                       flags |= PPMU_LIMITED_PMC_OK;
+               } else if (ppmu->limited_pmc_event(ev)) {
+                       /*
+                        * The requested event_id is on a limited PMC,
+                        * but we can't use a limited PMC; see if any
+                        * alternative goes on a normal PMC.
+                        */
+                       ev = normal_pmc_alternative(ev, flags);
+                       if (!ev)
+                               return -EINVAL;
+               }
+       }
+
+       /*
+        * If this is in a group, check if it can go on with all the
+        * other hardware events in the group.  We assume the event
+        * hasn't been linked into its leader's sibling list at this point.
+        */
+       n = 0;
+       if (event->group_leader != event) {
+               n = collect_events(event->group_leader, ppmu->n_counter - 1,
+                                  ctrs, events, cflags);
+               if (n < 0)
+                       return -EINVAL;
+       }
+       events[n] = ev;
+       ctrs[n] = event;
+       cflags[n] = flags;
+       if (check_excludes(ctrs, cflags, n, 1))
+               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 -EINVAL;
+
+       event->hw.config = events[n];
+       event->hw.event_base = cflags[n];
+       event->hw.last_period = event->hw.sample_period;
+       local64_set(&event->hw.period_left, event->hw.last_period);
+
+       /*
+        * See if we need to reserve the PMU.
+        * If no events are currently in use, then we have to take a
+        * mutex to ensure that we don't race with another task doing
+        * reserve_pmc_hardware or release_pmc_hardware.
+        */
+       err = 0;
+       if (!atomic_inc_not_zero(&num_events)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_read(&num_events) == 0 &&
+                   reserve_pmc_hardware(perf_event_interrupt))
+                       err = -EBUSY;
+               else
+                       atomic_inc(&num_events);
+               mutex_unlock(&pmc_reserve_mutex);
+       }
+       event->destroy = hw_perf_event_destroy;
+
+       return err;
+}
+
+static int power_pmu_event_idx(struct perf_event *event)
+{
+       return event->hw.idx;
+}
+
+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,
+       .event_idx      = power_pmu_event_idx,
+};
+
+/*
+ * A counter has overflowed; update its count and record
+ * things if requested.  Note that interrupts are hard-disabled
+ * here so there is no possibility of being interrupted.
+ */
+static void record_and_restart(struct perf_event *event, unsigned long val,
+                              struct pt_regs *regs)
+{
+       u64 period = event->hw.sample_period;
+       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 = check_and_compute_delta(prev, val);
+       local64_add(delta, &event->count);
+
+       /*
+        * See if the total period for this event has expired,
+        * and update for the next period.
+        */
+       val = 0;
+       left = local64_read(&event->hw.period_left) - delta;
+       if (period) {
+               if (left <= 0) {
+                       left += period;
+                       if (left <= 0)
+                               left = period;
+                       record = 1;
+                       event->hw.last_period = event->hw.sample_period;
+               }
+               if (left < 0x80000000LL)
+                       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.
+        */
+       if (record) {
+               struct perf_sample_data data;
+
+               perf_sample_data_init(&data, ~0ULL);
+               data.period = event->hw.last_period;
+
+               if (event->attr.sample_type & PERF_SAMPLE_ADDR)
+                       perf_get_data_addr(regs, &data.addr);
+
+               if (perf_event_overflow(event, &data, regs))
+                       power_pmu_stop(event, 0);
+       }
+}
+
+/*
+ * Called from generic code to get the misc flags (i.e. processor mode)
+ * for an event_id.
+ */
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+       u32 flags = perf_get_misc_flags(regs);
+
+       if (flags)
+               return flags;
+       return user_mode(regs) ? PERF_RECORD_MISC_USER :
+               PERF_RECORD_MISC_KERNEL;
+}
+
+/*
+ * Called from generic code to get the instruction pointer
+ * for an event_id.
+ */
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+       unsigned long ip;
+
+       if (TRAP(regs) != 0xf00)
+               return regs->nip;       /* not a PMU interrupt */
+
+       ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
+       return ip;
+}
+
+static bool pmc_overflow(unsigned long val)
+{
+       if ((int)val < 0)
+               return true;
+
+       /*
+        * Events on POWER7 can roll back if a speculative event doesn't
+        * eventually complete. Unfortunately in some rare cases they will
+        * raise a performance monitor exception. We need to catch this to
+        * ensure we reset the PMC. In all cases the PMC will be 256 or less
+        * cycles from overflow.
+        *
+        * We only do this if the first pass fails to find any overflowing
+        * PMCs because a user might set a period of less than 256 and we
+        * don't want to mistakenly reset them.
+        */
+       if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
+               return true;
+
+       return false;
+}
+
+/*
+ * Performance monitor interrupt stuff
+ */
+static void perf_event_interrupt(struct pt_regs *regs)
+{
+       int i;
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event;
+       unsigned long val;
+       int found = 0;
+       int nmi;
+
+       if (cpuhw->n_limited)
+               freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),
+                                       mfspr(SPRN_PMC6));
+
+       perf_read_regs(regs);
+
+       nmi = perf_intr_is_nmi(regs);
+       if (nmi)
+               nmi_enter();
+       else
+               irq_enter();
+
+       for (i = 0; i < cpuhw->n_events; ++i) {
+               event = cpuhw->event[i];
+               if (!event->hw.idx || is_limited_pmc(event->hw.idx))
+                       continue;
+               val = read_pmc(event->hw.idx);
+               if ((int)val < 0) {
+                       /* event has overflowed */
+                       found = 1;
+                       record_and_restart(event, val, regs);
+               }
+       }
+
+       /*
+        * In case we didn't find and reset the event that caused
+        * the interrupt, scan all events and reset any that are
+        * negative, to avoid getting continual interrupts.
+        * Any that we processed in the previous loop will not be negative.
+        */
+       if (!found) {
+               for (i = 0; i < ppmu->n_counter; ++i) {
+                       if (is_limited_pmc(i + 1))
+                               continue;
+                       val = read_pmc(i + 1);
+                       if (pmc_overflow(val))
+                               write_pmc(i + 1, 0);
+               }
+       }
+
+       /*
+        * Reset MMCR0 to its normal value.  This will set PMXE and
+        * clear FC (freeze counters) and PMAO (perf mon alert occurred)
+        * and thus allow interrupts to occur again.
+        * XXX might want to use MSR.PM to keep the events frozen until
+        * we get back out of this interrupt.
+        */
+       write_mmcr0(cpuhw, cpuhw->mmcr[0]);
+
+       if (nmi)
+               nmi_exit();
+       else
+               irq_exit();
+}
+
+static void power_pmu_setup(int cpu)
+{
+       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+       if (!ppmu)
+               return;
+       memset(cpuhw, 0, sizeof(*cpuhw));
+       cpuhw->mmcr[0] = MMCR0_FC;
+}
+
+static int __cpuinit
+power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               power_pmu_setup(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+int __cpuinit register_power_pmu(struct power_pmu *pmu)
+{
+       if (ppmu)
+               return -EBUSY;          /* something's already registered */
+
+       ppmu = pmu;
+       pr_info("%s performance monitor hardware support registered\n",
+               pmu->name);
+
+#ifdef MSR_HV
+       /*
+        * Use FCHV to ignore kernel events if MSR.HV is set.
+        */
+       if (mfmsr() & MSR_HV)
+               freeze_events_kernel = MMCR0_FCHV;
+#endif /* CONFIG_PPC64 */
+
+       perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
+       perf_cpu_notifier(power_pmu_notifier);
+
+       return 0;
+}
diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c
new file mode 100644 (file)
index 0000000..0a6d2a9
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ * Performance event support - Freescale Embedded Performance Monitor
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ * 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/sched.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <asm/reg_fsl_emb.h>
+#include <asm/pmc.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/ptrace.h>
+
+struct cpu_hw_events {
+       int n_events;
+       int disabled;
+       u8  pmcs_enabled;
+       struct perf_event *event[MAX_HWEVENTS];
+};
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static struct fsl_emb_pmu *ppmu;
+
+/* Number of perf_events counting hardware events */
+static atomic_t num_events;
+/* Used to avoid races in calling reserve/release_pmc_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/*
+ * If interrupts were soft-disabled when a PMU interrupt occurs, treat
+ * it as an NMI.
+ */
+static inline int perf_intr_is_nmi(struct pt_regs *regs)
+{
+#ifdef __powerpc64__
+       return !regs->softe;
+#else
+       return 0;
+#endif
+}
+
+static void perf_event_interrupt(struct pt_regs *regs);
+
+/*
+ * Read one performance monitor counter (PMC).
+ */
+static unsigned long read_pmc(int idx)
+{
+       unsigned long val;
+
+       switch (idx) {
+       case 0:
+               val = mfpmr(PMRN_PMC0);
+               break;
+       case 1:
+               val = mfpmr(PMRN_PMC1);
+               break;
+       case 2:
+               val = mfpmr(PMRN_PMC2);
+               break;
+       case 3:
+               val = mfpmr(PMRN_PMC3);
+               break;
+       default:
+               printk(KERN_ERR "oops trying to read PMC%d\n", idx);
+               val = 0;
+       }
+       return val;
+}
+
+/*
+ * Write one PMC.
+ */
+static void write_pmc(int idx, unsigned long val)
+{
+       switch (idx) {
+       case 0:
+               mtpmr(PMRN_PMC0, val);
+               break;
+       case 1:
+               mtpmr(PMRN_PMC1, val);
+               break;
+       case 2:
+               mtpmr(PMRN_PMC2, val);
+               break;
+       case 3:
+               mtpmr(PMRN_PMC3, val);
+               break;
+       default:
+               printk(KERN_ERR "oops trying to write PMC%d\n", idx);
+       }
+
+       isync();
+}
+
+/*
+ * Write one local control A register
+ */
+static void write_pmlca(int idx, unsigned long val)
+{
+       switch (idx) {
+       case 0:
+               mtpmr(PMRN_PMLCA0, val);
+               break;
+       case 1:
+               mtpmr(PMRN_PMLCA1, val);
+               break;
+       case 2:
+               mtpmr(PMRN_PMLCA2, val);
+               break;
+       case 3:
+               mtpmr(PMRN_PMLCA3, val);
+               break;
+       default:
+               printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
+       }
+
+       isync();
+}
+
+/*
+ * Write one local control B register
+ */
+static void write_pmlcb(int idx, unsigned long val)
+{
+       switch (idx) {
+       case 0:
+               mtpmr(PMRN_PMLCB0, val);
+               break;
+       case 1:
+               mtpmr(PMRN_PMLCB1, val);
+               break;
+       case 2:
+               mtpmr(PMRN_PMLCB2, val);
+               break;
+       case 3:
+               mtpmr(PMRN_PMLCB3, val);
+               break;
+       default:
+               printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
+       }
+
+       isync();
+}
+
+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.
+        * Therefore we treat them like NMIs.
+        */
+       do {
+               prev = local64_read(&event->hw.prev_count);
+               barrier();
+               val = read_pmc(event->hw.idx);
+       } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
+
+       /* The counters are only 32 bits wide */
+       delta = (val - prev) & 0xfffffffful;
+       local64_add(delta, &event->count);
+       local64_sub(delta, &event->hw.period_left);
+}
+
+/*
+ * Disable all events to prevent PMU interrupts and to allow
+ * events to be added or removed.
+ */
+static void fsl_emb_pmu_disable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       if (!cpuhw->disabled) {
+               cpuhw->disabled = 1;
+
+               /*
+                * Check if we ever enabled the PMU on this cpu.
+                */
+               if (!cpuhw->pmcs_enabled) {
+                       ppc_enable_pmcs();
+                       cpuhw->pmcs_enabled = 1;
+               }
+
+               if (atomic_read(&num_events)) {
+                       /*
+                        * Set the 'freeze all counters' bit, and disable
+                        * interrupts.  The barrier is to make sure the
+                        * mtpmr has been executed and the PMU has frozen
+                        * the events before we return.
+                        */
+
+                       mtpmr(PMRN_PMGC0, PMGC0_FAC);
+                       isync();
+               }
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Re-enable all events if disable == 0.
+ * If we were previously disabled and events were added, then
+ * put the new config on the PMU.
+ */
+static void fsl_emb_pmu_enable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+       if (!cpuhw->disabled)
+               goto out;
+
+       cpuhw->disabled = 0;
+       ppc_set_pmu_inuse(cpuhw->n_events != 0);
+
+       if (cpuhw->n_events > 0) {
+               mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
+               isync();
+       }
+
+ out:
+       local_irq_restore(flags);
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+                         struct perf_event *ctrs[])
+{
+       int n = 0;
+       struct perf_event *event;
+
+       if (!is_software_event(group)) {
+               if (n >= max_count)
+                       return -1;
+               ctrs[n] = group;
+               n++;
+       }
+       list_for_each_entry(event, &group->sibling_list, group_entry) {
+               if (!is_software_event(event) &&
+                   event->state != PERF_EVENT_STATE_OFF) {
+                       if (n >= max_count)
+                               return -1;
+                       ctrs[n] = event;
+                       n++;
+               }
+       }
+       return n;
+}
+
+/* context locked on entry */
+static int fsl_emb_pmu_add(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuhw;
+       int ret = -EAGAIN;
+       int num_counters = ppmu->n_counter;
+       u64 val;
+       int i;
+
+       perf_pmu_disable(event->pmu);
+       cpuhw = &get_cpu_var(cpu_hw_events);
+
+       if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
+               num_counters = ppmu->n_restricted;
+
+       /*
+        * Allocate counters from top-down, so that restricted-capable
+        * counters are kept free as long as possible.
+        */
+       for (i = num_counters - 1; i >= 0; i--) {
+               if (cpuhw->event[i])
+                       continue;
+
+               break;
+       }
+
+       if (i < 0)
+               goto out;
+
+       event->hw.idx = i;
+       cpuhw->event[i] = event;
+       ++cpuhw->n_events;
+
+       val = 0;
+       if (event->hw.sample_period) {
+               s64 left = local64_read(&event->hw.period_left);
+               if (left < 0x80000000L)
+                       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);
+
+       write_pmlcb(i, event->hw.config >> 32);
+       write_pmlca(i, event->hw.config_base);
+
+       ret = 0;
+ out:
+       put_cpu_var(cpu_hw_events);
+       perf_pmu_enable(event->pmu);
+       return ret;
+}
+
+/* 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;
+
+       fsl_emb_pmu_read(event);
+
+       cpuhw = &get_cpu_var(cpu_hw_events);
+
+       WARN_ON(event != cpuhw->event[event->hw.idx]);
+
+       write_pmlca(i, 0);
+       write_pmlcb(i, 0);
+       write_pmc(i, 0);
+
+       cpuhw->event[i] = NULL;
+       event->hw.idx = -1;
+
+       /*
+        * TODO: if at least one restricted event exists, and we
+        * just freed up a non-restricted-capable counter, and
+        * there is a restricted-capable counter occupied by
+        * a non-restricted event, migrate that event to the
+        * vacated counter.
+        */
+
+       cpuhw->n_events--;
+
+ out:
+       perf_pmu_enable(event->pmu);
+       put_cpu_var(cpu_hw_events);
+}
+
+static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
+{
+       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_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 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.
+ */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+       if (!atomic_add_unless(&num_events, -1, 1)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_dec_return(&num_events) == 0)
+                       release_pmc_hardware();
+               mutex_unlock(&pmc_reserve_mutex);
+       }
+}
+
+/*
+ * Translate a generic cache event_id config to a raw event_id code.
+ */
+static int hw_perf_cache_event(u64 config, u64 *eventp)
+{
+       unsigned long type, op, result;
+       int ev;
+
+       if (!ppmu->cache_events)
+               return -EINVAL;
+
+       /* unpack config */
+       type = config & 0xff;
+       op = (config >> 8) & 0xff;
+       result = (config >> 16) & 0xff;
+
+       if (type >= PERF_COUNT_HW_CACHE_MAX ||
+           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       ev = (*ppmu->cache_events)[type][op][result];
+       if (ev == 0)
+               return -EOPNOTSUPP;
+       if (ev == -1)
+               return -EINVAL;
+       *eventp = ev;
+       return 0;
+}
+
+static int fsl_emb_pmu_event_init(struct perf_event *event)
+{
+       u64 ev;
+       struct perf_event *events[MAX_HWEVENTS];
+       int n;
+       int err;
+       int num_restricted;
+       int i;
+
+       switch (event->attr.type) {
+       case PERF_TYPE_HARDWARE:
+               ev = event->attr.config;
+               if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
+                       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;
+               break;
+
+       case PERF_TYPE_RAW:
+               ev = event->attr.config;
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
+       event->hw.config = ppmu->xlate_event(ev);
+       if (!(event->hw.config & FSL_EMB_EVENT_VALID))
+               return -EINVAL;
+
+       /*
+        * If this is in a group, check if it can go on with all the
+        * other hardware events in the group.  We assume the event
+        * hasn't been linked into its leader's sibling list at this point.
+        */
+       n = 0;
+       if (event->group_leader != event) {
+               n = collect_events(event->group_leader,
+                                  ppmu->n_counter - 1, events);
+               if (n < 0)
+                       return -EINVAL;
+       }
+
+       if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
+               num_restricted = 0;
+               for (i = 0; i < n; i++) {
+                       if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
+                               num_restricted++;
+               }
+
+               if (num_restricted >= ppmu->n_restricted)
+                       return -EINVAL;
+       }
+
+       event->hw.idx = -1;
+
+       event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
+                               (u32)((ev << 16) & PMLCA_EVENT_MASK);
+
+       if (event->attr.exclude_user)
+               event->hw.config_base |= PMLCA_FCU;
+       if (event->attr.exclude_kernel)
+               event->hw.config_base |= PMLCA_FCS;
+       if (event->attr.exclude_idle)
+               return -ENOTSUPP;
+
+       event->hw.last_period = event->hw.sample_period;
+       local64_set(&event->hw.period_left, event->hw.last_period);
+
+       /*
+        * See if we need to reserve the PMU.
+        * If no events are currently in use, then we have to take a
+        * mutex to ensure that we don't race with another task doing
+        * reserve_pmc_hardware or release_pmc_hardware.
+        */
+       err = 0;
+       if (!atomic_inc_not_zero(&num_events)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_read(&num_events) == 0 &&
+                   reserve_pmc_hardware(perf_event_interrupt))
+                       err = -EBUSY;
+               else
+                       atomic_inc(&num_events);
+               mutex_unlock(&pmc_reserve_mutex);
+
+               mtpmr(PMRN_PMGC0, PMGC0_FAC);
+               isync();
+       }
+       event->destroy = hw_perf_event_destroy;
+
+       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
+ * here so there is no possibility of being interrupted.
+ */
+static void record_and_restart(struct perf_event *event, unsigned long val,
+                              struct pt_regs *regs)
+{
+       u64 period = event->hw.sample_period;
+       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;
+       local64_add(delta, &event->count);
+
+       /*
+        * See if the total period for this event has expired,
+        * and update for the next period.
+        */
+       val = 0;
+       left = local64_read(&event->hw.period_left) - delta;
+       if (period) {
+               if (left <= 0) {
+                       left += period;
+                       if (left <= 0)
+                               left = period;
+                       record = 1;
+                       event->hw.last_period = event->hw.sample_period;
+               }
+               if (left < 0x80000000LL)
+                       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.
+        */
+       if (record) {
+               struct perf_sample_data data;
+
+               perf_sample_data_init(&data, 0);
+               data.period = event->hw.last_period;
+
+               if (perf_event_overflow(event, &data, regs))
+                       fsl_emb_pmu_stop(event, 0);
+       }
+}
+
+static void perf_event_interrupt(struct pt_regs *regs)
+{
+       int i;
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event;
+       unsigned long val;
+       int found = 0;
+       int nmi;
+
+       nmi = perf_intr_is_nmi(regs);
+       if (nmi)
+               nmi_enter();
+       else
+               irq_enter();
+
+       for (i = 0; i < ppmu->n_counter; ++i) {
+               event = cpuhw->event[i];
+
+               val = read_pmc(i);
+               if ((int)val < 0) {
+                       if (event) {
+                               /* event has overflowed */
+                               found = 1;
+                               record_and_restart(event, val, regs);
+                       } else {
+                               /*
+                                * Disabled counter is negative,
+                                * reset it just in case.
+                                */
+                               write_pmc(i, 0);
+                       }
+               }
+       }
+
+       /* PMM will keep counters frozen until we return from the interrupt. */
+       mtmsr(mfmsr() | MSR_PMM);
+       mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
+       isync();
+
+       if (nmi)
+               nmi_exit();
+       else
+               irq_exit();
+}
+
+void hw_perf_event_setup(int cpu)
+{
+       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+       memset(cpuhw, 0, sizeof(*cpuhw));
+}
+
+int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
+{
+       if (ppmu)
+               return -EBUSY;          /* something's already registered */
+
+       ppmu = pmu;
+       pr_info("%s performance monitor hardware support registered\n",
+               pmu->name);
+
+       perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
+
+       return 0;
+}
diff --git a/arch/powerpc/perf/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c
new file mode 100644 (file)
index 0000000..cb2e294
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Performance counter support for e500 family processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ * 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/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Map of generic hardware event types to hardware events
+ * Zero if unsupported
+ */
+static int e500_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = 1,
+       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
+       [PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
+       [PERF_COUNT_HW_BRANCH_MISSES] = 15,
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int e500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       /*
+        * D-cache misses are not split into read/write/prefetch;
+        * use raw event 41.
+        */
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        27,             0       },
+               [C(OP_WRITE)] = {       28,             0       },
+               [C(OP_PREFETCH)] = {    29,             0       },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        2,              60      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       /*
+        * Assuming LL means L2, it's not a good match for this model.
+        * It allocates only on L1 castout or explicit prefetch, and
+        * does not have separate read/write events (but it does have
+        * separate instruction/data events).
+        */
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       0,              0       },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       /*
+        * There are data/instruction MMU misses, but that's a miss on
+        * the chip's internal level-one TLB which is probably not
+        * what the user wants.  Instead, unified level-two TLB misses
+        * are reported here.
+        */
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        26,             66      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        12,             15      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+static int num_events = 128;
+
+/* Upper half of event id is PMLCb, for threshold events */
+static u64 e500_xlate_event(u64 event_id)
+{
+       u32 event_low = (u32)event_id;
+       u64 ret;
+
+       if (event_low >= num_events)
+               return 0;
+
+       ret = FSL_EMB_EVENT_VALID;
+
+       if (event_low >= 76 && event_low <= 81) {
+               ret |= FSL_EMB_EVENT_RESTRICTED;
+               ret |= event_id &
+                      (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH);
+       } else if (event_id &
+                  (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)) {
+               /* Threshold requested on non-threshold event */
+               return 0;
+       }
+
+       return ret;
+}
+
+static struct fsl_emb_pmu e500_pmu = {
+       .name                   = "e500 family",
+       .n_counter              = 4,
+       .n_restricted           = 2,
+       .xlate_event            = e500_xlate_event,
+       .n_generic              = ARRAY_SIZE(e500_generic_events),
+       .generic_events         = e500_generic_events,
+       .cache_events           = &e500_cache_events,
+};
+
+static int init_e500_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type)
+               return -ENODEV;
+
+       if (!strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500mc"))
+               num_events = 256;
+       else if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500"))
+               return -ENODEV;
+
+       return register_fsl_emb_pmu(&e500_pmu);
+}
+
+early_initcall(init_e500_pmu);
diff --git a/arch/powerpc/perf/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c
new file mode 100644 (file)
index 0000000..fe21b51
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Performance counter support for MPC7450-family processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+#define N_COUNTER      6       /* Number of hardware counters */
+#define MAX_ALT                3       /* Maximum number of event alternative codes */
+
+/*
+ * Bits in event code for MPC7450 family
+ */
+#define PM_THRMULT_MSKS        0x40000
+#define PM_THRESH_SH   12
+#define PM_THRESH_MSK  0x3f
+#define PM_PMC_SH      8
+#define PM_PMC_MSK     7
+#define PM_PMCSEL_MSK  0x7f
+
+/*
+ * Classify events according to how specific their PMC requirements are.
+ * Result is:
+ *     0: can go on any PMC
+ *     1: can go on PMCs 1-4
+ *     2: can go on PMCs 1,2,4
+ *     3: can go on PMCs 1 or 2
+ *     4: can only go on one PMC
+ *     -1: event code is invalid
+ */
+#define N_CLASSES      5
+
+static int mpc7450_classify_event(u32 event)
+{
+       int pmc;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > N_COUNTER)
+                       return -1;
+               return 4;
+       }
+       event &= PM_PMCSEL_MSK;
+       if (event <= 1)
+               return 0;
+       if (event <= 7)
+               return 1;
+       if (event <= 13)
+               return 2;
+       if (event <= 22)
+               return 3;
+       return -1;
+}
+
+/*
+ * Events using threshold and possible threshold scale:
+ *     code    scale?  name
+ *     11e     N       PM_INSTQ_EXCEED_CYC
+ *     11f     N       PM_ALTV_IQ_EXCEED_CYC
+ *     128     Y       PM_DTLB_SEARCH_EXCEED_CYC
+ *     12b     Y       PM_LD_MISS_EXCEED_L1_CYC
+ *     220     N       PM_CQ_EXCEED_CYC
+ *     30c     N       PM_GPR_RB_EXCEED_CYC
+ *     30d     ?       PM_FPR_IQ_EXCEED_CYC ?
+ *     311     Y       PM_ITLB_SEARCH_EXCEED
+ *     410     N       PM_GPR_IQ_EXCEED_CYC
+ */
+
+/*
+ * Return use of threshold and threshold scale bits:
+ * 0 = uses neither, 1 = uses threshold, 2 = uses both
+ */
+static int mpc7450_threshold_use(u32 event)
+{
+       int pmc, sel;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       sel = event & PM_PMCSEL_MSK;
+       switch (pmc) {
+       case 1:
+               if (sel == 0x1e || sel == 0x1f)
+                       return 1;
+               if (sel == 0x28 || sel == 0x2b)
+                       return 2;
+               break;
+       case 2:
+               if (sel == 0x20)
+                       return 1;
+               break;
+       case 3:
+               if (sel == 0xc || sel == 0xd)
+                       return 1;
+               if (sel == 0x11)
+                       return 2;
+               break;
+       case 4:
+               if (sel == 0x10)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Layout of constraint bits:
+ * 33222222222211111111110000000000
+ * 10987654321098765432109876543210
+ *  |<    ><  > < > < ><><><><><><>
+ *  TS TV   G4   G3  G2P6P5P4P3P2P1
+ *
+ * P1 - P6
+ *     0 - 11: Count of events needing PMC1 .. PMC6
+ *
+ * G2
+ *     12 - 14: Count of events needing PMC1 or PMC2
+ *
+ * G3
+ *     16 - 18: Count of events needing PMC1, PMC2 or PMC4
+ *
+ * G4
+ *     20 - 23: Count of events needing PMC1, PMC2, PMC3 or PMC4
+ *
+ * TV
+ *     24 - 29: Threshold value requested
+ *
+ * TS
+ *     30: Threshold scale value requested
+ */
+
+static u32 pmcbits[N_COUNTER][2] = {
+       { 0x00844002, 0x00111001 },     /* PMC1 mask, value: P1,G2,G3,G4 */
+       { 0x00844008, 0x00111004 },     /* PMC2: P2,G2,G3,G4 */
+       { 0x00800020, 0x00100010 },     /* PMC3: P3,G4 */
+       { 0x00840080, 0x00110040 },     /* PMC4: P4,G3,G4 */
+       { 0x00000200, 0x00000100 },     /* PMC5: P5 */
+       { 0x00000800, 0x00000400 }      /* PMC6: P6 */
+};
+
+static u32 classbits[N_CLASSES - 1][2] = {
+       { 0x00000000, 0x00000000 },     /* class 0: no constraint */
+       { 0x00800000, 0x00100000 },     /* class 1: G4 */
+       { 0x00040000, 0x00010000 },     /* class 2: G3 */
+       { 0x00004000, 0x00001000 },     /* class 3: G2 */
+};
+
+static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
+                                 unsigned long *valp)
+{
+       int pmc, class;
+       u32 mask, value;
+       int thresh, tuse;
+
+       class = mpc7450_classify_event(event);
+       if (class < 0)
+               return -1;
+       if (class == 4) {
+               pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
+               mask  = pmcbits[pmc - 1][0];
+               value = pmcbits[pmc - 1][1];
+       } else {
+               mask  = classbits[class][0];
+               value = classbits[class][1];
+       }
+
+       tuse = mpc7450_threshold_use(event);
+       if (tuse) {
+               thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
+               mask  |= 0x3f << 24;
+               value |= thresh << 24;
+               if (tuse == 2) {
+                       mask |= 0x40000000;
+                       if ((unsigned int)event & PM_THRMULT_MSKS)
+                               value |= 0x40000000;
+               }
+       }
+
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+       { 0x217, 0x317 },               /* PM_L1_DCACHE_MISS */
+       { 0x418, 0x50f, 0x60f },        /* PM_SNOOP_RETRY */
+       { 0x502, 0x602 },               /* PM_L2_HIT */
+       { 0x503, 0x603 },               /* PM_L3_HIT */
+       { 0x504, 0x604 },               /* PM_L2_ICACHE_MISS */
+       { 0x505, 0x605 },               /* PM_L3_ICACHE_MISS */
+       { 0x506, 0x606 },               /* PM_L2_DCACHE_MISS */
+       { 0x507, 0x607 },               /* PM_L3_DCACHE_MISS */
+       { 0x50a, 0x623 },               /* PM_LD_HIT_L3 */
+       { 0x50b, 0x624 },               /* PM_ST_HIT_L3 */
+       { 0x50d, 0x60d },               /* PM_L2_TOUCH_HIT */
+       { 0x50e, 0x60e },               /* PM_L3_TOUCH_HIT */
+       { 0x512, 0x612 },               /* PM_INT_LOCAL */
+       { 0x513, 0x61d },               /* PM_L2_MISS */
+       { 0x514, 0x61e },               /* PM_L3_MISS */
+};
+
+/*
+ * Scan the alternatives table for a match and return the
+ * index into the alternatives table if found, else -1.
+ */
+static int find_alternative(u32 event)
+{
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+               if (event < event_alternatives[i][0])
+                       break;
+               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
+                       if (event == event_alternatives[i][j])
+                               return i;
+       }
+       return -1;
+}
+
+static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, nalt = 1;
+       u32 ae;
+
+       alt[0] = event;
+       nalt = 1;
+       i = find_alternative((u32)event);
+       if (i >= 0) {
+               for (j = 0; j < MAX_ALT; ++j) {
+                       ae = event_alternatives[i][j];
+                       if (ae && ae != (u32)event)
+                               alt[nalt++] = ae;
+               }
+       }
+       return nalt;
+}
+
+/*
+ * Bitmaps of which PMCs each class can use for classes 0 - 3.
+ * Bit i is set if PMC i+1 is usable.
+ */
+static const u8 classmap[N_CLASSES] = {
+       0x3f, 0x0f, 0x0b, 0x03, 0
+};
+
+/* Bit position and width of each PMCSEL field */
+static const int pmcsel_shift[N_COUNTER] = {
+       6,      0,      27,     22,     17,     11
+};
+static const u32 pmcsel_mask[N_COUNTER] = {
+       0x7f,   0x3f,   0x1f,   0x1f,   0x1f,   0x3f
+};
+
+/*
+ * Compute MMCR0/1/2 values for a set of events.
+ */
+static int mpc7450_compute_mmcr(u64 event[], int n_ev,
+                               unsigned int hwc[], unsigned long mmcr[])
+{
+       u8 event_index[N_CLASSES][N_COUNTER];
+       int n_classevent[N_CLASSES];
+       int i, j, class, tuse;
+       u32 pmc_inuse = 0, pmc_avail;
+       u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
+       u32 ev, pmc, thresh;
+
+       if (n_ev > N_COUNTER)
+               return -1;
+
+       /* First pass: count usage in each class */
+       for (i = 0; i < N_CLASSES; ++i)
+               n_classevent[i] = 0;
+       for (i = 0; i < n_ev; ++i) {
+               class = mpc7450_classify_event(event[i]);
+               if (class < 0)
+                       return -1;
+               j = n_classevent[class]++;
+               event_index[class][j] = i;
+       }
+
+       /* Second pass: allocate PMCs from most specific event to least */
+       for (class = N_CLASSES - 1; class >= 0; --class) {
+               for (i = 0; i < n_classevent[class]; ++i) {
+                       ev = event[event_index[class][i]];
+                       if (class == 4) {
+                               pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
+                               if (pmc_inuse & (1 << (pmc - 1)))
+                                       return -1;
+                       } else {
+                               /* Find a suitable PMC */
+                               pmc_avail = classmap[class] & ~pmc_inuse;
+                               if (!pmc_avail)
+                                       return -1;
+                               pmc = ffs(pmc_avail);
+                       }
+                       pmc_inuse |= 1 << (pmc - 1);
+
+                       tuse = mpc7450_threshold_use(ev);
+                       if (tuse) {
+                               thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
+                               mmcr0 |= thresh << 16;
+                               if (tuse == 2 && (ev & PM_THRMULT_MSKS))
+                                       mmcr2 = 0x80000000;
+                       }
+                       ev &= pmcsel_mask[pmc - 1];
+                       ev <<= pmcsel_shift[pmc - 1];
+                       if (pmc <= 2)
+                               mmcr0 |= ev;
+                       else
+                               mmcr1 |= ev;
+                       hwc[event_index[class][i]] = pmc - 1;
+               }
+       }
+
+       if (pmc_inuse & 1)
+               mmcr0 |= MMCR0_PMC1CE;
+       if (pmc_inuse & 0x3e)
+               mmcr0 |= MMCR0_PMCnCE;
+
+       /* Return MMCRx values */
+       mmcr[0] = mmcr0;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcr2;
+       return 0;
+}
+
+/*
+ * Disable counting by a PMC.
+ * Note that the pmc argument is 0-based here, not 1-based.
+ */
+static void mpc7450_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       if (pmc <= 1)
+               mmcr[0] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
+       else
+               mmcr[1] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
+}
+
+static int mpc7450_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 1,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 2,
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x217, /* PM_L1_DCACHE_MISS */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x122, /* PM_BR_CMPL */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x41c, /* PM_BR_MPRED */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x225   },
+               [C(OP_WRITE)] = {       0,              0x227   },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x129,          0x115   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    0x634,          0       },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       0,              0       },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x312   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x223   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x122,          0x41c   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+struct power_pmu mpc7450_pmu = {
+       .name                   = "MPC7450 family",
+       .n_counter              = N_COUNTER,
+       .max_alternatives       = MAX_ALT,
+       .add_fields             = 0x00111555ul,
+       .test_adder             = 0x00301000ul,
+       .compute_mmcr           = mpc7450_compute_mmcr,
+       .get_constraint         = mpc7450_get_constraint,
+       .get_alternatives       = mpc7450_get_alternatives,
+       .disable_pmc            = mpc7450_disable_pmc,
+       .n_generic              = ARRAY_SIZE(mpc7450_generic_events),
+       .generic_events         = mpc7450_generic_events,
+       .cache_events           = &mpc7450_cache_events,
+};
+
+static int __init init_mpc7450_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
+               return -ENODEV;
+
+       return register_power_pmu(&mpc7450_pmu);
+}
+
+early_initcall(init_mpc7450_pmu);
diff --git a/arch/powerpc/perf/power4-pmu.c b/arch/powerpc/perf/power4-pmu.c
new file mode 100644 (file)
index 0000000..b4f1dda
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
+ *
+ * Copyright 2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER4
+ */
+#define PM_PMC_SH      12      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0xf
+#define PM_UNIT_SH     8       /* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK    0xf
+#define PM_LOWER_SH    6
+#define PM_LOWER_MSK   1
+#define PM_LOWER_MSKS  0x40
+#define PM_BYTE_SH     4       /* Byte number of event bus to use */
+#define PM_BYTE_MSK    3
+#define PM_PMCSEL_MSK  7
+
+/*
+ * Unit code values
+ */
+#define PM_FPU         1
+#define PM_ISU1                2
+#define PM_IFU         3
+#define PM_IDU0                4
+#define PM_ISU1_ALT    6
+#define PM_ISU2                7
+#define PM_IFU_ALT     8
+#define PM_LSU0                9
+#define PM_LSU1                0xc
+#define PM_GPS         0xf
+
+/*
+ * Bits in MMCR0 for POWER4
+ */
+#define MMCR0_PMC1SEL_SH       8
+#define MMCR0_PMC2SEL_SH       1
+#define MMCR_PMCSEL_MSK                0x1f
+
+/*
+ * Bits in MMCR1 for POWER4
+ */
+#define MMCR1_TTM0SEL_SH       62
+#define MMCR1_TTC0SEL_SH       61
+#define MMCR1_TTM1SEL_SH       59
+#define MMCR1_TTC1SEL_SH       58
+#define MMCR1_TTM2SEL_SH       56
+#define MMCR1_TTC2SEL_SH       55
+#define MMCR1_TTM3SEL_SH       53
+#define MMCR1_TTC3SEL_SH       52
+#define MMCR1_TTMSEL_MSK       3
+#define MMCR1_TD_CP_DBG0SEL_SH 50
+#define MMCR1_TD_CP_DBG1SEL_SH 48
+#define MMCR1_TD_CP_DBG2SEL_SH 46
+#define MMCR1_TD_CP_DBG3SEL_SH 44
+#define MMCR1_DEBUG0SEL_SH     43
+#define MMCR1_DEBUG1SEL_SH     42
+#define MMCR1_DEBUG2SEL_SH     41
+#define MMCR1_DEBUG3SEL_SH     40
+#define MMCR1_PMC1_ADDER_SEL_SH        39
+#define MMCR1_PMC2_ADDER_SEL_SH        38
+#define MMCR1_PMC6_ADDER_SEL_SH        37
+#define MMCR1_PMC5_ADDER_SEL_SH        36
+#define MMCR1_PMC8_ADDER_SEL_SH        35
+#define MMCR1_PMC7_ADDER_SEL_SH        34
+#define MMCR1_PMC3_ADDER_SEL_SH        33
+#define MMCR1_PMC4_ADDER_SEL_SH        32
+#define MMCR1_PMC3SEL_SH       27
+#define MMCR1_PMC4SEL_SH       22
+#define MMCR1_PMC5SEL_SH       17
+#define MMCR1_PMC6SEL_SH       12
+#define MMCR1_PMC7SEL_SH       7
+#define MMCR1_PMC8SEL_SH       2       /* note bit 0 is in MMCRA for GP */
+
+static short mmcr1_adder_bits[8] = {
+       MMCR1_PMC1_ADDER_SEL_SH,
+       MMCR1_PMC2_ADDER_SEL_SH,
+       MMCR1_PMC3_ADDER_SEL_SH,
+       MMCR1_PMC4_ADDER_SEL_SH,
+       MMCR1_PMC5_ADDER_SEL_SH,
+       MMCR1_PMC6_ADDER_SEL_SH,
+       MMCR1_PMC7_ADDER_SEL_SH,
+       MMCR1_PMC8_ADDER_SEL_SH
+};
+
+/*
+ * Bits in MMCRA
+ */
+#define MMCRA_PMC8SEL0_SH      17      /* PMC8SEL bit 0 for GP */
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *        |[  >[  >[   >|||[  >[  ><  ><  ><  ><  ><><><><><><><><>
+ *        | UC1 UC2 UC3 ||| PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
+ *       \SMPL         ||\TTC3SEL
+ *                     |\TTC_IFU_SEL
+ *                     \TTM2SEL0
+ *
+ * SMPL - SAMPLE_ENABLE constraint
+ *     56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
+ *
+ * UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
+ *     55: UC1 error 0x0080_0000_0000_0000
+ *     54: FPU events needed 0x0040_0000_0000_0000
+ *     53: ISU1 events needed 0x0020_0000_0000_0000
+ *     52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
+ *
+ * UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
+ *     51: UC2 error 0x0008_0000_0000_0000
+ *     50: FPU events needed 0x0004_0000_0000_0000
+ *     49: IFU events needed 0x0002_0000_0000_0000
+ *     48: LSU0 events needed 0x0001_0000_0000_0000
+ *
+ * UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
+ *     47: UC3 error 0x8000_0000_0000
+ *     46: LSU0 events needed 0x4000_0000_0000
+ *     45: IFU events needed 0x2000_0000_0000
+ *     44: IDU0|ISU2 events needed 0x1000_0000_0000
+ *     43: ISU1 events needed 0x0800_0000_0000
+ *
+ * TTM2SEL0
+ *     42: 0 = IDU0 events needed
+ *                1 = ISU2 events needed 0x0400_0000_0000
+ *
+ * TTC_IFU_SEL
+ *     41: 0 = IFU.U events needed
+ *                1 = IFU.L events needed 0x0200_0000_0000
+ *
+ * TTC3SEL
+ *     40: 0 = LSU1.U events needed
+ *                1 = LSU1.L events needed 0x0100_0000_0000
+ *
+ * PS1
+ *     39: PS1 error 0x0080_0000_0000
+ *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
+ *
+ * PS2
+ *     35: PS2 error 0x0008_0000_0000
+ *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
+ *
+ * B0
+ *     28-31: Byte 0 event source 0xf000_0000
+ *                1 = FPU
+ *        2 = ISU1
+ *        3 = IFU
+ *        4 = IDU0
+ *        7 = ISU2
+ *        9 = LSU0
+ *        c = LSU1
+ *        f = GPS
+ *
+ * B1, B2, B3
+ *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
+ *
+ * P8
+ *     15: P8 error 0x8000
+ *     14-15: Count of events needing PMC8
+ *
+ * P1..P7
+ *     0-13: Count of events needing PMC1..PMC7
+ *
+ * Note: this doesn't allow events using IFU.U to be combined with events
+ * using IFU.L, though that is feasible (using TTM0 and TTM2).  However
+ * there are no listed events for IFU.L (they are debug events not
+ * verified for performance monitoring) so this shouldn't cause a
+ * problem.
+ */
+
+static struct unitinfo {
+       unsigned long   value, mask;
+       int             unit;
+       int             lowerbit;
+} p4_unitinfo[16] = {
+       [PM_FPU]  = { 0x44000000000000ul, 0x88000000000000ul, PM_FPU, 0 },
+       [PM_ISU1] = { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
+       [PM_ISU1_ALT] =
+                   { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
+       [PM_IFU]  = { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
+       [PM_IFU_ALT] =
+                   { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
+       [PM_IDU0] = { 0x10100000000000ul, 0x80840000000000ul, PM_IDU0, 1 },
+       [PM_ISU2] = { 0x10140000000000ul, 0x80840000000000ul, PM_ISU2, 0 },
+       [PM_LSU0] = { 0x01400000000000ul, 0x08800000000000ul, PM_LSU0, 0 },
+       [PM_LSU1] = { 0x00000000000000ul, 0x00010000000000ul, PM_LSU1, 40 },
+       [PM_GPS]  = { 0x00000000000000ul, 0x00000000000000ul, PM_GPS, 0 }
+};
+
+static unsigned char direct_marked_event[8] = {
+       (1<<2) | (1<<3),        /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
+       (1<<3) | (1<<5),        /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
+       (1<<3),                 /* PMC3: PM_MRK_ST_CMPL_INT */
+       (1<<4) | (1<<5),        /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
+       (1<<4) | (1<<5),        /* PMC5: PM_MRK_GRP_TIMEO */
+       (1<<3) | (1<<4) | (1<<5),
+               /* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
+       (1<<4) | (1<<5),        /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
+       (1<<4),                 /* PMC8: PM_MRK_LSU_FIN */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int p4_marked_instr_event(u64 event)
+{
+       int pmc, psel, unit, byte, bit;
+       unsigned int mask;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = event & PM_PMCSEL_MSK;
+       if (pmc) {
+               if (direct_marked_event[pmc - 1] & (1 << psel))
+                       return 1;
+               if (psel == 0)          /* add events */
+                       bit = (pmc <= 4)? pmc - 1: 8 - pmc;
+               else if (psel == 6)     /* decode events */
+                       bit = 4;
+               else
+                       return 0;
+       } else
+               bit = psel;
+
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       mask = 0;
+       switch (unit) {
+       case PM_LSU1:
+               if (event & PM_LOWER_MSKS)
+                       mask = 1 << 28;         /* byte 7 bit 4 */
+               else
+                       mask = 6 << 24;         /* byte 3 bits 1 and 2 */
+               break;
+       case PM_LSU0:
+               /* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
+               mask = 0x083dff00;
+       }
+       return (mask >> (byte * 8 + bit)) & 1;
+}
+
+static int p4_get_constraint(u64 event, unsigned long *maskp,
+                            unsigned long *valp)
+{
+       int pmc, byte, unit, lower, sh;
+       unsigned long mask = 0, value = 0;
+       int grp = -1;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 8)
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+               grp = ((pmc - 1) >> 1) & 1;
+       }
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       if (unit) {
+               lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
+
+               /*
+                * Bus events on bytes 0 and 2 can be counted
+                * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
+                */
+               if (!pmc)
+                       grp = byte & 1;
+
+               if (!p4_unitinfo[unit].unit)
+                       return -1;
+               mask  |= p4_unitinfo[unit].mask;
+               value |= p4_unitinfo[unit].value;
+               sh = p4_unitinfo[unit].lowerbit;
+               if (sh > 1)
+                       value |= (unsigned long)lower << sh;
+               else if (lower != sh)
+                       return -1;
+               unit = p4_unitinfo[unit].unit;
+
+               /* Set byte lane select field */
+               mask  |= 0xfULL << (28 - 4 * byte);
+               value |= (unsigned long)unit << (28 - 4 * byte);
+       }
+       if (grp == 0) {
+               /* increment PMC1/2/5/6 field */
+               mask  |= 0x8000000000ull;
+               value |= 0x1000000000ull;
+       } else {
+               /* increment PMC3/4/7/8 field */
+               mask  |= 0x800000000ull;
+               value |= 0x100000000ull;
+       }
+
+       /* Marked instruction events need sample_enable set */
+       if (p4_marked_instr_event(event)) {
+               mask  |= 1ull << 56;
+               value |= 1ull << 56;
+       }
+
+       /* PMCSEL=6 decode events on byte 2 need sample_enable clear */
+       if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
+               mask  |= 1ull << 56;
+
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+static unsigned int ppc_inst_cmpl[] = {
+       0x1001, 0x4001, 0x6001, 0x7001, 0x8001
+};
+
+static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, na;
+
+       alt[0] = event;
+       na = 1;
+
+       /* 2 possibilities for PM_GRP_DISP_REJECT */
+       if (event == 0x8003 || event == 0x0224) {
+               alt[1] = event ^ (0x8003 ^ 0x0224);
+               return 2;
+       }
+
+       /* 2 possibilities for PM_ST_MISS_L1 */
+       if (event == 0x0c13 || event == 0x0c23) {
+               alt[1] = event ^ (0x0c13 ^ 0x0c23);
+               return 2;
+       }
+
+       /* several possibilities for PM_INST_CMPL */
+       for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
+               if (event == ppc_inst_cmpl[i]) {
+                       for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
+                               if (j != i)
+                                       alt[na++] = ppc_inst_cmpl[j];
+                       break;
+               }
+       }
+
+       return na;
+}
+
+static int p4_compute_mmcr(u64 event[], int n_ev,
+                          unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
+       unsigned int pmc, unit, byte, psel, lower;
+       unsigned int ttm, grp;
+       unsigned int pmc_inuse = 0;
+       unsigned int pmc_grp_use[2];
+       unsigned char busbyte[4];
+       unsigned char unituse[16];
+       unsigned int unitlower = 0;
+       int i;
+
+       if (n_ev > 8)
+               return -1;
+
+       /* First pass to count resource use */
+       pmc_grp_use[0] = pmc_grp_use[1] = 0;
+       memset(busbyte, 0, sizeof(busbyte));
+       memset(unituse, 0, sizeof(unituse));
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;
+                       pmc_inuse |= 1 << (pmc - 1);
+                       /* count 1/2/5/6 vs 3/4/7/8 use */
+                       ++pmc_grp_use[((pmc - 1) >> 1) & 1];
+               }
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
+               if (unit) {
+                       if (!pmc)
+                               ++pmc_grp_use[byte & 1];
+                       if (unit == 6 || unit == 8)
+                               /* map alt ISU1/IFU codes: 6->2, 8->3 */
+                               unit = (unit >> 1) - 1;
+                       if (busbyte[byte] && busbyte[byte] != unit)
+                               return -1;
+                       busbyte[byte] = unit;
+                       lower <<= unit;
+                       if (unituse[unit] && lower != (unitlower & lower))
+                               return -1;
+                       unituse[unit] = 1;
+                       unitlower |= lower;
+               }
+       }
+       if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
+               return -1;
+
+       /*
+        * Assign resources and set multiplexer selects.
+        *
+        * Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
+        * Each TTMx can only select one unit, but since
+        * units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
+        * we have some choices.
+        */
+       if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
+               unituse[6] = 1;         /* Move 2 to 6 */
+               unituse[2] = 0;
+       }
+       if (unituse[3] & (unituse[1] | unituse[2])) {
+               unituse[8] = 1;         /* Move 3 to 8 */
+               unituse[3] = 0;
+               unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
+       }
+       /* Check only one unit per TTMx */
+       if (unituse[1] + unituse[2] + unituse[3] > 1 ||
+           unituse[4] + unituse[6] + unituse[7] > 1 ||
+           unituse[8] + unituse[9] > 1 ||
+           (unituse[5] | unituse[10] | unituse[11] |
+            unituse[13] | unituse[14]))
+               return -1;
+
+       /* Set TTMxSEL fields.  Note, units 1-3 => TTM0SEL codes 0-2 */
+       mmcr1 |= (unsigned long)(unituse[3] * 2 + unituse[2])
+               << MMCR1_TTM0SEL_SH;
+       mmcr1 |= (unsigned long)(unituse[7] * 3 + unituse[6] * 2)
+               << MMCR1_TTM1SEL_SH;
+       mmcr1 |= (unsigned long)unituse[9] << MMCR1_TTM2SEL_SH;
+
+       /* Set TTCxSEL fields. */
+       if (unitlower & 0xe)
+               mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
+       if (unitlower & 0xf0)
+               mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
+       if (unitlower & 0xf00)
+               mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
+       if (unitlower & 0x7000)
+               mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
+
+       /* Set byte lane select fields. */
+       for (byte = 0; byte < 4; ++byte) {
+               unit = busbyte[byte];
+               if (!unit)
+                       continue;
+               if (unit == 0xf) {
+                       /* special case for GPS */
+                       mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
+               } else {
+                       if (!unituse[unit])
+                               ttm = unit - 1;         /* 2->1, 3->2 */
+                       else
+                               ttm = unit >> 2;
+                       mmcr1 |= (unsigned long)ttm
+                               << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+               }
+       }
+
+       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               psel = event[i] & PM_PMCSEL_MSK;
+               if (!pmc) {
+                       /* Bus event or 00xxx direct event (off or cycles) */
+                       if (unit)
+                               psel |= 0x10 | ((byte & 2) << 2);
+                       for (pmc = 0; pmc < 8; ++pmc) {
+                               if (pmc_inuse & (1 << pmc))
+                                       continue;
+                               grp = (pmc >> 1) & 1;
+                               if (unit) {
+                                       if (grp == (byte & 1))
+                                               break;
+                               } else if (pmc_grp_use[grp] < 4) {
+                                       ++pmc_grp_use[grp];
+                                       break;
+                               }
+                       }
+                       pmc_inuse |= 1 << pmc;
+               } else {
+                       /* Direct event */
+                       --pmc;
+                       if (psel == 0 && (byte & 2))
+                               /* add events on higher-numbered bus */
+                               mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
+                       else if (psel == 6 && byte == 3)
+                               /* seem to need to set sample_enable here */
+                               mmcra |= MMCRA_SAMPLE_ENABLE;
+                       psel |= 8;
+               }
+               if (pmc <= 1)
+                       mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
+               else
+                       mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
+               if (pmc == 7)   /* PMC8 */
+                       mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
+               hwc[i] = pmc;
+               if (p4_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+       }
+
+       if (pmc_inuse & 1)
+               mmcr0 |= MMCR0_PMC1CE;
+       if (pmc_inuse & 0xfe)
+               mmcr0 |= MMCR0_PMCjCE;
+
+       mmcra |= 0x2000;        /* mark only one IOP per PPC instruction */
+
+       /* Return MMCRx values */
+       mmcr[0] = mmcr0;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+static void p4_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       /*
+        * Setting the PMCxSEL field to 0 disables PMC x.
+        * (Note that pmc is 0-based here, not 1-based.)
+        */
+       if (pmc <= 1) {
+               mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
+       } else {
+               mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
+               if (pmc == 7)
+                       mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
+       }
+}
+
+static int p4_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 7,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x1001,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x8c10, /* PM_LD_REF_L1 */
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c10, /* PM_LD_MISS_L1 */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x330,  /* PM_BR_ISSUED */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x331,  /* PM_BR_MPRED_CR */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x8c10,         0x3c10  },
+               [C(OP_WRITE)] = {       0x7c10,         0xc13   },
+               [C(OP_PREFETCH)] = {    0xc35,          0       },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       0,              0       },
+               [C(OP_PREFETCH)] = {    0xc34,          0       },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x904   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x900   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x330,          0x331   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+static struct power_pmu power4_pmu = {
+       .name                   = "POWER4/4+",
+       .n_counter              = 8,
+       .max_alternatives       = 5,
+       .add_fields             = 0x0000001100005555ul,
+       .test_adder             = 0x0011083300000000ul,
+       .compute_mmcr           = p4_compute_mmcr,
+       .get_constraint         = p4_get_constraint,
+       .get_alternatives       = p4_get_alternatives,
+       .disable_pmc            = p4_disable_pmc,
+       .n_generic              = ARRAY_SIZE(p4_generic_events),
+       .generic_events         = p4_generic_events,
+       .cache_events           = &power4_cache_events,
+};
+
+static int __init init_power4_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
+               return -ENODEV;
+
+       return register_power_pmu(&power4_pmu);
+}
+
+early_initcall(init_power4_pmu);
diff --git a/arch/powerpc/perf/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c
new file mode 100644 (file)
index 0000000..a8757ba
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Performance counter support for POWER5+/++ (not POWER5) processors.
+ *
+ * Copyright 2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
+ */
+#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0xf
+#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
+#define PM_UNIT_SH     16      /* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK    0xf
+#define PM_BYTE_SH     12      /* Byte number of event bus to use */
+#define PM_BYTE_MSK    7
+#define PM_GRS_SH      8       /* Storage subsystem mux select */
+#define PM_GRS_MSK     7
+#define PM_BUSEVENT_MSK        0x80    /* Set if event uses event bus */
+#define PM_PMCSEL_MSK  0x7f
+
+/* Values in PM_UNIT field */
+#define PM_FPU         0
+#define PM_ISU0                1
+#define PM_IFU         2
+#define PM_ISU1                3
+#define PM_IDU         4
+#define PM_ISU0_ALT    6
+#define PM_GRS         7
+#define PM_LSU0                8
+#define PM_LSU1                0xc
+#define PM_LASTUNIT    0xc
+
+/*
+ * Bits in MMCR1 for POWER5+
+ */
+#define MMCR1_TTM0SEL_SH       62
+#define MMCR1_TTM1SEL_SH       60
+#define MMCR1_TTM2SEL_SH       58
+#define MMCR1_TTM3SEL_SH       56
+#define MMCR1_TTMSEL_MSK       3
+#define MMCR1_TD_CP_DBG0SEL_SH 54
+#define MMCR1_TD_CP_DBG1SEL_SH 52
+#define MMCR1_TD_CP_DBG2SEL_SH 50
+#define MMCR1_TD_CP_DBG3SEL_SH 48
+#define MMCR1_GRS_L2SEL_SH     46
+#define MMCR1_GRS_L2SEL_MSK    3
+#define MMCR1_GRS_L3SEL_SH     44
+#define MMCR1_GRS_L3SEL_MSK    3
+#define MMCR1_GRS_MCSEL_SH     41
+#define MMCR1_GRS_MCSEL_MSK    7
+#define MMCR1_GRS_FABSEL_SH    39
+#define MMCR1_GRS_FABSEL_MSK   3
+#define MMCR1_PMC1_ADDER_SEL_SH        35
+#define MMCR1_PMC2_ADDER_SEL_SH        34
+#define MMCR1_PMC3_ADDER_SEL_SH        33
+#define MMCR1_PMC4_ADDER_SEL_SH        32
+#define MMCR1_PMC1SEL_SH       25
+#define MMCR1_PMC2SEL_SH       17
+#define MMCR1_PMC3SEL_SH       9
+#define MMCR1_PMC4SEL_SH       1
+#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
+#define MMCR1_PMCSEL_MSK       0x7f
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *             [  ><><>< ><> <><>[  >  <  ><  ><  ><  ><><><><><><>
+ *             NC  G0G1G2 G3 T0T1 UC    B0  B1  B2  B3 P6P5P4P3P2P1
+ *
+ * NC - number of counters
+ *     51: NC error 0x0008_0000_0000_0000
+ *     48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
+ *
+ * G0..G3 - GRS mux constraints
+ *     46-47: GRS_L2SEL value
+ *     44-45: GRS_L3SEL value
+ *     41-44: GRS_MCSEL value
+ *     39-40: GRS_FABSEL value
+ *     Note that these match up with their bit positions in MMCR1
+ *
+ * T0 - TTM0 constraint
+ *     36-37: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0x30_0000_0000
+ *
+ * T1 - TTM1 constraint
+ *     34-35: TTM1SEL value (0=IDU, 3=GRS) 0x0c_0000_0000
+ *
+ * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
+ *     33: UC3 error 0x02_0000_0000
+ *     32: FPU|IFU|ISU1 events needed 0x01_0000_0000
+ *     31: ISU0 events needed 0x01_8000_0000
+ *     30: IDU|GRS events needed 0x00_4000_0000
+ *
+ * B0
+ *     24-27: Byte 0 event source 0x0f00_0000
+ *           Encoding as for the event code
+ *
+ * B1, B2, B3
+ *     20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
+ *
+ * P6
+ *     11: P6 error 0x800
+ *     10-11: Count of events needing PMC6
+ *
+ * P1..P5
+ *     0-9: Count of events needing PMC1..PMC5
+ */
+
+static const int grsel_shift[8] = {
+       MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
+       MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
+       MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
+};
+
+/* Masks and values for using events from the various units */
+static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
+       [PM_FPU] =   { 0x3200000000ul, 0x0100000000ul },
+       [PM_ISU0] =  { 0x0200000000ul, 0x0080000000ul },
+       [PM_ISU1] =  { 0x3200000000ul, 0x3100000000ul },
+       [PM_IFU] =   { 0x3200000000ul, 0x2100000000ul },
+       [PM_IDU] =   { 0x0e00000000ul, 0x0040000000ul },
+       [PM_GRS] =   { 0x0e00000000ul, 0x0c40000000ul },
+};
+
+static int power5p_get_constraint(u64 event, unsigned long *maskp,
+                                 unsigned long *valp)
+{
+       int pmc, byte, unit, sh;
+       int bit, fmask;
+       unsigned long mask = 0, value = 0;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 6)
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+               if (pmc >= 5 && !(event == 0x500009 || event == 0x600005))
+                       return -1;
+       }
+       if (event & PM_BUSEVENT_MSK) {
+               unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+               if (unit > PM_LASTUNIT)
+                       return -1;
+               if (unit == PM_ISU0_ALT)
+                       unit = PM_ISU0;
+               mask |= unit_cons[unit][0];
+               value |= unit_cons[unit][1];
+               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+               if (byte >= 4) {
+                       if (unit != PM_LSU1)
+                               return -1;
+                       /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
+                       ++unit;
+                       byte &= 3;
+               }
+               if (unit == PM_GRS) {
+                       bit = event & 7;
+                       fmask = (bit == 6)? 7: 3;
+                       sh = grsel_shift[bit];
+                       mask |= (unsigned long)fmask << sh;
+                       value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
+                               << sh;
+               }
+               /* Set byte lane select field */
+               mask  |= 0xfUL << (24 - 4 * byte);
+               value |= (unsigned long)unit << (24 - 4 * byte);
+       }
+       if (pmc < 5) {
+               /* need a counter from PMC1-4 set */
+               mask  |= 0x8000000000000ul;
+               value |= 0x1000000000000ul;
+       }
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+static int power5p_limited_pmc_event(u64 event)
+{
+       int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+
+       return pmc == 5 || pmc == 6;
+}
+
+#define MAX_ALT        3       /* at most 3 alternatives for any event */
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+       { 0x100c0,  0x40001f },                 /* PM_GCT_FULL_CYC */
+       { 0x120e4,  0x400002 },                 /* PM_GRP_DISP_REJECT */
+       { 0x230e2,  0x323087 },                 /* PM_BR_PRED_CR */
+       { 0x230e3,  0x223087, 0x3230a0 },       /* PM_BR_PRED_TA */
+       { 0x410c7,  0x441084 },                 /* PM_THRD_L2MISS_BOTH_CYC */
+       { 0x800c4,  0xc20e0 },                  /* PM_DTLB_MISS */
+       { 0xc50c6,  0xc60e0 },                  /* PM_MRK_DTLB_MISS */
+       { 0x100005, 0x600005 },                 /* PM_RUN_CYC */
+       { 0x100009, 0x200009 },                 /* PM_INST_CMPL */
+       { 0x200015, 0x300015 },                 /* PM_LSU_LMQ_SRQ_EMPTY_CYC */
+       { 0x300009, 0x400009 },                 /* PM_INST_DISP */
+};
+
+/*
+ * Scan the alternatives table for a match and return the
+ * index into the alternatives table if found, else -1.
+ */
+static int find_alternative(unsigned int event)
+{
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+               if (event < event_alternatives[i][0])
+                       break;
+               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
+                       if (event == event_alternatives[i][j])
+                               return i;
+       }
+       return -1;
+}
+
+static const unsigned char bytedecode_alternatives[4][4] = {
+       /* PMC 1 */     { 0x21, 0x23, 0x25, 0x27 },
+       /* PMC 2 */     { 0x07, 0x17, 0x0e, 0x1e },
+       /* PMC 3 */     { 0x20, 0x22, 0x24, 0x26 },
+       /* PMC 4 */     { 0x07, 0x17, 0x0e, 0x1e }
+};
+
+/*
+ * Some direct events for decodes of event bus byte 3 have alternative
+ * PMCSEL values on other counters.  This returns the alternative
+ * event code for those that do, or -1 otherwise.  This also handles
+ * alternative PCMSEL values for add events.
+ */
+static s64 find_alternative_bdecode(u64 event)
+{
+       int pmc, altpmc, pp, j;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc == 0 || pmc > 4)
+               return -1;
+       altpmc = 5 - pmc;       /* 1 <-> 4, 2 <-> 3 */
+       pp = event & PM_PMCSEL_MSK;
+       for (j = 0; j < 4; ++j) {
+               if (bytedecode_alternatives[pmc - 1][j] == pp) {
+                       return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
+                               (altpmc << PM_PMC_SH) |
+                               bytedecode_alternatives[altpmc - 1][j];
+               }
+       }
+
+       /* new decode alternatives for power5+ */
+       if (pmc == 1 && (pp == 0x0d || pp == 0x0e))
+               return event + (2 << PM_PMC_SH) + (0x2e - 0x0d);
+       if (pmc == 3 && (pp == 0x2e || pp == 0x2f))
+               return event - (2 << PM_PMC_SH) - (0x2e - 0x0d);
+
+       /* alternative add event encodings */
+       if (pp == 0x10 || pp == 0x28)
+               return ((event ^ (0x10 ^ 0x28)) & ~PM_PMC_MSKS) |
+                       (altpmc << PM_PMC_SH);
+
+       return -1;
+}
+
+static int power5p_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, nalt = 1;
+       int nlim;
+       s64 ae;
+
+       alt[0] = event;
+       nalt = 1;
+       nlim = power5p_limited_pmc_event(event);
+       i = find_alternative(event);
+       if (i >= 0) {
+               for (j = 0; j < MAX_ALT; ++j) {
+                       ae = event_alternatives[i][j];
+                       if (ae && ae != event)
+                               alt[nalt++] = ae;
+                       nlim += power5p_limited_pmc_event(ae);
+               }
+       } else {
+               ae = find_alternative_bdecode(event);
+               if (ae > 0)
+                       alt[nalt++] = ae;
+       }
+
+       if (flags & PPMU_ONLY_COUNT_RUN) {
+               /*
+                * We're only counting in RUN state,
+                * so PM_CYC is equivalent to PM_RUN_CYC
+                * and PM_INST_CMPL === PM_RUN_INST_CMPL.
+                * This doesn't include alternatives that don't provide
+                * any extra flexibility in assigning PMCs (e.g.
+                * 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC).
+                * Note that even with these additional alternatives
+                * we never end up with more than 3 alternatives for any event.
+                */
+               j = nalt;
+               for (i = 0; i < nalt; ++i) {
+                       switch (alt[i]) {
+                       case 0xf:       /* PM_CYC */
+                               alt[j++] = 0x600005;    /* PM_RUN_CYC */
+                               ++nlim;
+                               break;
+                       case 0x600005:  /* PM_RUN_CYC */
+                               alt[j++] = 0xf;
+                               break;
+                       case 0x100009:  /* PM_INST_CMPL */
+                               alt[j++] = 0x500009;    /* PM_RUN_INST_CMPL */
+                               ++nlim;
+                               break;
+                       case 0x500009:  /* PM_RUN_INST_CMPL */
+                               alt[j++] = 0x100009;    /* PM_INST_CMPL */
+                               alt[j++] = 0x200009;
+                               break;
+                       }
+               }
+               nalt = j;
+       }
+
+       if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
+               /* remove the limited PMC events */
+               j = 0;
+               for (i = 0; i < nalt; ++i) {
+                       if (!power5p_limited_pmc_event(alt[i])) {
+                               alt[j] = alt[i];
+                               ++j;
+                       }
+               }
+               nalt = j;
+       } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
+               /* remove all but the limited PMC events */
+               j = 0;
+               for (i = 0; i < nalt; ++i) {
+                       if (power5p_limited_pmc_event(alt[i])) {
+                               alt[j] = alt[i];
+                               ++j;
+                       }
+               }
+               nalt = j;
+       }
+
+       return nalt;
+}
+
+/*
+ * Map of which direct events on which PMCs are marked instruction events.
+ * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
+ * Bit 0 is set if it is marked for all PMCs.
+ * The 0x80 bit indicates a byte decode PMCSEL value.
+ */
+static unsigned char direct_event_is_marked[0x28] = {
+       0,      /* 00 */
+       0x1f,   /* 01 PM_IOPS_CMPL */
+       0x2,    /* 02 PM_MRK_GRP_DISP */
+       0xe,    /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
+       0,      /* 04 */
+       0x1c,   /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
+       0x80,   /* 06 */
+       0x80,   /* 07 */
+       0, 0, 0,/* 08 - 0a */
+       0x18,   /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
+       0,      /* 0c */
+       0x80,   /* 0d */
+       0x80,   /* 0e */
+       0,      /* 0f */
+       0,      /* 10 */
+       0x14,   /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
+       0,      /* 12 */
+       0x10,   /* 13 PM_MRK_GRP_CMPL */
+       0x1f,   /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
+       0x2,    /* 15 PM_MRK_GRP_ISSUED */
+       0x80,   /* 16 */
+       0x80,   /* 17 */
+       0, 0, 0, 0, 0,
+       0x80,   /* 1d */
+       0x80,   /* 1e */
+       0,      /* 1f */
+       0x80,   /* 20 */
+       0x80,   /* 21 */
+       0x80,   /* 22 */
+       0x80,   /* 23 */
+       0x80,   /* 24 */
+       0x80,   /* 25 */
+       0x80,   /* 26 */
+       0x80,   /* 27 */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int power5p_marked_instr_event(u64 event)
+{
+       int pmc, psel;
+       int bit, byte, unit;
+       u32 mask;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = event & PM_PMCSEL_MSK;
+       if (pmc >= 5)
+               return 0;
+
+       bit = -1;
+       if (psel < sizeof(direct_event_is_marked)) {
+               if (direct_event_is_marked[psel] & (1 << pmc))
+                       return 1;
+               if (direct_event_is_marked[psel] & 0x80)
+                       bit = 4;
+               else if (psel == 0x08)
+                       bit = pmc - 1;
+               else if (psel == 0x10)
+                       bit = 4 - pmc;
+               else if (psel == 0x1b && (pmc == 1 || pmc == 3))
+                       bit = 4;
+       } else if ((psel & 0x48) == 0x40) {
+               bit = psel & 7;
+       } else if (psel == 0x28) {
+               bit = pmc - 1;
+       } else if (pmc == 3 && (psel == 0x2e || psel == 0x2f)) {
+               bit = 4;
+       }
+
+       if (!(event & PM_BUSEVENT_MSK) || bit == -1)
+               return 0;
+
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       if (unit == PM_LSU0) {
+               /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
+               mask = 0x5dff00;
+       } else if (unit == PM_LSU1 && byte >= 4) {
+               byte -= 4;
+               /* byte 5 bits 6-7, byte 6 bits 0,4, byte 7 bits 0-4,6 */
+               mask = 0x5f11c000;
+       } else
+               return 0;
+
+       return (mask >> (byte * 8 + bit)) & 1;
+}
+
+static int power5p_compute_mmcr(u64 event[], int n_ev,
+                               unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr1 = 0;
+       unsigned long mmcra = 0;
+       unsigned int pmc, unit, byte, psel;
+       unsigned int ttm;
+       int i, isbus, bit, grsel;
+       unsigned int pmc_inuse = 0;
+       unsigned char busbyte[4];
+       unsigned char unituse[16];
+       int ttmuse;
+
+       if (n_ev > 6)
+               return -1;
+
+       /* First pass to count resource use */
+       memset(busbyte, 0, sizeof(busbyte));
+       memset(unituse, 0, sizeof(unituse));
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc > 6)
+                               return -1;
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;
+                       pmc_inuse |= 1 << (pmc - 1);
+               }
+               if (event[i] & PM_BUSEVENT_MSK) {
+                       unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+                       byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+                       if (unit > PM_LASTUNIT)
+                               return -1;
+                       if (unit == PM_ISU0_ALT)
+                               unit = PM_ISU0;
+                       if (byte >= 4) {
+                               if (unit != PM_LSU1)
+                                       return -1;
+                               ++unit;
+                               byte &= 3;
+                       }
+                       if (busbyte[byte] && busbyte[byte] != unit)
+                               return -1;
+                       busbyte[byte] = unit;
+                       unituse[unit] = 1;
+               }
+       }
+
+       /*
+        * Assign resources and set multiplexer selects.
+        *
+        * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
+        * choice we have to deal with.
+        */
+       if (unituse[PM_ISU0] &
+           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
+               unituse[PM_ISU0_ALT] = 1;       /* move ISU to TTM1 */
+               unituse[PM_ISU0] = 0;
+       }
+       /* Set TTM[01]SEL fields. */
+       ttmuse = 0;
+       for (i = PM_FPU; i <= PM_ISU1; ++i) {
+               if (!unituse[i])
+                       continue;
+               if (ttmuse++)
+                       return -1;
+               mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
+       }
+       ttmuse = 0;
+       for (; i <= PM_GRS; ++i) {
+               if (!unituse[i])
+                       continue;
+               if (ttmuse++)
+                       return -1;
+               mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
+       }
+       if (ttmuse > 1)
+               return -1;
+
+       /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
+       for (byte = 0; byte < 4; ++byte) {
+               unit = busbyte[byte];
+               if (!unit)
+                       continue;
+               if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
+                       /* get ISU0 through TTM1 rather than TTM0 */
+                       unit = PM_ISU0_ALT;
+               } else if (unit == PM_LSU1 + 1) {
+                       /* select lower word of LSU1 for this byte */
+                       mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
+               }
+               ttm = unit >> 2;
+               mmcr1 |= (unsigned long)ttm
+                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+       }
+
+       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               psel = event[i] & PM_PMCSEL_MSK;
+               isbus = event[i] & PM_BUSEVENT_MSK;
+               if (!pmc) {
+                       /* Bus event or any-PMC direct event */
+                       for (pmc = 0; pmc < 4; ++pmc) {
+                               if (!(pmc_inuse & (1 << pmc)))
+                                       break;
+                       }
+                       if (pmc >= 4)
+                               return -1;
+                       pmc_inuse |= 1 << pmc;
+               } else if (pmc <= 4) {
+                       /* Direct event */
+                       --pmc;
+                       if (isbus && (byte & 2) &&
+                           (psel == 8 || psel == 0x10 || psel == 0x28))
+                               /* add events on higher-numbered bus */
+                               mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
+               } else {
+                       /* Instructions or run cycles on PMC5/6 */
+                       --pmc;
+               }
+               if (isbus && unit == PM_GRS) {
+                       bit = psel & 7;
+                       grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
+                       mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
+               }
+               if (power5p_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+               if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1))
+                       /* select alternate byte lane */
+                       psel |= 0x10;
+               if (pmc <= 3)
+                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
+               hwc[i] = pmc;
+       }
+
+       /* Return MMCRx values */
+       mmcr[0] = 0;
+       if (pmc_inuse & 1)
+               mmcr[0] = MMCR0_PMC1CE;
+       if (pmc_inuse & 0x3e)
+               mmcr[0] |= MMCR0_PMCjCE;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+static void power5p_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       if (pmc <= 3)
+               mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
+}
+
+static int power5p_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 0xf,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x100009,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x1c10a8, /* LD_REF_L1 */
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c1088, /* LD_MISS_L1 */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x230e4,  /* BR_ISSUED */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x230e5,  /* BR_MPRED_CR */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x1c10a8,       0x3c1088        },
+               [C(OP_WRITE)] = {       0x2c10a8,       0xc10c3         },
+               [C(OP_PREFETCH)] = {    0xc70e7,        -1              },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0               },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    0,              0               },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0               },
+               [C(OP_WRITE)] = {       0,              0               },
+               [C(OP_PREFETCH)] = {    0xc50c3,        0               },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0xc20e4,        0x800c4         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x800c0         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x230e4,        0x230e5         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1              },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+};
+
+static struct power_pmu power5p_pmu = {
+       .name                   = "POWER5+/++",
+       .n_counter              = 6,
+       .max_alternatives       = MAX_ALT,
+       .add_fields             = 0x7000000000055ul,
+       .test_adder             = 0x3000040000000ul,
+       .compute_mmcr           = power5p_compute_mmcr,
+       .get_constraint         = power5p_get_constraint,
+       .get_alternatives       = power5p_get_alternatives,
+       .disable_pmc            = power5p_disable_pmc,
+       .limited_pmc_event      = power5p_limited_pmc_event,
+       .flags                  = PPMU_LIMITED_PMC5_6,
+       .n_generic              = ARRAY_SIZE(power5p_generic_events),
+       .generic_events         = power5p_generic_events,
+       .cache_events           = &power5p_cache_events,
+};
+
+static int __init init_power5p_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+")
+            && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")))
+               return -ENODEV;
+
+       return register_power_pmu(&power5p_pmu);
+}
+
+early_initcall(init_power5p_pmu);
diff --git a/arch/powerpc/perf/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c
new file mode 100644 (file)
index 0000000..e7f06eb
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Performance counter support for POWER5 (not POWER5++) processors.
+ *
+ * Copyright 2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER5 (not POWER5++)
+ */
+#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0xf
+#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
+#define PM_UNIT_SH     16      /* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK    0xf
+#define PM_BYTE_SH     12      /* Byte number of event bus to use */
+#define PM_BYTE_MSK    7
+#define PM_GRS_SH      8       /* Storage subsystem mux select */
+#define PM_GRS_MSK     7
+#define PM_BUSEVENT_MSK        0x80    /* Set if event uses event bus */
+#define PM_PMCSEL_MSK  0x7f
+
+/* Values in PM_UNIT field */
+#define PM_FPU         0
+#define PM_ISU0                1
+#define PM_IFU         2
+#define PM_ISU1                3
+#define PM_IDU         4
+#define PM_ISU0_ALT    6
+#define PM_GRS         7
+#define PM_LSU0                8
+#define PM_LSU1                0xc
+#define PM_LASTUNIT    0xc
+
+/*
+ * Bits in MMCR1 for POWER5
+ */
+#define MMCR1_TTM0SEL_SH       62
+#define MMCR1_TTM1SEL_SH       60
+#define MMCR1_TTM2SEL_SH       58
+#define MMCR1_TTM3SEL_SH       56
+#define MMCR1_TTMSEL_MSK       3
+#define MMCR1_TD_CP_DBG0SEL_SH 54
+#define MMCR1_TD_CP_DBG1SEL_SH 52
+#define MMCR1_TD_CP_DBG2SEL_SH 50
+#define MMCR1_TD_CP_DBG3SEL_SH 48
+#define MMCR1_GRS_L2SEL_SH     46
+#define MMCR1_GRS_L2SEL_MSK    3
+#define MMCR1_GRS_L3SEL_SH     44
+#define MMCR1_GRS_L3SEL_MSK    3
+#define MMCR1_GRS_MCSEL_SH     41
+#define MMCR1_GRS_MCSEL_MSK    7
+#define MMCR1_GRS_FABSEL_SH    39
+#define MMCR1_GRS_FABSEL_MSK   3
+#define MMCR1_PMC1_ADDER_SEL_SH        35
+#define MMCR1_PMC2_ADDER_SEL_SH        34
+#define MMCR1_PMC3_ADDER_SEL_SH        33
+#define MMCR1_PMC4_ADDER_SEL_SH        32
+#define MMCR1_PMC1SEL_SH       25
+#define MMCR1_PMC2SEL_SH       17
+#define MMCR1_PMC3SEL_SH       9
+#define MMCR1_PMC4SEL_SH       1
+#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
+#define MMCR1_PMCSEL_MSK       0x7f
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *         <><>[  ><><>< ><> [  >[ >[ ><  ><  ><  ><  ><><><><><><>
+ *         T0T1 NC G0G1G2 G3  UC PS1PS2 B0  B1  B2  B3 P6P5P4P3P2P1
+ *
+ * T0 - TTM0 constraint
+ *     54-55: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0xc0_0000_0000_0000
+ *
+ * T1 - TTM1 constraint
+ *     52-53: TTM1SEL value (0=IDU, 3=GRS) 0x30_0000_0000_0000
+ *
+ * NC - number of counters
+ *     51: NC error 0x0008_0000_0000_0000
+ *     48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
+ *
+ * G0..G3 - GRS mux constraints
+ *     46-47: GRS_L2SEL value
+ *     44-45: GRS_L3SEL value
+ *     41-44: GRS_MCSEL value
+ *     39-40: GRS_FABSEL value
+ *     Note that these match up with their bit positions in MMCR1
+ *
+ * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
+ *     37: UC3 error 0x20_0000_0000
+ *     36: FPU|IFU|ISU1 events needed 0x10_0000_0000
+ *     35: ISU0 events needed 0x08_0000_0000
+ *     34: IDU|GRS events needed 0x04_0000_0000
+ *
+ * PS1
+ *     33: PS1 error 0x2_0000_0000
+ *     31-32: count of events needing PMC1/2 0x1_8000_0000
+ *
+ * PS2
+ *     30: PS2 error 0x4000_0000
+ *     28-29: count of events needing PMC3/4 0x3000_0000
+ *
+ * B0
+ *     24-27: Byte 0 event source 0x0f00_0000
+ *           Encoding as for the event code
+ *
+ * B1, B2, B3
+ *     20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
+ *
+ * P1..P6
+ *     0-11: Count of events needing PMC1..PMC6
+ */
+
+static const int grsel_shift[8] = {
+       MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
+       MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
+       MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
+};
+
+/* Masks and values for using events from the various units */
+static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
+       [PM_FPU] =   { 0xc0002000000000ul, 0x00001000000000ul },
+       [PM_ISU0] =  { 0x00002000000000ul, 0x00000800000000ul },
+       [PM_ISU1] =  { 0xc0002000000000ul, 0xc0001000000000ul },
+       [PM_IFU] =   { 0xc0002000000000ul, 0x80001000000000ul },
+       [PM_IDU] =   { 0x30002000000000ul, 0x00000400000000ul },
+       [PM_GRS] =   { 0x30002000000000ul, 0x30000400000000ul },
+};
+
+static int power5_get_constraint(u64 event, unsigned long *maskp,
+                                unsigned long *valp)
+{
+       int pmc, byte, unit, sh;
+       int bit, fmask;
+       unsigned long mask = 0, value = 0;
+       int grp = -1;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 6)
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+               if (pmc <= 4)
+                       grp = (pmc - 1) >> 1;
+               else if (event != 0x500009 && event != 0x600005)
+                       return -1;
+       }
+       if (event & PM_BUSEVENT_MSK) {
+               unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+               if (unit > PM_LASTUNIT)
+                       return -1;
+               if (unit == PM_ISU0_ALT)
+                       unit = PM_ISU0;
+               mask |= unit_cons[unit][0];
+               value |= unit_cons[unit][1];
+               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+               if (byte >= 4) {
+                       if (unit != PM_LSU1)
+                               return -1;
+                       /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
+                       ++unit;
+                       byte &= 3;
+               }
+               if (unit == PM_GRS) {
+                       bit = event & 7;
+                       fmask = (bit == 6)? 7: 3;
+                       sh = grsel_shift[bit];
+                       mask |= (unsigned long)fmask << sh;
+                       value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
+                               << sh;
+               }
+               /*
+                * Bus events on bytes 0 and 2 can be counted
+                * on PMC1/2; bytes 1 and 3 on PMC3/4.
+                */
+               if (!pmc)
+                       grp = byte & 1;
+               /* Set byte lane select field */
+               mask  |= 0xfUL << (24 - 4 * byte);
+               value |= (unsigned long)unit << (24 - 4 * byte);
+       }
+       if (grp == 0) {
+               /* increment PMC1/2 field */
+               mask  |= 0x200000000ul;
+               value |= 0x080000000ul;
+       } else if (grp == 1) {
+               /* increment PMC3/4 field */
+               mask  |= 0x40000000ul;
+               value |= 0x10000000ul;
+       }
+       if (pmc < 5) {
+               /* need a counter from PMC1-4 set */
+               mask  |= 0x8000000000000ul;
+               value |= 0x1000000000000ul;
+       }
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+#define MAX_ALT        3       /* at most 3 alternatives for any event */
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+       { 0x120e4,  0x400002 },                 /* PM_GRP_DISP_REJECT */
+       { 0x410c7,  0x441084 },                 /* PM_THRD_L2MISS_BOTH_CYC */
+       { 0x100005, 0x600005 },                 /* PM_RUN_CYC */
+       { 0x100009, 0x200009, 0x500009 },       /* PM_INST_CMPL */
+       { 0x300009, 0x400009 },                 /* PM_INST_DISP */
+};
+
+/*
+ * Scan the alternatives table for a match and return the
+ * index into the alternatives table if found, else -1.
+ */
+static int find_alternative(u64 event)
+{
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+               if (event < event_alternatives[i][0])
+                       break;
+               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
+                       if (event == event_alternatives[i][j])
+                               return i;
+       }
+       return -1;
+}
+
+static const unsigned char bytedecode_alternatives[4][4] = {
+       /* PMC 1 */     { 0x21, 0x23, 0x25, 0x27 },
+       /* PMC 2 */     { 0x07, 0x17, 0x0e, 0x1e },
+       /* PMC 3 */     { 0x20, 0x22, 0x24, 0x26 },
+       /* PMC 4 */     { 0x07, 0x17, 0x0e, 0x1e }
+};
+
+/*
+ * Some direct events for decodes of event bus byte 3 have alternative
+ * PMCSEL values on other counters.  This returns the alternative
+ * event code for those that do, or -1 otherwise.
+ */
+static s64 find_alternative_bdecode(u64 event)
+{
+       int pmc, altpmc, pp, j;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc == 0 || pmc > 4)
+               return -1;
+       altpmc = 5 - pmc;       /* 1 <-> 4, 2 <-> 3 */
+       pp = event & PM_PMCSEL_MSK;
+       for (j = 0; j < 4; ++j) {
+               if (bytedecode_alternatives[pmc - 1][j] == pp) {
+                       return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
+                               (altpmc << PM_PMC_SH) |
+                               bytedecode_alternatives[altpmc - 1][j];
+               }
+       }
+       return -1;
+}
+
+static int power5_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, nalt = 1;
+       s64 ae;
+
+       alt[0] = event;
+       nalt = 1;
+       i = find_alternative(event);
+       if (i >= 0) {
+               for (j = 0; j < MAX_ALT; ++j) {
+                       ae = event_alternatives[i][j];
+                       if (ae && ae != event)
+                               alt[nalt++] = ae;
+               }
+       } else {
+               ae = find_alternative_bdecode(event);
+               if (ae > 0)
+                       alt[nalt++] = ae;
+       }
+       return nalt;
+}
+
+/*
+ * Map of which direct events on which PMCs are marked instruction events.
+ * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
+ * Bit 0 is set if it is marked for all PMCs.
+ * The 0x80 bit indicates a byte decode PMCSEL value.
+ */
+static unsigned char direct_event_is_marked[0x28] = {
+       0,      /* 00 */
+       0x1f,   /* 01 PM_IOPS_CMPL */
+       0x2,    /* 02 PM_MRK_GRP_DISP */
+       0xe,    /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
+       0,      /* 04 */
+       0x1c,   /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
+       0x80,   /* 06 */
+       0x80,   /* 07 */
+       0, 0, 0,/* 08 - 0a */
+       0x18,   /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
+       0,      /* 0c */
+       0x80,   /* 0d */
+       0x80,   /* 0e */
+       0,      /* 0f */
+       0,      /* 10 */
+       0x14,   /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
+       0,      /* 12 */
+       0x10,   /* 13 PM_MRK_GRP_CMPL */
+       0x1f,   /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
+       0x2,    /* 15 PM_MRK_GRP_ISSUED */
+       0x80,   /* 16 */
+       0x80,   /* 17 */
+       0, 0, 0, 0, 0,
+       0x80,   /* 1d */
+       0x80,   /* 1e */
+       0,      /* 1f */
+       0x80,   /* 20 */
+       0x80,   /* 21 */
+       0x80,   /* 22 */
+       0x80,   /* 23 */
+       0x80,   /* 24 */
+       0x80,   /* 25 */
+       0x80,   /* 26 */
+       0x80,   /* 27 */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int power5_marked_instr_event(u64 event)
+{
+       int pmc, psel;
+       int bit, byte, unit;
+       u32 mask;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = event & PM_PMCSEL_MSK;
+       if (pmc >= 5)
+               return 0;
+
+       bit = -1;
+       if (psel < sizeof(direct_event_is_marked)) {
+               if (direct_event_is_marked[psel] & (1 << pmc))
+                       return 1;
+               if (direct_event_is_marked[psel] & 0x80)
+                       bit = 4;
+               else if (psel == 0x08)
+                       bit = pmc - 1;
+               else if (psel == 0x10)
+                       bit = 4 - pmc;
+               else if (psel == 0x1b && (pmc == 1 || pmc == 3))
+                       bit = 4;
+       } else if ((psel & 0x58) == 0x40)
+               bit = psel & 7;
+
+       if (!(event & PM_BUSEVENT_MSK))
+               return 0;
+
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       if (unit == PM_LSU0) {
+               /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
+               mask = 0x5dff00;
+       } else if (unit == PM_LSU1 && byte >= 4) {
+               byte -= 4;
+               /* byte 4 bits 1,3,5,7, byte 5 bits 6-7, byte 7 bits 0-4,6 */
+               mask = 0x5f00c0aa;
+       } else
+               return 0;
+
+       return (mask >> (byte * 8 + bit)) & 1;
+}
+
+static int power5_compute_mmcr(u64 event[], int n_ev,
+                              unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr1 = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
+       unsigned int pmc, unit, byte, psel;
+       unsigned int ttm, grp;
+       int i, isbus, bit, grsel;
+       unsigned int pmc_inuse = 0;
+       unsigned int pmc_grp_use[2];
+       unsigned char busbyte[4];
+       unsigned char unituse[16];
+       int ttmuse;
+
+       if (n_ev > 6)
+               return -1;
+
+       /* First pass to count resource use */
+       pmc_grp_use[0] = pmc_grp_use[1] = 0;
+       memset(busbyte, 0, sizeof(busbyte));
+       memset(unituse, 0, sizeof(unituse));
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc > 6)
+                               return -1;
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;
+                       pmc_inuse |= 1 << (pmc - 1);
+                       /* count 1/2 vs 3/4 use */
+                       if (pmc <= 4)
+                               ++pmc_grp_use[(pmc - 1) >> 1];
+               }
+               if (event[i] & PM_BUSEVENT_MSK) {
+                       unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+                       byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+                       if (unit > PM_LASTUNIT)
+                               return -1;
+                       if (unit == PM_ISU0_ALT)
+                               unit = PM_ISU0;
+                       if (byte >= 4) {
+                               if (unit != PM_LSU1)
+                                       return -1;
+                               ++unit;
+                               byte &= 3;
+                       }
+                       if (!pmc)
+                               ++pmc_grp_use[byte & 1];
+                       if (busbyte[byte] && busbyte[byte] != unit)
+                               return -1;
+                       busbyte[byte] = unit;
+                       unituse[unit] = 1;
+               }
+       }
+       if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2)
+               return -1;
+
+       /*
+        * Assign resources and set multiplexer selects.
+        *
+        * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
+        * choice we have to deal with.
+        */
+       if (unituse[PM_ISU0] &
+           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
+               unituse[PM_ISU0_ALT] = 1;       /* move ISU to TTM1 */
+               unituse[PM_ISU0] = 0;
+       }
+       /* Set TTM[01]SEL fields. */
+       ttmuse = 0;
+       for (i = PM_FPU; i <= PM_ISU1; ++i) {
+               if (!unituse[i])
+                       continue;
+               if (ttmuse++)
+                       return -1;
+               mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
+       }
+       ttmuse = 0;
+       for (; i <= PM_GRS; ++i) {
+               if (!unituse[i])
+                       continue;
+               if (ttmuse++)
+                       return -1;
+               mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
+       }
+       if (ttmuse > 1)
+               return -1;
+
+       /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
+       for (byte = 0; byte < 4; ++byte) {
+               unit = busbyte[byte];
+               if (!unit)
+                       continue;
+               if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
+                       /* get ISU0 through TTM1 rather than TTM0 */
+                       unit = PM_ISU0_ALT;
+               } else if (unit == PM_LSU1 + 1) {
+                       /* select lower word of LSU1 for this byte */
+                       mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
+               }
+               ttm = unit >> 2;
+               mmcr1 |= (unsigned long)ttm
+                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+       }
+
+       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               psel = event[i] & PM_PMCSEL_MSK;
+               isbus = event[i] & PM_BUSEVENT_MSK;
+               if (!pmc) {
+                       /* Bus event or any-PMC direct event */
+                       for (pmc = 0; pmc < 4; ++pmc) {
+                               if (pmc_inuse & (1 << pmc))
+                                       continue;
+                               grp = (pmc >> 1) & 1;
+                               if (isbus) {
+                                       if (grp == (byte & 1))
+                                               break;
+                               } else if (pmc_grp_use[grp] < 2) {
+                                       ++pmc_grp_use[grp];
+                                       break;
+                               }
+                       }
+                       pmc_inuse |= 1 << pmc;
+               } else if (pmc <= 4) {
+                       /* Direct event */
+                       --pmc;
+                       if ((psel == 8 || psel == 0x10) && isbus && (byte & 2))
+                               /* add events on higher-numbered bus */
+                               mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
+               } else {
+                       /* Instructions or run cycles on PMC5/6 */
+                       --pmc;
+               }
+               if (isbus && unit == PM_GRS) {
+                       bit = psel & 7;
+                       grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
+                       mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
+               }
+               if (power5_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+               if (pmc <= 3)
+                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
+               hwc[i] = pmc;
+       }
+
+       /* Return MMCRx values */
+       mmcr[0] = 0;
+       if (pmc_inuse & 1)
+               mmcr[0] = MMCR0_PMC1CE;
+       if (pmc_inuse & 0x3e)
+               mmcr[0] |= MMCR0_PMCjCE;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+static void power5_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       if (pmc <= 3)
+               mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
+}
+
+static int power5_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 0xf,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x100009,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x4c1090, /* LD_REF_L1 */
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3c1088, /* LD_MISS_L1 */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x230e4,  /* BR_ISSUED */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x230e5,  /* BR_MPRED_CR */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x4c1090,       0x3c1088        },
+               [C(OP_WRITE)] = {       0x3c1090,       0xc10c3         },
+               [C(OP_PREFETCH)] = {    0xc70e7,        0               },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0               },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    0,              0               },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x3c309b        },
+               [C(OP_WRITE)] = {       0,              0               },
+               [C(OP_PREFETCH)] = {    0xc50c3,        0               },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x2c4090,       0x800c4         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x800c0         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x230e4,        0x230e5         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1              },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+};
+
+static struct power_pmu power5_pmu = {
+       .name                   = "POWER5",
+       .n_counter              = 6,
+       .max_alternatives       = MAX_ALT,
+       .add_fields             = 0x7000090000555ul,
+       .test_adder             = 0x3000490000000ul,
+       .compute_mmcr           = power5_compute_mmcr,
+       .get_constraint         = power5_get_constraint,
+       .get_alternatives       = power5_get_alternatives,
+       .disable_pmc            = power5_disable_pmc,
+       .n_generic              = ARRAY_SIZE(power5_generic_events),
+       .generic_events         = power5_generic_events,
+       .cache_events           = &power5_cache_events,
+};
+
+static int __init init_power5_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
+               return -ENODEV;
+
+       return register_power_pmu(&power5_pmu);
+}
+
+early_initcall(init_power5_pmu);
diff --git a/arch/powerpc/perf/power6-pmu.c b/arch/powerpc/perf/power6-pmu.c
new file mode 100644 (file)
index 0000000..31128e0
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Performance counter support for POWER6 processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER6
+ */
+#define PM_PMC_SH      20      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0x7
+#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
+#define PM_UNIT_SH     16      /* Unit event comes (TTMxSEL encoding) */
+#define PM_UNIT_MSK    0xf
+#define PM_UNIT_MSKS   (PM_UNIT_MSK << PM_UNIT_SH)
+#define PM_LLAV                0x8000  /* Load lookahead match value */
+#define PM_LLA         0x4000  /* Load lookahead match enable */
+#define PM_BYTE_SH     12      /* Byte of event bus to use */
+#define PM_BYTE_MSK    3
+#define PM_SUBUNIT_SH  8       /* Subunit event comes from (NEST_SEL enc.) */
+#define PM_SUBUNIT_MSK 7
+#define PM_SUBUNIT_MSKS        (PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
+#define PM_PMCSEL_MSK  0xff    /* PMCxSEL value */
+#define PM_BUSEVENT_MSK        0xf3700
+
+/*
+ * Bits in MMCR1 for POWER6
+ */
+#define MMCR1_TTM0SEL_SH       60
+#define MMCR1_TTMSEL_SH(n)     (MMCR1_TTM0SEL_SH - (n) * 4)
+#define MMCR1_TTMSEL_MSK       0xf
+#define MMCR1_TTMSEL(m, n)     (((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
+#define MMCR1_NESTSEL_SH       45
+#define MMCR1_NESTSEL_MSK      0x7
+#define MMCR1_NESTSEL(m)       (((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
+#define MMCR1_PMC1_LLA         (1ul << 44)
+#define MMCR1_PMC1_LLA_VALUE   (1ul << 39)
+#define MMCR1_PMC1_ADDR_SEL    (1ul << 35)
+#define MMCR1_PMC1SEL_SH       24
+#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
+#define MMCR1_PMCSEL_MSK       0xff
+
+/*
+ * Map of which direct events on which PMCs are marked instruction events.
+ * Indexed by PMCSEL value >> 1.
+ * Bottom 4 bits are a map of which PMCs are interesting,
+ * top 4 bits say what sort of event:
+ *   0 = direct marked event,
+ *   1 = byte decode event,
+ *   4 = add/and event (PMC1 -> bits 0 & 4),
+ *   5 = add/and event (PMC1 -> bits 1 & 5),
+ *   6 = add/and event (PMC1 -> bits 2 & 6),
+ *   7 = add/and event (PMC1 -> bits 3 & 7).
+ */
+static unsigned char direct_event_is_marked[0x60 >> 1] = {
+       0,      /* 00 */
+       0,      /* 02 */
+       0,      /* 04 */
+       0x07,   /* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
+       0x04,   /* 08 PM_MRK_DFU_FIN */
+       0x06,   /* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
+       0,      /* 0c */
+       0,      /* 0e */
+       0x02,   /* 10 PM_MRK_INST_DISP */
+       0x08,   /* 12 PM_MRK_LSU_DERAT_MISS */
+       0,      /* 14 */
+       0,      /* 16 */
+       0x0c,   /* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
+       0x0f,   /* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
+       0x01,   /* 1c PM_MRK_INST_ISSUED */
+       0,      /* 1e */
+       0,      /* 20 */
+       0,      /* 22 */
+       0,      /* 24 */
+       0,      /* 26 */
+       0x15,   /* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
+       0,      /* 2a */
+       0,      /* 2c */
+       0,      /* 2e */
+       0x4f,   /* 30 */
+       0x7f,   /* 32 */
+       0x4f,   /* 34 */
+       0x5f,   /* 36 */
+       0x6f,   /* 38 */
+       0x4f,   /* 3a */
+       0,      /* 3c */
+       0x08,   /* 3e PM_MRK_INST_TIMEO */
+       0x1f,   /* 40 */
+       0x1f,   /* 42 */
+       0x1f,   /* 44 */
+       0x1f,   /* 46 */
+       0x1f,   /* 48 */
+       0x1f,   /* 4a */
+       0x1f,   /* 4c */
+       0x1f,   /* 4e */
+       0,      /* 50 */
+       0x05,   /* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
+       0x1c,   /* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
+       0x02,   /* 56 PM_MRK_LD_MISS_L1 */
+       0,      /* 58 */
+       0,      /* 5a */
+       0,      /* 5c */
+       0,      /* 5e */
+};
+
+/*
+ * Masks showing for each unit which bits are marked events.
+ * These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
+ */
+static u32 marked_bus_events[16] = {
+       0x01000000,     /* direct events set 1: byte 3 bit 0 */
+       0x00010000,     /* direct events set 2: byte 2 bit 0 */
+       0, 0, 0, 0,     /* IDU, IFU, nest: nothing */
+       0x00000088,     /* VMX set 1: byte 0 bits 3, 7 */
+       0x000000c0,     /* VMX set 2: byte 0 bits 4-7 */
+       0x04010000,     /* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
+       0xff010000u,    /* LSU set 2: byte 2 bit 0, all of byte 3 */
+       0,              /* LSU set 3 */
+       0x00000010,     /* VMX set 3: byte 0 bit 4 */
+       0,              /* BFP set 1 */
+       0x00000022,     /* BFP set 2: byte 0 bits 1, 5 */
+       0, 0
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int power6_marked_instr_event(u64 event)
+{
+       int pmc, psel, ptype;
+       int bit, byte, unit;
+       u32 mask;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = (event & PM_PMCSEL_MSK) >> 1;    /* drop edge/level bit */
+       if (pmc >= 5)
+               return 0;
+
+       bit = -1;
+       if (psel < sizeof(direct_event_is_marked)) {
+               ptype = direct_event_is_marked[psel];
+               if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
+                       return 0;
+               ptype >>= 4;
+               if (ptype == 0)
+                       return 1;
+               if (ptype == 1)
+                       bit = 0;
+               else
+                       bit = ptype ^ (pmc - 1);
+       } else if ((psel & 0x48) == 0x40)
+               bit = psel & 7;
+
+       if (!(event & PM_BUSEVENT_MSK) || bit == -1)
+               return 0;
+
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       mask = marked_bus_events[unit];
+       return (mask >> (byte * 8 + bit)) & 1;
+}
+
+/*
+ * Assign PMC numbers and compute MMCR1 value for a set of events
+ */
+static int p6_compute_mmcr(u64 event[], int n_ev,
+                          unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr1 = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
+       int i;
+       unsigned int pmc, ev, b, u, s, psel;
+       unsigned int ttmset = 0;
+       unsigned int pmc_inuse = 0;
+
+       if (n_ev > 6)
+               return -1;
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;      /* collision! */
+                       pmc_inuse |= 1 << (pmc - 1);
+               }
+       }
+       for (i = 0; i < n_ev; ++i) {
+               ev = event[i];
+               pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       --pmc;
+               } else {
+                       /* can go on any PMC; find a free one */
+                       for (pmc = 0; pmc < 4; ++pmc)
+                               if (!(pmc_inuse & (1 << pmc)))
+                                       break;
+                       if (pmc >= 4)
+                               return -1;
+                       pmc_inuse |= 1 << pmc;
+               }
+               hwc[i] = pmc;
+               psel = ev & PM_PMCSEL_MSK;
+               if (ev & PM_BUSEVENT_MSK) {
+                       /* this event uses the event bus */
+                       b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
+                       u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
+                       /* check for conflict on this byte of event bus */
+                       if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
+                               return -1;
+                       mmcr1 |= (unsigned long)u << MMCR1_TTMSEL_SH(b);
+                       ttmset |= 1 << b;
+                       if (u == 5) {
+                               /* Nest events have a further mux */
+                               s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
+                               if ((ttmset & 0x10) &&
+                                   MMCR1_NESTSEL(mmcr1) != s)
+                                       return -1;
+                               ttmset |= 0x10;
+                               mmcr1 |= (unsigned long)s << MMCR1_NESTSEL_SH;
+                       }
+                       if (0x30 <= psel && psel <= 0x3d) {
+                               /* these need the PMCx_ADDR_SEL bits */
+                               if (b >= 2)
+                                       mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
+                       }
+                       /* bus select values are different for PMC3/4 */
+                       if (pmc >= 2 && (psel & 0x90) == 0x80)
+                               psel ^= 0x20;
+               }
+               if (ev & PM_LLA) {
+                       mmcr1 |= MMCR1_PMC1_LLA >> pmc;
+                       if (ev & PM_LLAV)
+                               mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
+               }
+               if (power6_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+               if (pmc < 4)
+                       mmcr1 |= (unsigned long)psel << MMCR1_PMCSEL_SH(pmc);
+       }
+       mmcr[0] = 0;
+       if (pmc_inuse & 1)
+               mmcr[0] = MMCR0_PMC1CE;
+       if (pmc_inuse & 0xe)
+               mmcr[0] |= MMCR0_PMCjCE;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+/*
+ * Layout of constraint bits:
+ *
+ *     0-1     add field: number of uses of PMC1 (max 1)
+ *     2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
+ *     12-15   add field: number of uses of PMC1-4 (max 4)
+ *     16-19   select field: unit on byte 0 of event bus
+ *     20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
+ *     32-34   select field: nest (subunit) event selector
+ */
+static int p6_get_constraint(u64 event, unsigned long *maskp,
+                            unsigned long *valp)
+{
+       int pmc, byte, sh, subunit;
+       unsigned long mask = 0, value = 0;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+       }
+       if (event & PM_BUSEVENT_MSK) {
+               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+               sh = byte * 4 + (16 - PM_UNIT_SH);
+               mask |= PM_UNIT_MSKS << sh;
+               value |= (unsigned long)(event & PM_UNIT_MSKS) << sh;
+               if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
+                       subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
+                       mask  |= (unsigned long)PM_SUBUNIT_MSK << 32;
+                       value |= (unsigned long)subunit << 32;
+               }
+       }
+       if (pmc <= 4) {
+               mask  |= 0x8000;        /* add field for count of PMC1-4 uses */
+               value |= 0x1000;
+       }
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+static int p6_limited_pmc_event(u64 event)
+{
+       int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+
+       return pmc == 5 || pmc == 6;
+}
+
+#define MAX_ALT        4       /* at most 4 alternatives for any event */
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+       { 0x0130e8, 0x2000f6, 0x3000fc },       /* PM_PTEG_RELOAD_VALID */
+       { 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
+       { 0x080088, 0x200054, 0x3000f0 },       /* PM_ST_MISS_L1 */
+       { 0x10000a, 0x2000f4, 0x600005 },       /* PM_RUN_CYC */
+       { 0x10000b, 0x2000f5 },                 /* PM_RUN_COUNT */
+       { 0x10000e, 0x400010 },                 /* PM_PURR */
+       { 0x100010, 0x4000f8 },                 /* PM_FLUSH */
+       { 0x10001a, 0x200010 },                 /* PM_MRK_INST_DISP */
+       { 0x100026, 0x3000f8 },                 /* PM_TB_BIT_TRANS */
+       { 0x100054, 0x2000f0 },                 /* PM_ST_FIN */
+       { 0x100056, 0x2000fc },                 /* PM_L1_ICACHE_MISS */
+       { 0x1000f0, 0x40000a },                 /* PM_INST_IMC_MATCH_CMPL */
+       { 0x1000f8, 0x200008 },                 /* PM_GCT_EMPTY_CYC */
+       { 0x1000fc, 0x400006 },                 /* PM_LSU_DERAT_MISS_CYC */
+       { 0x20000e, 0x400007 },                 /* PM_LSU_DERAT_MISS */
+       { 0x200012, 0x300012 },                 /* PM_INST_DISP */
+       { 0x2000f2, 0x3000f2 },                 /* PM_INST_DISP */
+       { 0x2000f8, 0x300010 },                 /* PM_EXT_INT */
+       { 0x2000fe, 0x300056 },                 /* PM_DATA_FROM_L2MISS */
+       { 0x2d0030, 0x30001a },                 /* PM_MRK_FPU_FIN */
+       { 0x30000a, 0x400018 },                 /* PM_MRK_INST_FIN */
+       { 0x3000f6, 0x40000e },                 /* PM_L1_DCACHE_RELOAD_VALID */
+       { 0x3000fe, 0x400056 },                 /* PM_DATA_FROM_L3MISS */
+};
+
+/*
+ * This could be made more efficient with a binary search on
+ * a presorted list, if necessary
+ */
+static int find_alternatives_list(u64 event)
+{
+       int i, j;
+       unsigned int alt;
+
+       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+               if (event < event_alternatives[i][0])
+                       return -1;
+               for (j = 0; j < MAX_ALT; ++j) {
+                       alt = event_alternatives[i][j];
+                       if (!alt || event < alt)
+                               break;
+                       if (event == alt)
+                               return i;
+               }
+       }
+       return -1;
+}
+
+static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, nlim;
+       unsigned int psel, pmc;
+       unsigned int nalt = 1;
+       u64 aevent;
+
+       alt[0] = event;
+       nlim = p6_limited_pmc_event(event);
+
+       /* check the alternatives table */
+       i = find_alternatives_list(event);
+       if (i >= 0) {
+               /* copy out alternatives from list */
+               for (j = 0; j < MAX_ALT; ++j) {
+                       aevent = event_alternatives[i][j];
+                       if (!aevent)
+                               break;
+                       if (aevent != event)
+                               alt[nalt++] = aevent;
+                       nlim += p6_limited_pmc_event(aevent);
+               }
+
+       } else {
+               /* Check for alternative ways of computing sum events */
+               /* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
+               psel = event & (PM_PMCSEL_MSK & ~1);    /* ignore edge bit */
+               pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc && (psel == 0x32 || psel == 0x34))
+                       alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
+                               ((5 - pmc) << PM_PMC_SH);
+
+               /* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
+               if (pmc && (psel == 0x38 || psel == 0x3a))
+                       alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
+                               ((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
+       }
+
+       if (flags & PPMU_ONLY_COUNT_RUN) {
+               /*
+                * We're only counting in RUN state,
+                * so PM_CYC is equivalent to PM_RUN_CYC,
+                * PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
+                * This doesn't include alternatives that don't provide
+                * any extra flexibility in assigning PMCs (e.g.
+                * 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
+                * Note that even with these additional alternatives
+                * we never end up with more than 4 alternatives for any event.
+                */
+               j = nalt;
+               for (i = 0; i < nalt; ++i) {
+                       switch (alt[i]) {
+                       case 0x1e:      /* PM_CYC */
+                               alt[j++] = 0x600005;    /* PM_RUN_CYC */
+                               ++nlim;
+                               break;
+                       case 0x10000a:  /* PM_RUN_CYC */
+                               alt[j++] = 0x1e;        /* PM_CYC */
+                               break;
+                       case 2:         /* PM_INST_CMPL */
+                               alt[j++] = 0x500009;    /* PM_RUN_INST_CMPL */
+                               ++nlim;
+                               break;
+                       case 0x500009:  /* PM_RUN_INST_CMPL */
+                               alt[j++] = 2;           /* PM_INST_CMPL */
+                               break;
+                       case 0x10000e:  /* PM_PURR */
+                               alt[j++] = 0x4000f4;    /* PM_RUN_PURR */
+                               break;
+                       case 0x4000f4:  /* PM_RUN_PURR */
+                               alt[j++] = 0x10000e;    /* PM_PURR */
+                               break;
+                       }
+               }
+               nalt = j;
+       }
+
+       if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
+               /* remove the limited PMC events */
+               j = 0;
+               for (i = 0; i < nalt; ++i) {
+                       if (!p6_limited_pmc_event(alt[i])) {
+                               alt[j] = alt[i];
+                               ++j;
+                       }
+               }
+               nalt = j;
+       } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
+               /* remove all but the limited PMC events */
+               j = 0;
+               for (i = 0; i < nalt; ++i) {
+                       if (p6_limited_pmc_event(alt[i])) {
+                               alt[j] = alt[i];
+                               ++j;
+                       }
+               }
+               nalt = j;
+       }
+
+       return nalt;
+}
+
+static void p6_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       /* Set PMCxSEL to 0 to disable PMCx */
+       if (pmc <= 3)
+               mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
+}
+
+static int power6_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 0x1e,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 2,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x280030, /* LD_REF_L1 */
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x30000c, /* LD_MISS_L1 */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x410a0,  /* BR_PRED */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x400052, /* BR_MPRED */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ * The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
+ */
+static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x280030,       0x80080         },
+               [C(OP_WRITE)] = {       0x180032,       0x80088         },
+               [C(OP_PREFETCH)] = {    0x810a4,        0               },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x100056        },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    0x4008c,        0               },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x150730,       0x250532        },
+               [C(OP_WRITE)] = {       0x250432,       0x150432        },
+               [C(OP_PREFETCH)] = {    0x810a6,        0               },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x20000e        },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x420ce         },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x430e6,        0x400052        },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1              },
+               [C(OP_WRITE)] = {       -1,             -1              },
+               [C(OP_PREFETCH)] = {    -1,             -1              },
+       },
+};
+
+static struct power_pmu power6_pmu = {
+       .name                   = "POWER6",
+       .n_counter              = 6,
+       .max_alternatives       = MAX_ALT,
+       .add_fields             = 0x1555,
+       .test_adder             = 0x3000,
+       .compute_mmcr           = p6_compute_mmcr,
+       .get_constraint         = p6_get_constraint,
+       .get_alternatives       = p6_get_alternatives,
+       .disable_pmc            = p6_disable_pmc,
+       .limited_pmc_event      = p6_limited_pmc_event,
+       .flags                  = PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
+       .n_generic              = ARRAY_SIZE(power6_generic_events),
+       .generic_events         = power6_generic_events,
+       .cache_events           = &power6_cache_events,
+};
+
+static int __init init_power6_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
+               return -ENODEV;
+
+       return register_power_pmu(&power6_pmu);
+}
+
+early_initcall(init_power6_pmu);
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
new file mode 100644 (file)
index 0000000..1251e4d
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Performance counter support for POWER7 processors.
+ *
+ * Copyright 2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/string.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for POWER7
+ */
+#define PM_PMC_SH      16      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0xf
+#define PM_PMC_MSKS    (PM_PMC_MSK << PM_PMC_SH)
+#define PM_UNIT_SH     12      /* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK    0xf
+#define PM_COMBINE_SH  11      /* Combined event bit */
+#define PM_COMBINE_MSK 1
+#define PM_COMBINE_MSKS        0x800
+#define PM_L2SEL_SH    8       /* L2 event select */
+#define PM_L2SEL_MSK   7
+#define PM_PMCSEL_MSK  0xff
+
+/*
+ * Bits in MMCR1 for POWER7
+ */
+#define MMCR1_TTM0SEL_SH       60
+#define MMCR1_TTM1SEL_SH       56
+#define MMCR1_TTM2SEL_SH       52
+#define MMCR1_TTM3SEL_SH       48
+#define MMCR1_TTMSEL_MSK       0xf
+#define MMCR1_L2SEL_SH         45
+#define MMCR1_L2SEL_MSK                7
+#define MMCR1_PMC1_COMBINE_SH  35
+#define MMCR1_PMC2_COMBINE_SH  34
+#define MMCR1_PMC3_COMBINE_SH  33
+#define MMCR1_PMC4_COMBINE_SH  32
+#define MMCR1_PMC1SEL_SH       24
+#define MMCR1_PMC2SEL_SH       16
+#define MMCR1_PMC3SEL_SH       8
+#define MMCR1_PMC4SEL_SH       0
+#define MMCR1_PMCSEL_SH(n)     (MMCR1_PMC1SEL_SH - (n) * 8)
+#define MMCR1_PMCSEL_MSK       0xff
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *                                                 [  ><><><><><><>
+ *                                                  NC P6P5P4P3P2P1
+ *
+ * NC - number of counters
+ *     15: NC error 0x8000
+ *     12-14: number of events needing PMC1-4 0x7000
+ *
+ * P6
+ *     11: P6 error 0x800
+ *     10-11: Count of events needing PMC6
+ *
+ * P1..P5
+ *     0-9: Count of events needing PMC1..PMC5
+ */
+
+static int power7_get_constraint(u64 event, unsigned long *maskp,
+                                unsigned long *valp)
+{
+       int pmc, sh;
+       unsigned long mask = 0, value = 0;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 6)
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+               if (pmc >= 5 && !(event == 0x500fa || event == 0x600f4))
+                       return -1;
+       }
+       if (pmc < 5) {
+               /* need a counter from PMC1-4 set */
+               mask  |= 0x8000;
+               value |= 0x1000;
+       }
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+#define MAX_ALT        2       /* at most 2 alternatives for any event */
+
+static const unsigned int event_alternatives[][MAX_ALT] = {
+       { 0x200f2, 0x300f2 },           /* PM_INST_DISP */
+       { 0x200f4, 0x600f4 },           /* PM_RUN_CYC */
+       { 0x400fa, 0x500fa },           /* PM_RUN_INST_CMPL */
+};
+
+/*
+ * Scan the alternatives table for a match and return the
+ * index into the alternatives table if found, else -1.
+ */
+static int find_alternative(u64 event)
+{
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
+               if (event < event_alternatives[i][0])
+                       break;
+               for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
+                       if (event == event_alternatives[i][j])
+                               return i;
+       }
+       return -1;
+}
+
+static s64 find_alternative_decode(u64 event)
+{
+       int pmc, psel;
+
+       /* this only handles the 4x decode events */
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = event & PM_PMCSEL_MSK;
+       if ((pmc == 2 || pmc == 4) && (psel & ~7) == 0x40)
+               return event - (1 << PM_PMC_SH) + 8;
+       if ((pmc == 1 || pmc == 3) && (psel & ~7) == 0x48)
+               return event + (1 << PM_PMC_SH) - 8;
+       return -1;
+}
+
+static int power7_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       int i, j, nalt = 1;
+       s64 ae;
+
+       alt[0] = event;
+       nalt = 1;
+       i = find_alternative(event);
+       if (i >= 0) {
+               for (j = 0; j < MAX_ALT; ++j) {
+                       ae = event_alternatives[i][j];
+                       if (ae && ae != event)
+                               alt[nalt++] = ae;
+               }
+       } else {
+               ae = find_alternative_decode(event);
+               if (ae > 0)
+                       alt[nalt++] = ae;
+       }
+
+       if (flags & PPMU_ONLY_COUNT_RUN) {
+               /*
+                * We're only counting in RUN state,
+                * so PM_CYC is equivalent to PM_RUN_CYC
+                * and PM_INST_CMPL === PM_RUN_INST_CMPL.
+                * This doesn't include alternatives that don't provide
+                * any extra flexibility in assigning PMCs.
+                */
+               j = nalt;
+               for (i = 0; i < nalt; ++i) {
+                       switch (alt[i]) {
+                       case 0x1e:      /* PM_CYC */
+                               alt[j++] = 0x600f4;     /* PM_RUN_CYC */
+                               break;
+                       case 0x600f4:   /* PM_RUN_CYC */
+                               alt[j++] = 0x1e;
+                               break;
+                       case 0x2:       /* PM_PPC_CMPL */
+                               alt[j++] = 0x500fa;     /* PM_RUN_INST_CMPL */
+                               break;
+                       case 0x500fa:   /* PM_RUN_INST_CMPL */
+                               alt[j++] = 0x2; /* PM_PPC_CMPL */
+                               break;
+                       }
+               }
+               nalt = j;
+       }
+
+       return nalt;
+}
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int power7_marked_instr_event(u64 event)
+{
+       int pmc, psel;
+       int unit;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       psel = event & PM_PMCSEL_MSK & ~1;      /* trim off edge/level bit */
+       if (pmc >= 5)
+               return 0;
+
+       switch (psel >> 4) {
+       case 2:
+               return pmc == 2 || pmc == 4;
+       case 3:
+               if (psel == 0x3c)
+                       return pmc == 1;
+               if (psel == 0x3e)
+                       return pmc != 2;
+               return 1;
+       case 4:
+       case 5:
+               return unit == 0xd;
+       case 6:
+               if (psel == 0x64)
+                       return pmc >= 3;
+       case 8:
+               return unit == 0xd;
+       }
+       return 0;
+}
+
+static int power7_compute_mmcr(u64 event[], int n_ev,
+                              unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr1 = 0;
+       unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
+       unsigned int pmc, unit, combine, l2sel, psel;
+       unsigned int pmc_inuse = 0;
+       int i;
+
+       /* First pass to count resource use */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc > 6)
+                               return -1;
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;
+                       pmc_inuse |= 1 << (pmc - 1);
+               }
+       }
+
+       /* Second pass: assign PMCs, set all MMCR1 fields */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               combine = (event[i] >> PM_COMBINE_SH) & PM_COMBINE_MSK;
+               l2sel = (event[i] >> PM_L2SEL_SH) & PM_L2SEL_MSK;
+               psel = event[i] & PM_PMCSEL_MSK;
+               if (!pmc) {
+                       /* Bus event or any-PMC direct event */
+                       for (pmc = 0; pmc < 4; ++pmc) {
+                               if (!(pmc_inuse & (1 << pmc)))
+                                       break;
+                       }
+                       if (pmc >= 4)
+                               return -1;
+                       pmc_inuse |= 1 << pmc;
+               } else {
+                       /* Direct or decoded event */
+                       --pmc;
+               }
+               if (pmc <= 3) {
+                       mmcr1 |= (unsigned long) unit
+                               << (MMCR1_TTM0SEL_SH - 4 * pmc);
+                       mmcr1 |= (unsigned long) combine
+                               << (MMCR1_PMC1_COMBINE_SH - pmc);
+                       mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
+                       if (unit == 6)  /* L2 events */
+                               mmcr1 |= (unsigned long) l2sel
+                                       << MMCR1_L2SEL_SH;
+               }
+               if (power7_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+               hwc[i] = pmc;
+       }
+
+       /* Return MMCRx values */
+       mmcr[0] = 0;
+       if (pmc_inuse & 1)
+               mmcr[0] = MMCR0_PMC1CE;
+       if (pmc_inuse & 0x3e)
+               mmcr[0] |= MMCR0_PMCjCE;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       if (pmc <= 3)
+               mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
+}
+
+static int power7_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
+       [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */
+       [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a,  /* CMPLU_STALL */
+       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
+       [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880,      /* LD_REF_L1_LSU*/
+       [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0,         /* LD_MISS_L1   */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068,  /* BRU_FIN      */
+       [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6,        /* BR_MPRED     */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0xc880,         0x400f0 },
+               [C(OP_WRITE)] = {       0,              0x300f0 },
+               [C(OP_PREFETCH)] = {    0xd8b8,         0       },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x200fc },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    0x408a,         0       },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x16080,        0x26080 },
+               [C(OP_WRITE)] = {       0x16082,        0x26082 },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x300fc },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x400fc },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x10068,        0x400f6 },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+static struct power_pmu power7_pmu = {
+       .name                   = "POWER7",
+       .n_counter              = 6,
+       .max_alternatives       = MAX_ALT + 1,
+       .add_fields             = 0x1555ul,
+       .test_adder             = 0x3000ul,
+       .compute_mmcr           = power7_compute_mmcr,
+       .get_constraint         = power7_get_constraint,
+       .get_alternatives       = power7_get_alternatives,
+       .disable_pmc            = power7_disable_pmc,
+       .flags                  = PPMU_ALT_SIPR,
+       .n_generic              = ARRAY_SIZE(power7_generic_events),
+       .generic_events         = power7_generic_events,
+       .cache_events           = &power7_cache_events,
+};
+
+static int __init init_power7_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
+               return -ENODEV;
+
+       return register_power_pmu(&power7_pmu);
+}
+
+early_initcall(init_power7_pmu);
diff --git a/arch/powerpc/perf/ppc970-pmu.c b/arch/powerpc/perf/ppc970-pmu.c
new file mode 100644 (file)
index 0000000..111eb25
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Performance counter support for PPC970-family processors.
+ *
+ * Copyright 2008-2009 Paul Mackerras, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Bits in event code for PPC970
+ */
+#define PM_PMC_SH      12      /* PMC number (1-based) for direct events */
+#define PM_PMC_MSK     0xf
+#define PM_UNIT_SH     8       /* TTMMUX number and setting - unit select */
+#define PM_UNIT_MSK    0xf
+#define PM_SPCSEL_SH   6
+#define PM_SPCSEL_MSK  3
+#define PM_BYTE_SH     4       /* Byte number of event bus to use */
+#define PM_BYTE_MSK    3
+#define PM_PMCSEL_MSK  0xf
+
+/* Values in PM_UNIT field */
+#define PM_NONE                0
+#define PM_FPU         1
+#define PM_VPU         2
+#define PM_ISU         3
+#define PM_IFU         4
+#define PM_IDU         5
+#define PM_STS         6
+#define PM_LSU0                7
+#define PM_LSU1U       8
+#define PM_LSU1L       9
+#define PM_LASTUNIT    9
+
+/*
+ * Bits in MMCR0 for PPC970
+ */
+#define MMCR0_PMC1SEL_SH       8
+#define MMCR0_PMC2SEL_SH       1
+#define MMCR_PMCSEL_MSK                0x1f
+
+/*
+ * Bits in MMCR1 for PPC970
+ */
+#define MMCR1_TTM0SEL_SH       62
+#define MMCR1_TTM1SEL_SH       59
+#define MMCR1_TTM3SEL_SH       53
+#define MMCR1_TTMSEL_MSK       3
+#define MMCR1_TD_CP_DBG0SEL_SH 50
+#define MMCR1_TD_CP_DBG1SEL_SH 48
+#define MMCR1_TD_CP_DBG2SEL_SH 46
+#define MMCR1_TD_CP_DBG3SEL_SH 44
+#define MMCR1_PMC1_ADDER_SEL_SH        39
+#define MMCR1_PMC2_ADDER_SEL_SH        38
+#define MMCR1_PMC6_ADDER_SEL_SH        37
+#define MMCR1_PMC5_ADDER_SEL_SH        36
+#define MMCR1_PMC8_ADDER_SEL_SH        35
+#define MMCR1_PMC7_ADDER_SEL_SH        34
+#define MMCR1_PMC3_ADDER_SEL_SH        33
+#define MMCR1_PMC4_ADDER_SEL_SH        32
+#define MMCR1_PMC3SEL_SH       27
+#define MMCR1_PMC4SEL_SH       22
+#define MMCR1_PMC5SEL_SH       17
+#define MMCR1_PMC6SEL_SH       12
+#define MMCR1_PMC7SEL_SH       7
+#define MMCR1_PMC8SEL_SH       2
+
+static short mmcr1_adder_bits[8] = {
+       MMCR1_PMC1_ADDER_SEL_SH,
+       MMCR1_PMC2_ADDER_SEL_SH,
+       MMCR1_PMC3_ADDER_SEL_SH,
+       MMCR1_PMC4_ADDER_SEL_SH,
+       MMCR1_PMC5_ADDER_SEL_SH,
+       MMCR1_PMC6_ADDER_SEL_SH,
+       MMCR1_PMC7_ADDER_SEL_SH,
+       MMCR1_PMC8_ADDER_SEL_SH
+};
+
+/*
+ * Layout of constraint bits:
+ * 6666555555555544444444443333333333222222222211111111110000000000
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ *               <><><>[  >[  >[  ><  ><  ><  ><  ><><><><><><><><>
+ *               SPT0T1 UC  PS1 PS2 B0  B1  B2  B3 P1P2P3P4P5P6P7P8
+ *
+ * SP - SPCSEL constraint
+ *     48-49: SPCSEL value 0x3_0000_0000_0000
+ *
+ * T0 - TTM0 constraint
+ *     46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
+ *
+ * T1 - TTM1 constraint
+ *     44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
+ *
+ * UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
+ *     43: UC3 error 0x0800_0000_0000
+ *     42: FPU|IFU|VPU events needed 0x0400_0000_0000
+ *     41: ISU events needed 0x0200_0000_0000
+ *     40: IDU|STS events needed 0x0100_0000_0000
+ *
+ * PS1
+ *     39: PS1 error 0x0080_0000_0000
+ *     36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
+ *
+ * PS2
+ *     35: PS2 error 0x0008_0000_0000
+ *     32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
+ *
+ * B0
+ *     28-31: Byte 0 event source 0xf000_0000
+ *           Encoding as for the event code
+ *
+ * B1, B2, B3
+ *     24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
+ *
+ * P1
+ *     15: P1 error 0x8000
+ *     14-15: Count of events needing PMC1
+ *
+ * P2..P8
+ *     0-13: Count of events needing PMC2..PMC8
+ */
+
+static unsigned char direct_marked_event[8] = {
+       (1<<2) | (1<<3),        /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
+       (1<<3) | (1<<5),        /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
+       (1<<3) | (1<<5),        /* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
+       (1<<4) | (1<<5),        /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
+       (1<<4) | (1<<5),        /* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
+       (1<<3) | (1<<4) | (1<<5),
+               /* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
+       (1<<4) | (1<<5),        /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
+       (1<<4)                  /* PMC8: PM_MRK_LSU_FIN */
+};
+
+/*
+ * Returns 1 if event counts things relating to marked instructions
+ * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
+ */
+static int p970_marked_instr_event(u64 event)
+{
+       int pmc, psel, unit, byte, bit;
+       unsigned int mask;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       psel = event & PM_PMCSEL_MSK;
+       if (pmc) {
+               if (direct_marked_event[pmc - 1] & (1 << psel))
+                       return 1;
+               if (psel == 0)          /* add events */
+                       bit = (pmc <= 4)? pmc - 1: 8 - pmc;
+               else if (psel == 7 || psel == 13)       /* decode events */
+                       bit = 4;
+               else
+                       return 0;
+       } else
+               bit = psel;
+
+       byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       mask = 0;
+       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;
+       }
+       return (mask >> (byte * 8 + bit)) & 1;
+}
+
+/* Masks and values for using events from the various units */
+static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
+       [PM_FPU] =   { 0xc80000000000ull, 0x040000000000ull },
+       [PM_VPU] =   { 0xc80000000000ull, 0xc40000000000ull },
+       [PM_ISU] =   { 0x080000000000ull, 0x020000000000ull },
+       [PM_IFU] =   { 0xc80000000000ull, 0x840000000000ull },
+       [PM_IDU] =   { 0x380000000000ull, 0x010000000000ull },
+       [PM_STS] =   { 0x380000000000ull, 0x310000000000ull },
+};
+
+static int p970_get_constraint(u64 event, unsigned long *maskp,
+                              unsigned long *valp)
+{
+       int pmc, byte, unit, sh, spcsel;
+       unsigned long mask = 0, value = 0;
+       int grp = -1;
+
+       pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
+       if (pmc) {
+               if (pmc > 8)
+                       return -1;
+               sh = (pmc - 1) * 2;
+               mask |= 2 << sh;
+               value |= 1 << sh;
+               grp = ((pmc - 1) >> 1) & 1;
+       }
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       if (unit) {
+               if (unit > PM_LASTUNIT)
+                       return -1;
+               mask |= unit_cons[unit][0];
+               value |= unit_cons[unit][1];
+               byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
+               /*
+                * Bus events on bytes 0 and 2 can be counted
+                * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
+                */
+               if (!pmc)
+                       grp = byte & 1;
+               /* Set byte lane select field */
+               mask  |= 0xfULL << (28 - 4 * byte);
+               value |= (unsigned long)unit << (28 - 4 * byte);
+       }
+       if (grp == 0) {
+               /* increment PMC1/2/5/6 field */
+               mask  |= 0x8000000000ull;
+               value |= 0x1000000000ull;
+       } else if (grp == 1) {
+               /* increment PMC3/4/7/8 field */
+               mask  |= 0x800000000ull;
+               value |= 0x100000000ull;
+       }
+       spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
+       if (spcsel) {
+               mask  |= 3ull << 48;
+               value |= (unsigned long)spcsel << 48;
+       }
+       *maskp = mask;
+       *valp = value;
+       return 0;
+}
+
+static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
+{
+       alt[0] = event;
+
+       /* 2 alternatives for LSU empty */
+       if (event == 0x2002 || event == 0x3002) {
+               alt[1] = event ^ 0x1000;
+               return 2;
+       }
+
+       return 1;
+}
+
+static int p970_compute_mmcr(u64 event[], int n_ev,
+                            unsigned int hwc[], unsigned long mmcr[])
+{
+       unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
+       unsigned int pmc, unit, byte, psel;
+       unsigned int ttm, grp;
+       unsigned int pmc_inuse = 0;
+       unsigned int pmc_grp_use[2];
+       unsigned char busbyte[4];
+       unsigned char unituse[16];
+       unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
+       unsigned char ttmuse[2];
+       unsigned char pmcsel[8];
+       int i;
+       int spcsel;
+
+       if (n_ev > 8)
+               return -1;
+
+       /* First pass to count resource use */
+       pmc_grp_use[0] = pmc_grp_use[1] = 0;
+       memset(busbyte, 0, sizeof(busbyte));
+       memset(unituse, 0, sizeof(unituse));
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               if (pmc) {
+                       if (pmc_inuse & (1 << (pmc - 1)))
+                               return -1;
+                       pmc_inuse |= 1 << (pmc - 1);
+                       /* count 1/2/5/6 vs 3/4/7/8 use */
+                       ++pmc_grp_use[((pmc - 1) >> 1) & 1];
+               }
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               if (unit) {
+                       if (unit > PM_LASTUNIT)
+                               return -1;
+                       if (!pmc)
+                               ++pmc_grp_use[byte & 1];
+                       if (busbyte[byte] && busbyte[byte] != unit)
+                               return -1;
+                       busbyte[byte] = unit;
+                       unituse[unit] = 1;
+               }
+       }
+       if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
+               return -1;
+
+       /*
+        * Assign resources and set multiplexer selects.
+        *
+        * PM_ISU can go either on TTM0 or TTM1, but that's the only
+        * choice we have to deal with.
+        */
+       if (unituse[PM_ISU] &
+           (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
+               unitmap[PM_ISU] = 2 | 4;        /* move ISU to TTM1 */
+       /* Set TTM[01]SEL fields. */
+       ttmuse[0] = ttmuse[1] = 0;
+       for (i = PM_FPU; i <= PM_STS; ++i) {
+               if (!unituse[i])
+                       continue;
+               ttm = unitmap[i];
+               ++ttmuse[(ttm >> 2) & 1];
+               mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
+       }
+       /* Check only one unit per TTMx */
+       if (ttmuse[0] > 1 || ttmuse[1] > 1)
+               return -1;
+
+       /* Set byte lane select fields and TTM3SEL. */
+       for (byte = 0; byte < 4; ++byte) {
+               unit = busbyte[byte];
+               if (!unit)
+                       continue;
+               if (unit <= PM_STS)
+                       ttm = (unitmap[unit] >> 2) & 1;
+               else if (unit == PM_LSU0)
+                       ttm = 2;
+               else {
+                       ttm = 3;
+                       if (unit == PM_LSU1L && byte >= 2)
+                               mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
+               }
+               mmcr1 |= (unsigned long)ttm
+                       << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
+       }
+
+       /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
+       memset(pmcsel, 0x8, sizeof(pmcsel));    /* 8 means don't count */
+       for (i = 0; i < n_ev; ++i) {
+               pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
+               unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
+               byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
+               psel = event[i] & PM_PMCSEL_MSK;
+               if (!pmc) {
+                       /* Bus event or any-PMC direct event */
+                       if (unit)
+                               psel |= 0x10 | ((byte & 2) << 2);
+                       else
+                               psel |= 8;
+                       for (pmc = 0; pmc < 8; ++pmc) {
+                               if (pmc_inuse & (1 << pmc))
+                                       continue;
+                               grp = (pmc >> 1) & 1;
+                               if (unit) {
+                                       if (grp == (byte & 1))
+                                               break;
+                               } else if (pmc_grp_use[grp] < 4) {
+                                       ++pmc_grp_use[grp];
+                                       break;
+                               }
+                       }
+                       pmc_inuse |= 1 << pmc;
+               } else {
+                       /* Direct event */
+                       --pmc;
+                       if (psel == 0 && (byte & 2))
+                               /* add events on higher-numbered bus */
+                               mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
+               }
+               pmcsel[pmc] = psel;
+               hwc[i] = pmc;
+               spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
+               mmcr1 |= spcsel;
+               if (p970_marked_instr_event(event[i]))
+                       mmcra |= MMCRA_SAMPLE_ENABLE;
+       }
+       for (pmc = 0; pmc < 2; ++pmc)
+               mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
+       for (; pmc < 8; ++pmc)
+               mmcr1 |= (unsigned long)pmcsel[pmc]
+                       << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
+       if (pmc_inuse & 1)
+               mmcr0 |= MMCR0_PMC1CE;
+       if (pmc_inuse & 0xfe)
+               mmcr0 |= MMCR0_PMCjCE;
+
+       mmcra |= 0x2000;        /* mark only one IOP per PPC instruction */
+
+       /* Return MMCRx values */
+       mmcr[0] = mmcr0;
+       mmcr[1] = mmcr1;
+       mmcr[2] = mmcra;
+       return 0;
+}
+
+static void p970_disable_pmc(unsigned int pmc, unsigned long mmcr[])
+{
+       int shift, i;
+
+       if (pmc <= 1) {
+               shift = MMCR0_PMC1SEL_SH - 7 * pmc;
+               i = 0;
+       } else {
+               shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
+               i = 1;
+       }
+       /*
+        * Setting the PMCxSEL field to 0x08 disables PMC x.
+        */
+       mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
+}
+
+static int ppc970_generic_events[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = 7,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 1,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x8810, /* PM_LD_REF_L1 */
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x3810, /* PM_LD_MISS_L1 */
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x431,  /* PM_BR_ISSUED */
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x327,  /* PM_GRP_BR_MPRED */
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [C(L1D)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x8810,         0x3810  },
+               [C(OP_WRITE)] = {       0x7810,         0x813   },
+               [C(OP_PREFETCH)] = {    0x731,          0       },
+       },
+       [C(L1I)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    0,              0       },
+       },
+       [C(LL)] = {             /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0       },
+               [C(OP_WRITE)] = {       0,              0       },
+               [C(OP_PREFETCH)] = {    0x733,          0       },
+       },
+       [C(DTLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x704   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(ITLB)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0,              0x700   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(BPU)] = {            /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        0x431,          0x327   },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+       [C(NODE)] = {           /*      RESULT_ACCESS   RESULT_MISS */
+               [C(OP_READ)] = {        -1,             -1      },
+               [C(OP_WRITE)] = {       -1,             -1      },
+               [C(OP_PREFETCH)] = {    -1,             -1      },
+       },
+};
+
+static struct power_pmu ppc970_pmu = {
+       .name                   = "PPC970/FX/MP",
+       .n_counter              = 8,
+       .max_alternatives       = 2,
+       .add_fields             = 0x001100005555ull,
+       .test_adder             = 0x013300000000ull,
+       .compute_mmcr           = p970_compute_mmcr,
+       .get_constraint         = p970_get_constraint,
+       .get_alternatives       = p970_get_alternatives,
+       .disable_pmc            = p970_disable_pmc,
+       .n_generic              = ARRAY_SIZE(ppc970_generic_events),
+       .generic_events         = ppc970_generic_events,
+       .cache_events           = &ppc970_cache_events,
+};
+
+static int __init init_ppc970_pmu(void)
+{
+       if (!cur_cpu_spec->oprofile_cpu_type ||
+           (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
+            && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
+               return -ENODEV;
+
+       return register_power_pmu(&ppc970_pmu);
+}
+
+early_initcall(init_ppc970_pmu);
index fcf6bf2..2e4e64a 100644 (file)
@@ -23,6 +23,7 @@ config BLUESTONE
        default n
        select PPC44x_SIMPLE
        select APM821xx
+       select PPC4xx_PCI_EXPRESS
        select IBM_EMAC_RGMII
        help
          This option enables support for the APM APM821xx Evaluation board.
index 3f6229b..583e67f 100644 (file)
@@ -83,7 +83,7 @@ static void __init ppc47x_init_irq(void)
                 * device-tree, just pass 0 to all arguments
                 */
                struct mpic *mpic =
-                       mpic_alloc(np, 0, 0, 0, 0, " MPIC     ");
+                       mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
                BUG_ON(mpic == NULL);
                mpic_init(mpic);
                ppc_md.get_irq = mpic_get_irq;
index 5b8cdbb..a28a862 100644 (file)
@@ -71,8 +71,7 @@ static void __init iss4xx_init_irq(void)
                /* The MPIC driver will get everything it needs from the
                 * device-tree, just pass 0 to all arguments
                 */
-               struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0,
-                                              " MPIC     ");
+               struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
                BUG_ON(mpic == NULL);
                mpic_init(mpic);
                ppc_md.get_irq = mpic_get_irq;
index 8d22027..3ffb915 100644 (file)
@@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
 static char *board[] __initdata = {
        "amcc,arches",
        "amcc,bamboo",
-       "amcc,bluestone",
+       "apm,bluestone",
        "amcc,glacier",
        "ibm,ebony",
        "amcc,eiger",
index 846b789..c0aa040 100644 (file)
@@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void)
 
 /* list of the supported boards */
 static const char *board[] __initdata = {
+       "anonymous,a4m072",
        "anon,charon",
        "intercontrol,digsy-mtc",
        "manroland,mucmc52",
index 369fd54..d7e94f4 100644 (file)
@@ -98,13 +98,11 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio;
  *                                     of the localplus bus to the of_platform
  *                                     bus.
  */
-void __init
-mpc52xx_declare_of_platform_devices(void)
+void __init mpc52xx_declare_of_platform_devices(void)
 {
-       /* Find every child of the SOC node and add it to of_platform */
-       if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))
-               printk(KERN_ERR __FILE__ ": "
-                       "Error while probing of_platform bus\n");
+       /* Find all the 'platform' devices and register them. */
+       if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL))
+               pr_err(__FILE__ ": Error while populating devices from DT\n");
 }
 
 /*
index d7946be..f000d81 100644 (file)
@@ -6,6 +6,7 @@ menuconfig FSL_SOC_BOOKE
        select MPIC
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
+       select SERIAL_8250_EXTENDED if SERIAL_8250
        select SERIAL_8250_SHARE_IRQ if SERIAL_8250
        default y
 
@@ -13,6 +14,15 @@ if FSL_SOC_BOOKE
 
 if PPC32
 
+config FSL_85XX_CACHE_SRAM
+       bool
+       select PPC_LIB_RHEAP
+       help
+         When selected, this option enables cache-sram support
+         for memory allocation on P1/P2 QorIQ platforms.
+         cache-sram-size and cache-sram-offset kernel boot
+         parameters should be passed when this option is enabled.
+
 config MPC8540_ADS
        bool "Freescale MPC8540 ADS"
        select DEFAULT_UIMAGE
@@ -30,6 +40,7 @@ config MPC85xx_CDS
        bool "Freescale MPC85xx CDS"
        select DEFAULT_UIMAGE
        select PPC_I8259
+       select HAS_RAPIDIO
        help
          This option enables support for the MPC85xx CDS board
 
@@ -80,7 +91,6 @@ config P1010_RDB
 config P1022_DS
        bool "Freescale P1022 DS"
        select DEFAULT_UIMAGE
-       select PHYS_64BIT       # The DTS has 36-bit addresses
        select SWIOTLB
        help
          This option enables support for the Freescale P1022DS reference board.
@@ -171,6 +181,21 @@ config SBC8560
        help
          This option enables support for the Wind River SBC8560 board
 
+config GE_IMP3A
+       bool "GE Intelligent Platforms IMP3A"
+       select DEFAULT_UIMAGE
+       select SWIOTLB
+       select MMIO_NVRAM
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       select GE_FPGA
+       help
+         This option enables support for the GE Intelligent Platforms IMP3A
+         board.
+
+         This board is a 3U CompactPCI Single Board Computer with a Freescale
+         P2020 processor.
+
 config P2041_RDB
        bool "Freescale P2041 RDB"
        select DEFAULT_UIMAGE
index 9cb2d43..2125d4c 100644 (file)
@@ -27,3 +27,4 @@ obj-$(CONFIG_SBC8548)     += sbc8548.o
 obj-$(CONFIG_SOCRATES)    += socrates.o socrates_fpga_pic.o
 obj-$(CONFIG_KSI8560)    += ksi8560.o
 obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
+obj-$(CONFIG_GE_IMP3A)   += ge_imp3a.o
index 07e3e6c..df69e99 100644 (file)
@@ -36,8 +36,8 @@
 void __init corenet_ds_pic_init(void)
 {
        struct mpic *mpic;
-       unsigned int flags = MPIC_BIG_ENDIAN |
-                               MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU;
+       unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
+               MPIC_NO_RESET;
 
        if (ppc_md.get_irq == mpic_get_coreint_irq)
                flags |= MPIC_ENABLE_COREINT;
diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c
new file mode 100644 (file)
index 0000000..d50056f
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * GE IMP3A Board Setup
+ *
+ * Author Martyn Welch <martyn.welch@ge.com>
+ *
+ * Copyright 2010 GE Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup)
+ * Copyright 2007 Freescale Semiconductor Inc.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.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 <asm/swiotlb.h>
+#include <asm/nvram.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include "smp.h"
+
+#include "mpc85xx.h"
+#include <sysdev/ge/ge_pic.h>
+
+void __iomem *imp3a_regs;
+
+void __init ge_imp3a_pic_init(void)
+{
+       struct mpic *mpic;
+       struct device_node *np;
+       struct device_node *cascade_node = NULL;
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
+               mpic = mpic_alloc(NULL, 0,
+                       MPIC_NO_RESET |
+                       MPIC_BIG_ENDIAN |
+                       MPIC_SINGLE_DEST_CPU,
+                       0, 256, " OpenPIC  ");
+       } else {
+               mpic = mpic_alloc(NULL, 0,
+                         MPIC_BIG_ENDIAN |
+                         MPIC_SINGLE_DEST_CPU,
+                       0, 256, " OpenPIC  ");
+       }
+
+       BUG_ON(mpic == NULL);
+       mpic_init(mpic);
+       /*
+        * There is a simple interrupt handler in the main FPGA, this needs
+        * to be cascaded into the MPIC
+        */
+       for_each_node_by_type(np, "interrupt-controller")
+               if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) {
+                       cascade_node = np;
+                       break;
+               }
+
+       if (cascade_node == NULL) {
+               printk(KERN_WARNING "IMP3A: No FPGA PIC\n");
+               return;
+       }
+
+       gef_pic_init(cascade_node);
+       of_node_put(cascade_node);
+}
+
+#ifdef CONFIG_PCI
+static int primary_phb_addr;
+#endif /* CONFIG_PCI */
+
+/*
+ * Setup the architecture
+ */
+static void __init ge_imp3a_setup_arch(void)
+{
+       struct device_node *regs;
+#ifdef CONFIG_PCI
+       struct device_node *np;
+       struct pci_controller *hose;
+#endif
+       dma_addr_t max = 0xffffffff;
+
+       if (ppc_md.progress)
+               ppc_md.progress("ge_imp3a_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+       for_each_node_by_type(np, "pci") {
+               if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+                   of_device_is_compatible(np, "fsl,mpc8548-pcie") ||
+                   of_device_is_compatible(np, "fsl,p2020-pcie")) {
+                       struct resource rsrc;
+                       of_address_to_resource(np, 0, &rsrc);
+                       if ((rsrc.start & 0xfffff) == primary_phb_addr)
+                               fsl_add_bridge(np, 1);
+                       else
+                               fsl_add_bridge(np, 0);
+
+                       hose = pci_find_hose_for_OF_device(np);
+                       max = min(max, hose->dma_window_base_cur +
+                                       hose->dma_window_size);
+               }
+       }
+#endif
+
+       mpc85xx_smp_init();
+
+#ifdef CONFIG_SWIOTLB
+       if (memblock_end_of_DRAM() > max) {
+               ppc_swiotlb_enable = 1;
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+       }
+#endif
+
+       /* Remap basic board registers */
+       regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs");
+       if (regs) {
+               imp3a_regs = of_iomap(regs, 0);
+               if (imp3a_regs == NULL)
+                       printk(KERN_WARNING "Unable to map board registers\n");
+               of_node_put(regs);
+       }
+
+#if defined(CONFIG_MMIO_NVRAM)
+       mmio_nvram_init();
+#endif
+
+       printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n");
+}
+
+/* Return the PCB revision */
+static unsigned int ge_imp3a_get_pcb_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread16(imp3a_regs);
+       return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int ge_imp3a_get_board_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread16(imp3a_regs + 0x2);
+       return reg & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int ge_imp3a_get_fpga_rev(void)
+{
+       unsigned int reg;
+
+       reg = ioread16(imp3a_regs + 0x2);
+       return (reg >> 8) & 0xff;
+}
+
+/* Return compactPCI Geographical Address */
+static unsigned int ge_imp3a_get_cpci_geo_addr(void)
+{
+       unsigned int reg;
+
+       reg = ioread16(imp3a_regs + 0x6);
+       return (reg & 0x0f00) >> 8;
+}
+
+/* Return compactPCI System Controller Status */
+static unsigned int ge_imp3a_get_cpci_is_syscon(void)
+{
+       unsigned int reg;
+
+       reg = ioread16(imp3a_regs + 0x6);
+       return reg & (1 << 12);
+}
+
+static void ge_imp3a_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n");
+
+       seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(),
+               ('A' + ge_imp3a_get_board_rev() - 1));
+
+       seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev());
+
+       seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr());
+
+       seq_printf(m, "cPCI syscon\t: %s\n",
+               ge_imp3a_get_cpci_is_syscon() ? "yes" : "no");
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init ge_imp3a_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "ge,IMP3A")) {
+#ifdef CONFIG_PCI
+               primary_phb_addr = 0x9000;
+#endif
+               return 1;
+       }
+
+       return 0;
+}
+
+machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices);
+
+machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier);
+
+define_machine(ge_imp3a) {
+       .name                   = "GE_IMP3A",
+       .probe                  = ge_imp3a_probe,
+       .setup_arch             = ge_imp3a_setup_arch,
+       .init_IRQ               = ge_imp3a_pic_init,
+       .show_cpuinfo           = ge_imp3a_show_cpuinfo,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index 20f75d7..60120e5 100644 (file)
@@ -57,8 +57,7 @@ static void machine_restart(char *cmd)
 
 static void __init ksi8560_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index cf26682..f588726 100644 (file)
@@ -36,9 +36,7 @@
 
 void __init mpc8536_ds_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                         MPIC_WANTS_RESET |
-                         MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 3bebb51..d19f675 100644 (file)
@@ -50,8 +50,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose,
 
 static void __init mpc85xx_ads_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 40f03da..ab5f0bf 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Maintained by Kumar Gala (see MAINTAINERS for contact information)
  *
- * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005, 2011-2012 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
 
 #include "mpc85xx.h"
 
-/* CADMUS info */
-/* xxx - galak, move into device tree */
-#define CADMUS_BASE (0xf8004000)
-#define CADMUS_SIZE (256)
-#define CM_VER (0)
-#define CM_CSR (1)
-#define CM_RST (2)
-
+/*
+ * The CDS board contains an FPGA/CPLD called "Cadmus", which collects
+ * various logic and performs system control functions.
+ * Here is the FPGA/CPLD register map.
+ */
+struct cadmus_reg {
+       u8 cm_ver;              /* Board version */
+       u8 cm_csr;              /* General control/status */
+       u8 cm_rst;              /* Reset control */
+       u8 cm_hsclk;    /* High speed clock */
+       u8 cm_hsxclk;   /* High speed clock extended */
+       u8 cm_led;              /* LED data */
+       u8 cm_pci;              /* PCI control/status */
+       u8 cm_dma;              /* DMA control */
+       u8 res[248];    /* Total 256 bytes */
+};
 
-static int cds_pci_slot = 2;
-static volatile u8 *cadmus;
+static struct cadmus_reg *cadmus;
 
 #ifdef CONFIG_PCI
 
@@ -158,6 +165,33 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);
 DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
 DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge);
 
+#define PCI_DEVICE_ID_IDT_TSI310       0x01a7
+
+/*
+ * Fix Tsi310 PCI-X bridge resource.
+ * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space.
+ * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed.
+ */
+void mpc85xx_cds_fixup_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev = bus->self;
+       struct resource *res = bus->resource[0];
+
+       if (dev != NULL &&
+           dev->vendor == PCI_VENDOR_ID_IBM &&
+           dev->device == PCI_DEVICE_ID_IDT_TSI310) {
+               if (res) {
+                       res->start = 0;
+                       res->end   = 0x1fff;
+                       res->flags = IORESOURCE_IO;
+                       pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n");
+                       pr_info("mpc85xx_cds: %pR\n", res);
+               }
+       }
+
+       fsl_pcibios_fixup_bus(bus);
+}
+
 #ifdef CONFIG_PPC_I8259
 static void mpc85xx_8259_cascade_handler(unsigned int irq,
                                         struct irq_desc *desc)
@@ -188,8 +222,7 @@ static struct irqaction mpc85xxcds_8259_irqaction = {
 static void __init mpc85xx_cds_pic_init(void)
 {
        struct mpic *mpic;
-       mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
@@ -249,20 +282,30 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach);
  */
 static void __init mpc85xx_cds_setup_arch(void)
 {
-#ifdef CONFIG_PCI
        struct device_node *np;
-#endif
+       int cds_pci_slot;
 
        if (ppc_md.progress)
                ppc_md.progress("mpc85xx_cds_setup_arch()", 0);
 
-       cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
-       cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga");
+       if (!np) {
+               pr_err("Could not find FPGA node.\n");
+               return;
+       }
+
+       cadmus = of_iomap(np, 0);
+       of_node_put(np);
+       if (!cadmus) {
+               pr_err("Fail to map FPGA area.\n");
+               return;
+       }
 
        if (ppc_md.progress) {
                char buf[40];
+               cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1;
                snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n",
-                               cadmus[CM_VER], cds_pci_slot);
+                               in_8(&cadmus->cm_ver), cds_pci_slot);
                ppc_md.progress(buf, 0);
        }
 
@@ -292,7 +335,8 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m)
        svid = mfspr(SPRN_SVR);
 
        seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
-       seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]);
+       seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n",
+                       in_8(&cadmus->cm_ver));
        seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 
@@ -323,7 +367,7 @@ define_machine(mpc85xx_cds) {
        .get_irq        = mpic_get_irq,
 #ifdef CONFIG_PCI
        .restart        = mpc85xx_cds_restart,
-       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+       .pcibios_fixup_bus      = mpc85xx_cds_fixup_bus,
 #else
        .restart        = fsl_rstcr_restart,
 #endif
index eefbb91..6e23e3e 100644 (file)
@@ -72,13 +72,13 @@ void __init mpc85xx_ds_pic_init(void)
 
        if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
                mpic = mpic_alloc(NULL, 0,
-                       MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+                       MPIC_NO_RESET |
+                       MPIC_BIG_ENDIAN |
                        MPIC_SINGLE_DEST_CPU,
                        0, 256, " OpenPIC  ");
        } else {
                mpic = mpic_alloc(NULL, 0,
-                         MPIC_WANTS_RESET |
-                         MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+                         MPIC_BIG_ENDIAN |
                          MPIC_SINGLE_DEST_CPU,
                        0, 256, " OpenPIC  ");
        }
index 1d15a0c..f33662b 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved.
+ * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc.
+ * All rights reserved.
  *
  * Author: Andy Fleming <afleming@freescale.com>
  *
@@ -51,6 +52,7 @@
 #include <asm/qe_ic.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
+#include <asm/fsl_guts.h>
 #include "smp.h"
 
 #include "mpc85xx.h"
@@ -268,34 +270,27 @@ static void __init mpc85xx_mds_qe_init(void)
        mpc85xx_mds_reset_ucc_phys();
 
        if (machine_is(p1021_mds)) {
-#define MPC85xx_PMUXCR_OFFSET           0x60
-#define MPC85xx_PMUXCR_QE0              0x00008000
-#define MPC85xx_PMUXCR_QE3              0x00001000
-#define MPC85xx_PMUXCR_QE9              0x00000040
-#define MPC85xx_PMUXCR_QE12             0x00000008
-               static __be32 __iomem *pmuxcr;
 
-               np = of_find_node_by_name(NULL, "global-utilities");
+               struct ccsr_guts_85xx __iomem *guts;
 
+               np = of_find_node_by_name(NULL, "global-utilities");
                if (np) {
-                       pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET;
-
-                       if (!pmuxcr)
-                               printk(KERN_EMERG "Error: Alternate function"
-                                       " signal multiplex control register not"
-                                       " mapped!\n");
-                       else
+                       guts = of_iomap(np, 0);
+                       if (!guts)
+                               pr_err("mpc85xx-rdb: could not map global utilities register\n");
+                       else{
                        /* P1021 has pins muxed for QE and other functions. To
                         * enable QE UEC mode, we need to set bit QE0 for UCC1
                         * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
                         * and QE12 for QE MII management signals in PMUXCR
                         * register.
                         */
-                               setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 |
-                                                 MPC85xx_PMUXCR_QE3 |
-                                                 MPC85xx_PMUXCR_QE9 |
-                                                 MPC85xx_PMUXCR_QE12);
-
+                               setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) |
+                                                 MPC85xx_PMUXCR_QE(3) |
+                                                 MPC85xx_PMUXCR_QE(9) |
+                                                 MPC85xx_PMUXCR_QE(12));
+                               iounmap(guts);
+                       }
                        of_node_put(np);
                }
 
@@ -434,9 +429,8 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier);
 
 static void __init mpc85xx_mds_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-                       MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+                       MPIC_SINGLE_DEST_CPU,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
 
index ccf520e..db214cd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC85xx RDB Board Setup
  *
- * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2009,2012 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
@@ -26,6 +26,9 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/mpic.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -47,21 +50,36 @@ void __init mpc85xx_rdb_pic_init(void)
        struct mpic *mpic;
        unsigned long root = of_get_flat_dt_root();
 
+#ifdef CONFIG_QUICC_ENGINE
+       struct device_node *np;
+#endif
+
        if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) {
-               mpic = mpic_alloc(NULL, 0,
-                       MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+               mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET |
+                       MPIC_BIG_ENDIAN |
                        MPIC_SINGLE_DEST_CPU,
                        0, 256, " OpenPIC  ");
        } else {
                mpic = mpic_alloc(NULL, 0,
-                 MPIC_WANTS_RESET |
-                 MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+                 MPIC_BIG_ENDIAN |
                  MPIC_SINGLE_DEST_CPU,
                  0, 256, " OpenPIC  ");
        }
 
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
+
+#ifdef CONFIG_QUICC_ENGINE
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+       if (np) {
+               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+                               qe_ic_cascade_high_mpic);
+               of_node_put(np);
+
+       } else
+               pr_err("%s: Could not find qe-ic node\n", __func__);
+#endif
+
 }
 
 /*
@@ -69,7 +87,7 @@ void __init mpc85xx_rdb_pic_init(void)
  */
 static void __init mpc85xx_rdb_setup_arch(void)
 {
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
        struct device_node *np;
 #endif
 
@@ -85,11 +103,73 @@ static void __init mpc85xx_rdb_setup_arch(void)
 #endif
 
        mpc85xx_smp_init();
+
+#ifdef CONFIG_QUICC_ENGINE
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (!np) {
+               pr_err("%s: Could not find Quicc Engine node\n", __func__);
+               goto qe_fail;
+       }
+
+       qe_reset();
+       of_node_put(np);
+
+       np = of_find_node_by_name(NULL, "par_io");
+       if (np) {
+               struct device_node *ucc;
+
+               par_io_init(np);
+               of_node_put(np);
+
+               for_each_node_by_name(ucc, "ucc")
+                       par_io_of_config(ucc);
+
+       }
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
+       if (machine_is(p1025_rdb)) {
+
+               struct ccsr_guts_85xx __iomem *guts;
+
+               np = of_find_node_by_name(NULL, "global-utilities");
+               if (np) {
+                       guts = of_iomap(np, 0);
+                       if (!guts) {
+
+                               pr_err("mpc85xx-rdb: could not map global utilities register\n");
+
+                       } else {
+                       /* P1025 has pins muxed for QE and other functions. To
+                       * enable QE UEC mode, we need to set bit QE0 for UCC1
+                       * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
+                       * and QE12 for QE MII management singals in PMUXCR
+                       * register.
+                       */
+                               setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) |
+                                               MPC85xx_PMUXCR_QE(3) |
+                                               MPC85xx_PMUXCR_QE(9) |
+                                               MPC85xx_PMUXCR_QE(12));
+                               iounmap(guts);
+                       }
+                       of_node_put(np);
+               }
+
+       }
+#endif
+
+qe_fail:
+#endif /* CONFIG_QUICC_ENGINE */
+
        printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");
 }
 
 machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices);
 machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices);
+machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -112,6 +192,52 @@ static int __init p1020_rdb_probe(void)
        return 0;
 }
 
+static int __init p1020_rdb_pc_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC");
+}
+
+static int __init p1021_rdb_pc_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC"))
+               return 1;
+       return 0;
+}
+
+static int __init p2020_rdb_pc_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC"))
+               return 1;
+       return 0;
+}
+
+static int __init p1025_rdb_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P1025RDB");
+}
+
+static int __init p1020_mbg_pc_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC");
+}
+
+static int __init p1020_utm_pc_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC");
+}
+
 define_machine(p2020_rdb) {
        .name                   = "P2020 RDB",
        .probe                  = p2020_rdb_probe,
@@ -139,3 +265,87 @@ define_machine(p1020_rdb) {
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = udbg_progress,
 };
+
+define_machine(p1021_rdb_pc) {
+       .name                   = "P1021 RDB-PC",
+       .probe                  = p1021_rdb_pc_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+define_machine(p2020_rdb_pc) {
+       .name                   = "P2020RDB-PC",
+       .probe                  = p2020_rdb_pc_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+define_machine(p1025_rdb) {
+       .name                   = "P1025 RDB",
+       .probe                  = p1025_rdb_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+define_machine(p1020_mbg_pc) {
+       .name                   = "P1020 MBG-PC",
+       .probe                  = p1020_mbg_pc_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+define_machine(p1020_utm_pc) {
+       .name                   = "P1020 UTM-PC",
+       .probe                  = p1020_utm_pc_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+define_machine(p1020_rdb_pc) {
+       .name                   = "P1020RDB-PC",
+       .probe                  = p1020_rdb_pc_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index 538bc3f..d8bd656 100644 (file)
@@ -32,9 +32,8 @@
 
 void __init p1010_rdb_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-         MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-         MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+         MPIC_SINGLE_DEST_CPU,
          0, 256, " OpenPIC  ");
 
        BUG_ON(mpic == NULL);
index b0984ad..0fe88e3 100644 (file)
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
+#define PMUXCR_ELBCDIU_MASK    0xc0000000
+#define PMUXCR_ELBCDIU_NOR16   0x80000000
+#define PMUXCR_ELBCDIU_DIU     0x40000000
+
 /*
  * Board-specific initialization of the DIU.  This code should probably be
  * executed when the DIU is opened, rather than in arch code, but the DIU
 #define CLKDVDR_PXCLK_MASK     0x00FF0000
 
 /* Some ngPIXIS register definitions */
+#define PX_CTL         3
+#define PX_BRDCFG0     8
+#define PX_BRDCFG1     9
+
+#define PX_BRDCFG0_ELBC_SPI_MASK       0xc0
+#define PX_BRDCFG0_ELBC_SPI_ELBC       0x00
+#define PX_BRDCFG0_ELBC_SPI_NULL       0xc0
+#define PX_BRDCFG0_ELBC_DIU            0x02
+
 #define PX_BRDCFG1_DVIEN       0x80
 #define PX_BRDCFG1_DFPEN       0x40
 #define PX_BRDCFG1_BACKLIGHT   0x20
 #define PX_BRDCFG1_DDCEN       0x10
 
+#define PX_CTL_ALTACC          0x80
+
 /*
  * DIU Area Descriptor
  *
@@ -133,44 +148,117 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,
  */
 static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
 {
-       struct device_node *np;
-       void __iomem *pixis;
-       u8 __iomem *brdcfg1;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
-       if (!np)
-               /* older device trees used "fsl,p1022ds-pixis" */
-               np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
-       if (!np) {
-               pr_err("p1022ds: missing ngPIXIS node\n");
+       struct device_node *guts_node;
+       struct device_node *indirect_node = NULL;
+       struct ccsr_guts_85xx __iomem *guts;
+       u8 __iomem *lbc_lcs0_ba = NULL;
+       u8 __iomem *lbc_lcs1_ba = NULL;
+       u8 b;
+
+       /* Map the global utilities registers. */
+       guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_node) {
+               pr_err("p1022ds: missing global utilties device node\n");
                return;
        }
 
-       pixis = of_iomap(np, 0);
-       if (!pixis) {
-               pr_err("p1022ds: could not map ngPIXIS registers\n");
-               return;
+       guts = of_iomap(guts_node, 0);
+       if (!guts) {
+               pr_err("p1022ds: could not map global utilties device\n");
+               goto exit;
        }
-       brdcfg1 = pixis + 9;    /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+       indirect_node = of_find_compatible_node(NULL, NULL,
+                                            "fsl,p1022ds-indirect-pixis");
+       if (!indirect_node) {
+               pr_err("p1022ds: missing pixis indirect mode node\n");
+               goto exit;
+       }
+
+       lbc_lcs0_ba = of_iomap(indirect_node, 0);
+       if (!lbc_lcs0_ba) {
+               pr_err("p1022ds: could not map localbus chip select 0\n");
+               goto exit;
+       }
+
+       lbc_lcs1_ba = of_iomap(indirect_node, 1);
+       if (!lbc_lcs1_ba) {
+               pr_err("p1022ds: could not map localbus chip select 1\n");
+               goto exit;
+       }
+
+       /* Make sure we're in indirect mode first. */
+       if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
+           PMUXCR_ELBCDIU_DIU) {
+               struct device_node *pixis_node;
+               void __iomem *pixis;
+
+               pixis_node =
+                       of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga");
+               if (!pixis_node) {
+                       pr_err("p1022ds: missing pixis node\n");
+                       goto exit;
+               }
+
+               pixis = of_iomap(pixis_node, 0);
+               of_node_put(pixis_node);
+               if (!pixis) {
+                       pr_err("p1022ds: could not map pixis registers\n");
+                       goto exit;
+               }
+
+               /* Enable indirect PIXIS mode.  */
+               setbits8(pixis + PX_CTL, PX_CTL_ALTACC);
+               iounmap(pixis);
+
+               /* Switch the board mux to the DIU */
+               out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */
+               b = in_8(lbc_lcs1_ba);
+               b |= PX_BRDCFG0_ELBC_DIU;
+               out_8(lbc_lcs1_ba, b);
+
+               /* Set the chip mux to DIU mode. */
+               clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK,
+                               PMUXCR_ELBCDIU_DIU);
+               in_be32(&guts->pmuxcr);
+       }
+
 
        switch (port) {
        case FSL_DIU_PORT_DVI:
-               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
                /* Enable the DVI port, disable the DFP and the backlight */
-               clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
-                            PX_BRDCFG1_DVIEN);
+               out_8(lbc_lcs0_ba, PX_BRDCFG1);
+               b = in_8(lbc_lcs1_ba);
+               b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
+               b |= PX_BRDCFG1_DVIEN;
+               out_8(lbc_lcs1_ba, b);
                break;
        case FSL_DIU_PORT_LVDS:
-               printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
+               /*
+                * LVDS also needs backlight enabled, otherwise the display
+                * will be blank.
+                */
                /* Enable the DFP port, disable the DVI and the backlight */
-               clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
-                            PX_BRDCFG1_DFPEN);
+               out_8(lbc_lcs0_ba, PX_BRDCFG1);
+               b = in_8(lbc_lcs1_ba);
+               b &= ~PX_BRDCFG1_DVIEN;
+               b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT;
+               out_8(lbc_lcs1_ba, b);
                break;
        default:
                pr_err("p1022ds: unsupported monitor port %i\n", port);
        }
 
-       iounmap(pixis);
+exit:
+       if (lbc_lcs1_ba)
+               iounmap(lbc_lcs1_ba);
+       if (lbc_lcs0_ba)
+               iounmap(lbc_lcs0_ba);
+       if (guts)
+               iounmap(guts);
+
+       of_node_put(indirect_node);
+       of_node_put(guts_node);
 }
 
 /**
@@ -242,15 +330,56 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 void __init p1022_ds_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-               MPIC_WANTS_RESET |
-               MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                MPIC_SINGLE_DEST_CPU,
                0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
 }
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Disables a node in the device tree.
+ *
+ * This function is called before kmalloc() is available, so the 'new' object
+ * should be allocated in the global area.  The easiest way is to do that is
+ * to allocate one static local variable for each call to this function.
+ */
+static void __init disable_one_node(struct device_node *np, struct property *new)
+{
+       struct property *old;
+
+       old = of_find_property(np, new->name, NULL);
+       if (old)
+               prom_update_property(np, new, old);
+       else
+               prom_add_property(np, new);
+}
+
+/* TRUE if there is a "video=fslfb" command-line parameter. */
+static bool fslfb;
+
+/*
+ * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to
+ * true if we find it.
+ *
+ * We need to use early_param() instead of __setup() because the normal
+ * __setup() gets called to late.  However, early_param() gets called very
+ * early, before the device tree is unflattened, so all we can do now is set a
+ * global variable.  Later on, p1022_ds_setup_arch() will use that variable
+ * to determine if we need to update the device tree.
+ */
+static int __init early_video_setup(char *options)
+{
+       fslfb = (strncmp(options, "fslfb:", 6) == 0);
+
+       return 0;
+}
+early_param("video", early_video_setup);
+
+#endif
+
 /*
  * Setup the architecture
  */
@@ -288,6 +417,34 @@ static void __init p1022_ds_setup_arch(void)
        diu_ops.set_monitor_port        = p1022ds_set_monitor_port;
        diu_ops.set_pixel_clock         = p1022ds_set_pixel_clock;
        diu_ops.valid_monitor_port      = p1022ds_valid_monitor_port;
+
+       /*
+        * Disable the NOR flash node if there is video=fslfb... command-line
+        * parameter.  When the DIU is active, NOR flash is unavailable, so we
+        * have to disable the node before the MTD driver loads.
+        */
+       if (fslfb) {
+               struct device_node *np =
+                       of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
+
+               if (np) {
+                       np = of_find_compatible_node(np, NULL, "cfi-flash");
+                       if (np) {
+                               static struct property nor_status = {
+                                       .name = "status",
+                                       .value = "disabled",
+                                       .length = sizeof("disabled"),
+                               };
+
+                               pr_info("p1022ds: disabling %s node",
+                                       np->full_name);
+                               disable_one_node(np, &nor_status);
+                               of_node_put(np);
+                       }
+               }
+
+       }
+
 #endif
 
        mpc85xx_smp_init();
index d951e70..6b07398 100644 (file)
@@ -93,9 +93,8 @@ machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices);
 
 static void __init mpc85xx_rds_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-               MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-               MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+               MPIC_SINGLE_DEST_CPU,
                0, 256, " OpenPIC  ");
 
        BUG_ON(mpic == NULL);
index 184a507..1677b8a 100644 (file)
@@ -54,8 +54,7 @@ static int sbc_rev;
 
 static void __init sbc8548_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 940752e..3c3bbcc 100644 (file)
@@ -41,8 +41,7 @@
 
 static void __init sbc8560_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 18f6359..b719192 100644 (file)
@@ -48,8 +48,7 @@ static void __init socrates_pic_init(void)
 {
        struct device_node *np;
 
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index e9e5234..27ca3a7 100644 (file)
@@ -48,8 +48,7 @@
 
 static void __init stx_gp3_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index bf7c89f..d7504ce 100644 (file)
@@ -47,7 +47,7 @@
 static void __init tqm85xx_pic_init(void)
 {
        struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+                       MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 3a69f8b..503c215 100644 (file)
@@ -43,9 +43,7 @@
 
 void __init xes_mpc85xx_pic_init(void)
 {
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                         MPIC_WANTS_RESET |
-                         MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        mpic_init(mpic);
index 8d6599d..7a6279e 100644 (file)
@@ -39,6 +39,7 @@ config GEF_PPC9A
        select MMIO_NVRAM
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
+       select GE_FPGA
        help
          This option enables support for the GE PPC9A.
 
@@ -48,6 +49,7 @@ config GEF_SBC310
        select MMIO_NVRAM
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
+       select GE_FPGA
        help
          This option enables support for the GE SBC310.
 
@@ -57,6 +59,7 @@ config GEF_SBC610
        select MMIO_NVRAM
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
+       select GE_FPGA
        select HAS_RAPIDIO
        help
          This option enables support for the GE SBC610.
index 4b0d7b1..ede815d 100644 (file)
@@ -7,7 +7,6 @@ obj-$(CONFIG_SMP)               += mpc86xx_smp.o
 obj-$(CONFIG_MPC8641_HPCN)     += mpc86xx_hpcn.o
 obj-$(CONFIG_SBC8641D)         += sbc8641d.o
 obj-$(CONFIG_MPC8610_HPCD)     += mpc8610_hpcd.o
-gef-gpio-$(CONFIG_GPIOLIB)     += gef_gpio.o
-obj-$(CONFIG_GEF_SBC610)       += gef_sbc610.o gef_pic.o $(gef-gpio-y)
-obj-$(CONFIG_GEF_SBC310)       += gef_sbc310.o gef_pic.o $(gef-gpio-y)
-obj-$(CONFIG_GEF_PPC9A)                += gef_ppc9a.o gef_pic.o $(gef-gpio-y)
+obj-$(CONFIG_GEF_SBC610)       += gef_sbc610.o
+obj-$(CONFIG_GEF_SBC310)       += gef_sbc310.o
+obj-$(CONFIG_GEF_PPC9A)                += gef_ppc9a.o
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
deleted file mode 100644 (file)
index 2a70336..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Driver for GE FPGA based GPIO
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- *
- * 2008 (c) GE Intelligent Platforms Embedded Systems, 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.
- */
-
-/* TODO
- *
- * Configuration of output modes (totem-pole/open-drain)
- * Interrupt configuration - interrupts are always generated the FPGA relies on
- *     the I/O interrupt controllers mask to stop them propergating
- */
-
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#define GEF_GPIO_DIRECT                0x00
-#define GEF_GPIO_IN            0x04
-#define GEF_GPIO_OUT           0x08
-#define GEF_GPIO_TRIG          0x0C
-#define GEF_GPIO_POLAR_A       0x10
-#define GEF_GPIO_POLAR_B       0x14
-#define GEF_GPIO_INT_STAT      0x18
-#define GEF_GPIO_OVERRUN       0x1C
-#define GEF_GPIO_MODE          0x20
-
-static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
-{
-       unsigned int data;
-
-       data = ioread32be(reg);
-       /* value: 0=low; 1=high */
-       if (value & 0x1)
-               data = data | (0x1 << offset);
-       else
-               data = data & ~(0x1 << offset);
-
-       iowrite32be(data, reg);
-}
-
-
-static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
-{
-       unsigned int data;
-       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-       data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
-       data = data | (0x1 << offset);
-       iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
-       return 0;
-}
-
-static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
-{
-       unsigned int data;
-       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-       /* Set direction before switching to input */
-       _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-
-       data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
-       data = data & ~(0x1 << offset);
-       iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
-       return 0;
-}
-
-static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       unsigned int data;
-       int state = 0;
-       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-       data = ioread32be(mmchip->regs + GEF_GPIO_IN);
-       state = (int)((data >> offset) & 0x1);
-
-       return state;
-}
-
-static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
-       _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-}
-
-static int __init gef_gpio_init(void)
-{
-       struct device_node *np;
-       int retval;
-       struct of_mm_gpio_chip *gef_gpio_chip;
-
-       for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
-
-               pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
-               /* Allocate chip structure */
-               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
-               if (!gef_gpio_chip) {
-                       pr_err("%s: Unable to allocate structure\n",
-                               np->full_name);
-                       continue;
-               }
-
-               /* Setup pointers to chip functions */
-               gef_gpio_chip->gc.of_gpio_n_cells = 2;
-               gef_gpio_chip->gc.ngpio = 19;
-               gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
-               gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
-               gef_gpio_chip->gc.get = gef_gpio_get;
-               gef_gpio_chip->gc.set = gef_gpio_set;
-
-               /* This function adds a memory mapped GPIO chip */
-               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
-               if (retval) {
-                       kfree(gef_gpio_chip);
-                       pr_err("%s: Unable to add GPIO\n", np->full_name);
-               }
-       }
-
-       for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
-
-               pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
-               /* Allocate chip structure */
-               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
-               if (!gef_gpio_chip) {
-                       pr_err("%s: Unable to allocate structure\n",
-                               np->full_name);
-                       continue;
-               }
-
-               /* Setup pointers to chip functions */
-               gef_gpio_chip->gc.of_gpio_n_cells = 2;
-               gef_gpio_chip->gc.ngpio = 6;
-               gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
-               gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
-               gef_gpio_chip->gc.get = gef_gpio_get;
-               gef_gpio_chip->gc.set = gef_gpio_set;
-
-               /* This function adds a memory mapped GPIO chip */
-               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
-               if (retval) {
-                       kfree(gef_gpio_chip);
-                       pr_err("%s: Unable to add GPIO\n", np->full_name);
-               }
-       }
-
-       return 0;
-};
-arch_initcall(gef_gpio_init);
-
-MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
-MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
deleted file mode 100644 (file)
index af3fd69..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Interrupt handling for GE FPGA based PIC
- *
- * Author: Martyn Welch <martyn.welch@ge.com>
- *
- * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/irq.h>
-
-#include "gef_pic.h"
-
-#define DEBUG
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
-#else
-#define DBG(fmt...) do { } while (0)
-#endif
-
-#define GEF_PIC_NUM_IRQS       32
-
-/* Interrupt Controller Interface Registers */
-#define GEF_PIC_INTR_STATUS    0x0000
-
-#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
-#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
-#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
-
-#define GEF_PIC_MCP_MASK(cpu)  (0x0018 + (0x4 * cpu))
-#define GEF_PIC_CPU0_MCP_MASK  GEF_PIC_MCP_MASK(0)
-#define GEF_PIC_CPU1_MCP_MASK  GEF_PIC_MCP_MASK(1)
-
-
-static DEFINE_RAW_SPINLOCK(gef_pic_lock);
-
-static void __iomem *gef_pic_irq_reg_base;
-static struct irq_domain *gef_pic_irq_host;
-static int gef_pic_cascade_irq;
-
-/*
- * Interrupt Controller Handling
- *
- * The interrupt controller handles interrupts for most on board interrupts,
- * apart from PCI interrupts. For example on SBC610:
- *
- * 17:31 RO Reserved
- * 16    RO PCI Express Doorbell 3 Status
- * 15    RO PCI Express Doorbell 2 Status
- * 14    RO PCI Express Doorbell 1 Status
- * 13    RO PCI Express Doorbell 0 Status
- * 12    RO Real Time Clock Interrupt Status
- * 11    RO Temperature Interrupt Status
- * 10    RO Temperature Critical Interrupt Status
- * 9     RO Ethernet PHY1 Interrupt Status
- * 8     RO Ethernet PHY3 Interrupt Status
- * 7     RO PEX8548 Interrupt Status
- * 6     RO Reserved
- * 5     RO Watchdog 0 Interrupt Status
- * 4     RO Watchdog 1 Interrupt Status
- * 3     RO AXIS Message FIFO A Interrupt Status
- * 2     RO AXIS Message FIFO B Interrupt Status
- * 1     RO AXIS Message FIFO C Interrupt Status
- * 0     RO AXIS Message FIFO D Interrupt Status
- *
- * Interrupts can be forwarded to one of two output lines. Nothing
- * clever is done, so if the masks are incorrectly set, a single input
- * interrupt could generate interrupts on both output lines!
- *
- * The dual lines are there to allow the chained interrupts to be easily
- * passed into two different cores. We currently do not use this functionality
- * in this driver.
- *
- * Controller can also be configured to generate Machine checks (MCP), again on
- * two lines, to be attached to two different cores. It is suggested that these
- * should be masked out.
- */
-
-void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned int cascade_irq;
-
-       /*
-        * See if we actually have an interrupt, call generic handling code if
-        * we do.
-        */
-       cascade_irq = gef_pic_get_irq();
-
-       if (cascade_irq != NO_IRQ)
-               generic_handle_irq(cascade_irq);
-
-       chip->irq_eoi(&desc->irq_data);
-}
-
-static void gef_pic_mask(struct irq_data *d)
-{
-       unsigned long flags;
-       unsigned int hwirq = irqd_to_hwirq(d);
-       u32 mask;
-
-       raw_spin_lock_irqsave(&gef_pic_lock, flags);
-       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-       mask &= ~(1 << hwirq);
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
-       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-}
-
-static void gef_pic_mask_ack(struct irq_data *d)
-{
-       /* Don't think we actually have to do anything to ack an interrupt,
-        * we just need to clear down the devices interrupt and it will go away
-        */
-       gef_pic_mask(d);
-}
-
-static void gef_pic_unmask(struct irq_data *d)
-{
-       unsigned long flags;
-       unsigned int hwirq = irqd_to_hwirq(d);
-       u32 mask;
-
-       raw_spin_lock_irqsave(&gef_pic_lock, flags);
-       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-       mask |= (1 << hwirq);
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
-       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-}
-
-static struct irq_chip gef_pic_chip = {
-       .name           = "gefp",
-       .irq_mask       = gef_pic_mask,
-       .irq_mask_ack   = gef_pic_mask_ack,
-       .irq_unmask     = gef_pic_unmask,
-};
-
-
-/* When an interrupt is being configured, this call allows some flexibilty
- * in deciding which irq_chip structure is used
- */
-static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
-                         irq_hw_number_t hwirq)
-{
-       /* All interrupts are LEVEL sensitive */
-       irq_set_status_flags(virq, IRQ_LEVEL);
-       irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
-
-       return 0;
-}
-
-static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
-                           const u32 *intspec, unsigned int intsize,
-                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-{
-
-       *out_hwirq = intspec[0];
-       if (intsize > 1)
-               *out_flags = intspec[1];
-       else
-               *out_flags = IRQ_TYPE_LEVEL_HIGH;
-
-       return 0;
-}
-
-static const struct irq_domain_ops gef_pic_host_ops = {
-       .map    = gef_pic_host_map,
-       .xlate  = gef_pic_host_xlate,
-};
-
-
-/*
- * Initialisation of PIC, this should be called in BSP
- */
-void __init gef_pic_init(struct device_node *np)
-{
-       unsigned long flags;
-
-       /* Map the devices registers into memory */
-       gef_pic_irq_reg_base = of_iomap(np, 0);
-
-       raw_spin_lock_irqsave(&gef_pic_lock, flags);
-
-       /* Initialise everything as masked. */
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
-
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
-       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
-
-       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
-
-       /* Map controller */
-       gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
-       if (gef_pic_cascade_irq == NO_IRQ) {
-               printk(KERN_ERR "SBC610: failed to map cascade interrupt");
-               return;
-       }
-
-       /* Setup an irq_domain structure */
-       gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
-                                         &gef_pic_host_ops, NULL);
-       if (gef_pic_irq_host == NULL)
-               return;
-
-       /* Chain with parent controller */
-       irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
-}
-
-/*
- * This is called when we receive an interrupt with apparently comes from this
- * chip - check, returning the highest interrupt generated or return NO_IRQ
- */
-unsigned int gef_pic_get_irq(void)
-{
-       u32 cause, mask, active;
-       unsigned int virq = NO_IRQ;
-       int hwirq;
-
-       cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
-
-       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
-
-       active = cause & mask;
-
-       if (active) {
-               for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
-                       if (active & (0x1 << hwirq))
-                               break;
-               }
-               virq = irq_linear_revmap(gef_pic_irq_host,
-                       (irq_hw_number_t)hwirq);
-       }
-
-       return virq;
-}
-
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h
deleted file mode 100644 (file)
index 6149916..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __GEF_PIC_H__
-#define __GEF_PIC_H__
-
-#include <linux/init.h>
-
-void gef_pic_cascade(unsigned int, struct irq_desc *);
-unsigned int gef_pic_get_irq(void);
-void gef_pic_init(struct device_node *);
-
-#endif /* __GEF_PIC_H__ */
-
index 60ce07e..ed58b6c 100644 (file)
@@ -37,9 +37,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
index 3ecee25..710db69 100644 (file)
@@ -37,9 +37,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
index 5090d60..4a13d2f 100644 (file)
@@ -37,9 +37,9 @@
 
 #include <sysdev/fsl_pci.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/ge/ge_pic.h>
 
 #include "mpc86xx.h"
-#include "gef_pic.h"
 
 #undef DEBUG
 
index 52bbfa0..22cc357 100644 (file)
@@ -37,9 +37,8 @@ void __init mpc86xx_init_irq(void)
        int cascade_irq;
 #endif
 
-       struct mpic *mpic = mpic_alloc(NULL, 0,
-                       MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
-                       MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+                       MPIC_SINGLE_DEST_CPU,
                        0, 256, " MPIC     ");
        BUG_ON(mpic == NULL);
 
index 0cfb46d..a35ca44 100644 (file)
@@ -2,7 +2,6 @@ menu "Platform support"
 
 source "arch/powerpc/platforms/powernv/Kconfig"
 source "arch/powerpc/platforms/pseries/Kconfig"
-source "arch/powerpc/platforms/iseries/Kconfig"
 source "arch/powerpc/platforms/chrp/Kconfig"
 source "arch/powerpc/platforms/512x/Kconfig"
 source "arch/powerpc/platforms/52xx/Kconfig"
@@ -87,6 +86,14 @@ config MPIC_WEIRD
        bool
        default n
 
+config MPIC_MSGR
+       bool "MPIC message register support"
+       depends on MPIC
+       default n
+       help
+         Enables support for the MPIC message registers.  These
+         registers are used for inter-processor communication.
+
 config PPC_I8259
        bool
        default n
@@ -138,7 +145,7 @@ config MPIC_BROKEN_REGREAD
          of the register contents in software.
 
 config IBMVIO
-       depends on PPC_PSERIES || PPC_ISERIES
+       depends on PPC_PSERIES
        bool
        default y
 
index 2635a22..879b4a4 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_FSL_SOC_BOOKE)   += 85xx/
 obj-$(CONFIG_PPC_86xx)         += 86xx/
 obj-$(CONFIG_PPC_POWERNV)      += powernv/
 obj-$(CONFIG_PPC_PSERIES)      += pseries/
-obj-$(CONFIG_PPC_ISERIES)      += iseries/
 obj-$(CONFIG_PPC_MAPLE)                += maple/
 obj-$(CONFIG_PPC_PASEMI)       += pasemi/
 obj-$(CONFIG_PPC_CELL)         += cell/
index 62002a7..fa3e294 100644 (file)
@@ -197,7 +197,8 @@ static void __init mpic_init_IRQ(void)
                /* The MPIC driver will get everything it needs from the
                 * device-tree, just pass 0 to all arguments
                 */
-               mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC     ");
+               mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET,
+                               0, 0, " MPIC     ");
                if (mpic == NULL)
                        continue;
                mpic_init(mpic);
index d4a094c..1d75c92 100644 (file)
@@ -646,6 +646,7 @@ long spufs_create(struct path *path, struct dentry *dentry,
 
 out:
        mutex_unlock(&path->dentry->d_inode->i_mutex);
+       dput(dentry);
        return ret;
 }
 
@@ -757,9 +758,9 @@ spufs_create_root(struct super_block *sb, void *data)
                goto out_iput;
 
        ret = -ENOMEM;
-       sb->s_root = d_alloc_root(inode);
+       sb->s_root = d_make_root(inode);
        if (!sb->s_root)
-               goto out_iput;
+               goto out;
 
        return 0;
 out_iput:
@@ -828,19 +829,19 @@ static int __init spufs_init(void)
        ret = spu_sched_init();
        if (ret)
                goto out_cache;
-       ret = register_filesystem(&spufs_type);
+       ret = register_spu_syscalls(&spufs_calls);
        if (ret)
                goto out_sched;
-       ret = register_spu_syscalls(&spufs_calls);
+       ret = register_filesystem(&spufs_type);
        if (ret)
-               goto out_fs;
+               goto out_syscalls;
 
        spufs_init_isolated_loader();
 
        return 0;
 
-out_fs:
-       unregister_filesystem(&spufs_type);
+out_syscalls:
+       unregister_spu_syscalls(&spufs_calls);
 out_sched:
        spu_sched_exit();
 out_cache:
index 8591bb6..5665dcc 100644 (file)
@@ -70,8 +70,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
        ret = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                ret = spufs_create(&path, dentry, flags, mode, neighbor);
-               mutex_unlock(&path.dentry->d_inode->i_mutex);
-               dput(dentry);
                path_put(&path);
        }
 
index f1f17bb..c665d7d 100644 (file)
@@ -435,7 +435,8 @@ static void __init chrp_find_openpic(void)
        if (len > 1)
                isu_size = iranges[3];
 
-       chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC    ");
+       chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET,
+                       isu_size, 0, " MPIC    ");
        if (chrp_mpic == NULL) {
                printk(KERN_ERR "Failed to allocate MPIC structure\n");
                goto bail;
index 9cfcf20..ab51b21 100644 (file)
@@ -154,11 +154,9 @@ static void __init holly_init_IRQ(void)
        struct device_node *cascade_node = NULL;
 #endif
 
-       mpic = mpic_alloc(NULL, 0,
-                       MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+       mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                        MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
-                       24,
-                       NR_IRQS-4, /* num_sources used */
+                       24, 0,
                        "Tsi108_PIC");
 
        BUG_ON(mpic == NULL);
index bcfad92..455e7c0 100644 (file)
@@ -82,8 +82,7 @@ static void __init linkstation_init_IRQ(void)
 {
        struct mpic *mpic;
 
-       mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET,
-                       4, 32, " EPIC     ");
+       mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC     ");
        BUG_ON(mpic == NULL);
 
        /* PCI IRQs */
index f3350d7..74ccce3 100644 (file)
@@ -108,11 +108,9 @@ static void __init mpc7448_hpc2_init_IRQ(void)
        struct device_node *cascade_node = NULL;
 #endif
 
-       mpic = mpic_alloc(NULL, 0,
-                       MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+       mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
                        MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
-                       24,
-                       NR_IRQS-4, /* num_sources used */
+                       24, 0,
                        "Tsi108_PIC");
 
        BUG_ON(mpic == NULL);
index afa6388..e0ed3c7 100644 (file)
@@ -84,8 +84,7 @@ static void __init storcenter_init_IRQ(void)
 {
        struct mpic *mpic;
 
-       mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET,
-                       16, 32, " OpenPIC  ");
+       mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC  ");
        BUG_ON(mpic == NULL);
 
        /*
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
deleted file mode 100644 (file)
index 63835e0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-config PPC_ISERIES
-       bool "IBM Legacy iSeries"
-       depends on PPC64 && PPC_BOOK3S
-       select OF_DYNAMIC
-       select PPC_SMP_MUXED_IPI
-       select PPC_INDIRECT_PIO
-       select PPC_INDIRECT_MMIO
-       select PPC_PCI_CHOICE if EXPERT
-
-menu "iSeries device drivers"
-       depends on PPC_ISERIES
-
-config VIODASD
-       tristate "iSeries Virtual I/O disk support"
-       depends on BLOCK
-       select VIOPATH
-       help
-         If you are running on an iSeries system and you want to use
-         virtual disks created and managed by OS/400, say Y.
-
-config VIOCD
-       tristate "iSeries Virtual I/O CD support"
-       depends on BLOCK
-       select VIOPATH
-       help
-         If you are running Linux on an IBM iSeries system and you want to
-         read a CD drive owned by OS/400, say Y here.
-
-config VIOTAPE
-       tristate "iSeries Virtual Tape Support"
-       select VIOPATH
-       help
-         If you are running Linux on an iSeries system and you want Linux
-         to read and/or write a tape drive owned by OS/400, say Y here.
-
-endmenu
-
-config VIOPATH
-       bool
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
deleted file mode 100644 (file)
index a7602b1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-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 \
-       hvcall.o proc.o htab.o iommu.o misc.o irq.o
-obj-$(CONFIG_PCI) += pci.o
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_VIOPATH) += viopath.o vio.o
-obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h
deleted file mode 100644 (file)
index 8d95fe4..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _PLATFORMS_ISERIES_CALL_HPT_H
-#define _PLATFORMS_ISERIES_CALL_HPT_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/mmu.h>
-
-#define HvCallHptGetHptAddress         HvCallHpt +  0
-#define HvCallHptGetHptPages           HvCallHpt +  1
-#define HvCallHptSetPp                 HvCallHpt +  5
-#define HvCallHptSetSwBits             HvCallHpt +  6
-#define HvCallHptUpdate                        HvCallHpt +  7
-#define HvCallHptInvalidateNoSyncICache        HvCallHpt +  8
-#define HvCallHptGet                   HvCallHpt + 11
-#define HvCallHptFindNextValid         HvCallHpt + 12
-#define HvCallHptFindValid             HvCallHpt + 13
-#define HvCallHptAddValidate           HvCallHpt + 16
-#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18
-
-
-static inline u64 HvCallHpt_getHptAddress(void)
-{
-       return HvCall0(HvCallHptGetHptAddress);
-}
-
-static inline u64 HvCallHpt_getHptPages(void)
-{
-       return HvCall0(HvCallHptGetHptPages);
-}
-
-static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
-{
-       HvCall2(HvCallHptSetPp, hpteIndex, value);
-}
-
-static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)
-{
-       HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);
-}
-
-static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
-{
-       HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
-}
-
-static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,
-               u8 bitsoff)
-{
-       u64 compressedStatus;
-
-       compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet,
-                       hpteIndex, bitson, bitsoff, 1);
-       HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
-       return compressedStatus;
-}
-
-static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)
-{
-       return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
-}
-
-static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex,
-               u8 bitson, u8 bitsoff)
-{
-       return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,
-                       bitson, bitsoff);
-}
-
-static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)
-{
-       HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
-}
-
-static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit,
-                                        struct hash_pte *hpte)
-{
-       HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r);
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */
diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h
deleted file mode 100644 (file)
index dbdf698..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Provides the Hypervisor PCI calls for iSeries Linux Parition.
- * Copyright (C) 2001  <Wayne G Holm> <IBM 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; 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
- *
- * Change Activity:
- *   Created, Jan 9, 2001
- */
-
-#ifndef _PLATFORMS_ISERIES_CALL_PCI_H
-#define _PLATFORMS_ISERIES_CALL_PCI_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-/*
- * DSA == Direct Select Address
- * this struct must be 64 bits in total
- */
-struct HvCallPci_DsaAddr {
-       u16             busNumber;              /* PHB index? */
-       u8              subBusNumber;           /* PCI bus number? */
-       u8              deviceId;               /* device and function? */
-       u8              barNumber;
-       u8              reserved[3];
-};
-
-union HvDsaMap {
-       u64     DsaAddr;
-       struct HvCallPci_DsaAddr Dsa;
-};
-
-struct HvCallPci_LoadReturn {
-       u64             rc;
-       u64             value;
-};
-
-enum HvCallPci_DeviceType {
-       HvCallPci_NodeDevice    = 1,
-       HvCallPci_SpDevice      = 2,
-       HvCallPci_IopDevice     = 3,
-       HvCallPci_BridgeDevice  = 4,
-       HvCallPci_MultiFunctionDevice = 5,
-       HvCallPci_IoaDevice     = 6
-};
-
-
-struct HvCallPci_DeviceInfo {
-       u32     deviceType;             /* See DeviceType enum for values */
-};
-
-struct HvCallPci_BusUnitInfo {
-       u32     sizeReturned;           /* length of data returned */
-       u32     deviceType;             /* see DeviceType enum for values */
-};
-
-struct HvCallPci_BridgeInfo {
-       struct HvCallPci_BusUnitInfo busUnitInfo;  /* Generic bus unit info */
-       u8              subBusNumber;   /* Bus number of secondary bus */
-       u8              maxAgents;      /* Max idsels on secondary bus */
-        u8              maxSubBusNumber; /* Max Sub Bus */
-       u8              logicalSlotNumber; /* Logical Slot Number for IOA */
-};
-
-
-/*
- * Maximum BusUnitInfo buffer size.  Provided for clients so
- * they can allocate a buffer big enough for any type of bus
- * unit.  Increase as needed.
- */
-enum {HvCallPci_MaxBusUnitInfoSize = 128};
-
-struct HvCallPci_BarParms {
-       u64             vaddr;
-       u64             raddr;
-       u64             size;
-       u64             protectStart;
-       u64             protectEnd;
-       u64             relocationOffset;
-       u64             pciAddress;
-       u64             reserved[3];
-};
-
-enum HvCallPci_VpdType {
-       HvCallPci_BusVpd        = 1,
-       HvCallPci_BusAdapterVpd = 2
-};
-
-#define HvCallPciConfigLoad8           HvCallPci + 0
-#define HvCallPciConfigLoad16          HvCallPci + 1
-#define HvCallPciConfigLoad32          HvCallPci + 2
-#define HvCallPciConfigStore8          HvCallPci + 3
-#define HvCallPciConfigStore16         HvCallPci + 4
-#define HvCallPciConfigStore32         HvCallPci + 5
-#define HvCallPciEoi                   HvCallPci + 16
-#define HvCallPciGetBarParms           HvCallPci + 18
-#define HvCallPciMaskFisr              HvCallPci + 20
-#define HvCallPciUnmaskFisr            HvCallPci + 21
-#define HvCallPciSetSlotReset          HvCallPci + 25
-#define HvCallPciGetDeviceInfo         HvCallPci + 27
-#define HvCallPciGetCardVpd            HvCallPci + 28
-#define HvCallPciBarLoad8              HvCallPci + 40
-#define HvCallPciBarLoad16             HvCallPci + 41
-#define HvCallPciBarLoad32             HvCallPci + 42
-#define HvCallPciBarLoad64             HvCallPci + 43
-#define HvCallPciBarStore8             HvCallPci + 44
-#define HvCallPciBarStore16            HvCallPci + 45
-#define HvCallPciBarStore32            HvCallPci + 46
-#define HvCallPciBarStore64            HvCallPci + 47
-#define HvCallPciMaskInterrupts                HvCallPci + 48
-#define HvCallPciUnmaskInterrupts      HvCallPci + 49
-#define HvCallPciGetBusUnitInfo                HvCallPci + 50
-
-static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
-               u8 deviceId, u32 offset, u16 *value)
-{
-       struct HvCallPci_DsaAddr dsa;
-       struct HvCallPci_LoadReturn retVal;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumber;
-       dsa.subBusNumber = subBusNumber;
-       dsa.deviceId = deviceId;
-
-       HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);
-
-       *value = retVal.value;
-
-       return retVal.rc;
-}
-
-static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
-               u8 deviceId, u32 offset, u32 *value)
-{
-       struct HvCallPci_DsaAddr dsa;
-       struct HvCallPci_LoadReturn retVal;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumber;
-       dsa.subBusNumber = subBusNumber;
-       dsa.deviceId = deviceId;
-
-       HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
-
-       *value = retVal.value;
-
-       return retVal.rc;
-}
-
-static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
-               u8 deviceId, u32 offset, u8 value)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumber;
-       dsa.subBusNumber = subBusNumber;
-       dsa.deviceId = deviceId;
-
-       return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
-}
-
-static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm)
-{
-       struct HvCallPci_DsaAddr dsa;
-       struct HvCallPci_LoadReturn retVal;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);
-
-       return retVal.rc;
-}
-
-static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-       dsa.barNumber = barNumberParm;
-
-       return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u64 fisrMask)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u64 fisrMask)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm,
-               u8 deviceNumberParm, u64 parms, u32 sizeofParms)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceNumberParm << 4;
-
-       return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u64 interruptMask)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u64 interruptMask)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm,
-               u8 deviceIdParm, u64 parms, u32 sizeofParms)
-{
-       struct HvCallPci_DsaAddr dsa;
-
-       *((u64*)&dsa) = 0;
-
-       dsa.busNumber = busNumberParm;
-       dsa.subBusNumber = subBusParm;
-       dsa.deviceId = deviceIdParm;
-
-       return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms,
-                       sizeofParms);
-}
-
-static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm,
-               u16 sizeParm)
-{
-       u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,
-                       sizeParm, HvCallPci_BusVpd);
-       if (xRc == -1)
-               return -1;
-       else
-               return xRc & 0xFFFF;
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h
deleted file mode 100644 (file)
index c7e2516..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ISERIES_CALL_SM_H
-#define _ISERIES_CALL_SM_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-#define HvCallSmGet64BitsOfAccessMap   HvCallSm  + 11
-
-static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex,
-               u64 indexIntoBitMap)
-{
-       return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap);
-}
-
-#endif /* _ISERIES_CALL_SM_H */
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
deleted file mode 100644 (file)
index f0491cc..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- *    Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation
- *    Copyright (C) 2000-2004, IBM Corporation
- *
- *    Description:
- *      This file contains all the routines to build a flattened device
- *      tree for a legacy iSeries machine.
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#undef DEBUG
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_regs.h>
-#include <linux/pci_ids.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/if_ether.h>    /* ETH_ALEN */
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/lppaca.h>
-#include <asm/cputable.h>
-#include <asm/abs_addr.h>
-#include <asm/system.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/udbg.h>
-
-#include "processor_vpd.h"
-#include "call_hpt.h"
-#include "call_pci.h"
-#include "pci.h"
-#include "it_exp_vpd_panel.h"
-#include "naca.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/*
- * These are created by the linker script at the start and end
- * of the section containing all the strings marked with the DS macro.
- */
-extern char __dt_strings_start[];
-extern char __dt_strings_end[];
-
-#define DS(s)  ({      \
-       static const char __s[] __attribute__((section(".dt_strings"))) = s; \
-       __s;            \
-})
-
-struct iseries_flat_dt {
-       struct boot_param_header header;
-       u64 reserve_map[2];
-};
-
-static void * __initdata dt_data;
-
-/*
- * Putting these strings here keeps them out of the .dt_strings section
- * that we capture for the strings blob of the flattened device tree.
- */
-static char __initdata device_type_cpu[] = "cpu";
-static char __initdata device_type_memory[] = "memory";
-static char __initdata device_type_serial[] = "serial";
-static char __initdata device_type_network[] = "network";
-static char __initdata device_type_pci[] = "pci";
-static char __initdata device_type_vdevice[] = "vdevice";
-static char __initdata device_type_vscsi[] = "vscsi";
-
-
-/* EBCDIC to ASCII conversion routines */
-
-static unsigned char __init e2a(unsigned char x)
-{
-       switch (x) {
-       case 0x81 ... 0x89:
-               return x - 0x81 + 'a';
-       case 0x91 ... 0x99:
-               return x - 0x91 + 'j';
-       case 0xA2 ... 0xA9:
-               return x - 0xA2 + 's';
-       case 0xC1 ... 0xC9:
-               return x - 0xC1 + 'A';
-       case 0xD1 ... 0xD9:
-               return x - 0xD1 + 'J';
-       case 0xE2 ... 0xE9:
-               return x - 0xE2 + 'S';
-       case 0xF0 ... 0xF9:
-               return x - 0xF0 + '0';
-       }
-       return ' ';
-}
-
-static unsigned char * __init strne2a(unsigned char *dest,
-               const unsigned char *src, size_t n)
-{
-       int i;
-
-       n = strnlen(src, n);
-
-       for (i = 0; i < n; i++)
-               dest[i] = e2a(src[i]);
-
-       return dest;
-}
-
-static struct iseries_flat_dt * __init dt_init(void)
-{
-       struct iseries_flat_dt *dt;
-       unsigned long str_len;
-
-       str_len = __dt_strings_end - __dt_strings_start;
-       dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);
-       dt->header.off_mem_rsvmap =
-               offsetof(struct iseries_flat_dt, reserve_map);
-       dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
-       dt->header.off_dt_struct = dt->header.off_dt_strings
-               + ALIGN(str_len, 8);
-       dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
-       dt->header.dt_strings_size = str_len;
-
-       /* There is no notion of hardware cpu id on iSeries */
-       dt->header.boot_cpuid_phys = smp_processor_id();
-
-       memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
-                       str_len);
-
-       dt->header.magic = OF_DT_HEADER;
-       dt->header.version = 0x10;
-       dt->header.last_comp_version = 0x10;
-
-       dt->reserve_map[0] = 0;
-       dt->reserve_map[1] = 0;
-
-       return dt;
-}
-
-static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
-{
-       *((u32 *)dt_data) = value;
-       dt_data += sizeof(u32);
-}
-
-#ifdef notyet
-static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
-{
-       *((u64 *)dt_data) = value;
-       dt_data += sizeof(u64);
-}
-#endif
-
-static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,
-               int len)
-{
-       memcpy(dt_data, data, len);
-       dt_data += ALIGN(len, 4);
-}
-
-static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
-{
-       dt_push_u32(dt, OF_DT_BEGIN_NODE);
-       dt_push_bytes(dt, name, strlen(name) + 1);
-}
-
-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-
-static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name,
-               const void *data, int len)
-{
-       unsigned long offset;
-
-       dt_push_u32(dt, OF_DT_PROP);
-
-       /* Length of the data */
-       dt_push_u32(dt, len);
-
-       offset = name - __dt_strings_start;
-
-       /* The offset of the properties name in the string blob. */
-       dt_push_u32(dt, (u32)offset);
-
-       /* The actual data. */
-       dt_push_bytes(dt, data, len);
-}
-#define dt_prop(dt, name, data, len)   __dt_prop((dt), DS(name), (data), (len))
-
-#define dt_prop_str(dt, name, data)    \
-       dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */
-
-static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
-               u32 data)
-{
-       __dt_prop(dt, name, &data, sizeof(u32));
-}
-#define dt_prop_u32(dt, name, data)    __dt_prop_u32((dt), DS(name), (data))
-
-static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt,
-               const char *name, u64 data)
-{
-       __dt_prop(dt, name, &data, sizeof(u64));
-}
-#define dt_prop_u64(dt, name, data)    __dt_prop_u64((dt), DS(name), (data))
-
-#define dt_prop_u64_list(dt, name, data, n)    \
-       dt_prop((dt), name, (data), sizeof(u64) * (n))
-
-#define dt_prop_u32_list(dt, name, data, n)    \
-       dt_prop((dt), name, (data), sizeof(u32) * (n))
-
-#define dt_prop_empty(dt, name)                dt_prop((dt), name, NULL, 0)
-
-static void __init dt_cpus(struct iseries_flat_dt *dt)
-{
-       unsigned char buf[32];
-       unsigned char *p;
-       unsigned int i, index;
-       struct IoHriProcessorVpd *d;
-       u32 pft_size[2];
-
-       /* yuck */
-       snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
-       p = strchr(buf, ' ');
-       if (!p) p = buf + strlen(buf);
-
-       dt_start_node(dt, "cpus");
-       dt_prop_u32(dt, "#address-cells", 1);
-       dt_prop_u32(dt, "#size-cells", 0);
-
-       pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */
-       pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
-
-       for (i = 0; i < NR_LPPACAS; i++) {
-               if (lppaca[i].dyn_proc_status >= 2)
-                       continue;
-
-               snprintf(p, 32 - (p - buf), "@%d", i);
-               dt_start_node(dt, buf);
-
-               dt_prop_str(dt, "device_type", device_type_cpu);
-
-               index = lppaca[i].dyn_hv_phys_proc_index;
-               d = &xIoHriProcessorVpd[index];
-
-               dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
-               dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
-
-               dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
-               dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
-
-               /* magic conversions to Hz copied from old code */
-               dt_prop_u32(dt, "clock-frequency",
-                       ((1UL << 34) * 1000000) / d->xProcFreq);
-               dt_prop_u32(dt, "timebase-frequency",
-                       ((1UL << 32) * 1000000) / d->xTimeBaseFreq);
-
-               dt_prop_u32(dt, "reg", i);
-
-               dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
-
-               dt_end_node(dt);
-       }
-
-       dt_end_node(dt);
-}
-
-static void __init dt_model(struct iseries_flat_dt *dt)
-{
-       char buf[16] = "IBM,";
-
-       /* N.B. lparcfg.c knows about the "IBM," prefixes ... */
-       /* "IBM," + mfgId[2:3] + systemSerial[1:5] */
-       strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
-       strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
-       buf[11] = '\0';
-       dt_prop_str(dt, "system-id", buf);
-
-       /* "IBM," + machineType[0:4] */
-       strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
-       buf[8] = '\0';
-       dt_prop_str(dt, "model", buf);
-
-       dt_prop_str(dt, "compatible", "IBM,iSeries");
-       dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());
-}
-
-static void __init dt_initrd(struct iseries_flat_dt *dt)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (naca.xRamDisk) {
-               dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk);
-               dt_prop_u64(dt, "linux,initrd-end",
-                       (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE);
-       }
-#endif
-}
-
-static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
-               const char *name, u32 reg, int unit,
-               const char *type, const char *compat, int end)
-{
-       char buf[32];
-
-       snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));
-       dt_start_node(dt, buf);
-       dt_prop_str(dt, "device_type", type);
-       if (compat)
-               dt_prop_str(dt, "compatible", compat);
-       dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));
-       if (unit >= 0)
-               dt_prop_u32(dt, "linux,unit_address", unit);
-       if (end)
-               dt_end_node(dt);
-}
-
-static void __init dt_vdevices(struct iseries_flat_dt *dt)
-{
-       u32 reg = 0;
-       HvLpIndexMap vlan_map;
-       int i;
-
-       dt_start_node(dt, "vdevice");
-       dt_prop_str(dt, "device_type", device_type_vdevice);
-       dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
-       dt_prop_u32(dt, "#address-cells", 1);
-       dt_prop_u32(dt, "#size-cells", 0);
-
-       dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,
-                       "IBM,iSeries-vty", 1);
-       reg++;
-
-       dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
-                       "IBM,v-scsi", 1);
-       reg++;
-
-       vlan_map = HvLpConfig_getVirtualLanIndexMap();
-       for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
-               unsigned char mac_addr[ETH_ALEN];
-
-               if ((vlan_map & (0x8000 >> i)) == 0)
-                       continue;
-               dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,
-                               "IBM,iSeries-l-lan", 0);
-               mac_addr[0] = 0x02;
-               mac_addr[1] = 0x01;
-               mac_addr[2] = 0xff;
-               mac_addr[3] = i;
-               mac_addr[4] = 0xff;
-               mac_addr[5] = HvLpConfig_getLpIndex_outline();
-               dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
-               dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
-               dt_prop_u32(dt, "max-frame-size", 9000);
-               dt_prop_u32(dt, "address-bits", 48);
-
-               dt_end_node(dt);
-       }
-
-       dt_end_node(dt);
-}
-
-struct pci_class_name {
-       u16 code;
-       const char *name;
-       const char *type;
-};
-
-static struct pci_class_name __initdata pci_class_name[] = {
-       { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
-};
-
-static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
-{
-       struct pci_class_name *cp;
-
-       for (cp = pci_class_name;
-                       cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
-               if (cp->code == class_code)
-                       return cp;
-       return NULL;
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
-               HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
-{
-       HvSubBusNumber sub_bus = bridge_info->subBusNumber;
-       u16 vendor_id;
-       u16 device_id;
-       u32 class_id;
-       int err;
-       char buf[32];
-       u32 reg[5];
-       int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
-       int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
-       HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
-       u8 devfn;
-       struct pci_class_name *cp;
-
-       /*
-        * Connect all functions of any device found.
-        */
-       for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
-               for (function = 0; function < 8; function++) {
-                       HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
-                                       function);
-                       err = HvCallXm_connectBusUnit(bus, sub_bus,
-                                       agent_id, 0);
-                       if (err) {
-                               if (err != 0x302)
-                                       DBG("connectBusUnit(%x, %x, %x) %x\n",
-                                               bus, sub_bus, agent_id, err);
-                               continue;
-                       }
-
-                       err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-                                       PCI_VENDOR_ID, &vendor_id);
-                       if (err) {
-                               DBG("ReadVendor(%x, %x, %x) %x\n",
-                                       bus, sub_bus, agent_id, err);
-                               continue;
-                       }
-                       err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-                                       PCI_DEVICE_ID, &device_id);
-                       if (err) {
-                               DBG("ReadDevice(%x, %x, %x) %x\n",
-                                       bus, sub_bus, agent_id, err);
-                               continue;
-                       }
-                       err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
-                                       PCI_CLASS_REVISION , &class_id);
-                       if (err) {
-                               DBG("ReadClass(%x, %x, %x) %x\n",
-                                       bus, sub_bus, agent_id, err);
-                               continue;
-                       }
-
-                       devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
-                                       function);
-                       cp = dt_find_pci_class_name(class_id >> 16);
-                       if (cp && cp->name)
-                               strncpy(buf, cp->name, sizeof(buf) - 1);
-                       else
-                               snprintf(buf, sizeof(buf), "pci%x,%x",
-                                               vendor_id, device_id);
-                       buf[sizeof(buf) - 1] = '\0';
-                       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                       "@%x", PCI_SLOT(devfn));
-                       buf[sizeof(buf) - 1] = '\0';
-                       if (function != 0)
-                               snprintf(buf + strlen(buf),
-                                       sizeof(buf) - strlen(buf),
-                                       ",%x", function);
-                       dt_start_node(dt, buf);
-                       reg[0] = (bus << 16) | (devfn << 8);
-                       reg[1] = 0;
-                       reg[2] = 0;
-                       reg[3] = 0;
-                       reg[4] = 0;
-                       dt_prop_u32_list(dt, "reg", reg, 5);
-                       if (cp && (cp->type || cp->name))
-                               dt_prop_str(dt, "device_type",
-                                       cp->type ? cp->type : cp->name);
-                       dt_prop_u32(dt, "vendor-id", vendor_id);
-                       dt_prop_u32(dt, "device-id", device_id);
-                       dt_prop_u32(dt, "class-code", class_id >> 8);
-                       dt_prop_u32(dt, "revision-id", class_id & 0xff);
-                       dt_prop_u32(dt, "linux,subbus", sub_bus);
-                       dt_prop_u32(dt, "linux,agent-id", agent_id);
-                       dt_prop_u32(dt, "linux,logical-slot-number",
-                                       bridge_info->logicalSlotNumber);
-                       dt_end_node(dt);
-
-               }
-       }
-}
-
-static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
-               HvSubBusNumber sub_bus, int id_sel)
-{
-       struct HvCallPci_BridgeInfo bridge_info;
-       HvAgentId agent_id;
-       int function;
-       int ret;
-
-       /* Note: hvSubBus and irq is always be 0 at this level! */
-       for (function = 0; function < 8; ++function) {
-               agent_id = ISERIES_PCI_AGENTID(id_sel, function);
-               ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
-               if (ret != 0) {
-                       if (ret != 0xb)
-                               DBG("connectBusUnit(%x, %x, %x) %x\n",
-                                               bus, sub_bus, agent_id, ret);
-                       continue;
-               }
-               DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",
-                               bus, id_sel, function, agent_id);
-               ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
-                               iseries_hv_addr(&bridge_info),
-                               sizeof(struct HvCallPci_BridgeInfo));
-               if (ret != 0)
-                       continue;
-               DBG("bridge info: type %x subbus %x "
-                       "maxAgents %x maxsubbus %x logslot %x\n",
-                       bridge_info.busUnitInfo.deviceType,
-                       bridge_info.subBusNumber,
-                       bridge_info.maxAgents,
-                       bridge_info.maxSubBusNumber,
-                       bridge_info.logicalSlotNumber);
-               if (bridge_info.busUnitInfo.deviceType ==
-                               HvCallPci_BridgeDevice)
-                       scan_bridge_slot(dt, bus, &bridge_info);
-               else
-                       DBG("PCI: Invalid Bridge Configuration(0x%02X)",
-                               bridge_info.busUnitInfo.deviceType);
-       }
-}
-
-static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
-{
-       struct HvCallPci_DeviceInfo dev_info;
-       const HvSubBusNumber sub_bus = 0;       /* EADs is always 0. */
-       int err;
-       int id_sel;
-       const int max_agents = 8;
-
-       /*
-        * Probe for EADs Bridges
-        */
-       for (id_sel = 1; id_sel < max_agents; ++id_sel) {
-               err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
-                               iseries_hv_addr(&dev_info),
-                               sizeof(struct HvCallPci_DeviceInfo));
-               if (err) {
-                       if (err != 0x302)
-                               DBG("getDeviceInfo(%x, %x, %x) %x\n",
-                                               bus, sub_bus, id_sel, err);
-                       continue;
-               }
-               if (dev_info.deviceType != HvCallPci_NodeDevice) {
-                       DBG("PCI: Invalid System Configuration"
-                                       "(0x%02X) for bus 0x%02x id 0x%02x.\n",
-                                       dev_info.deviceType, bus, id_sel);
-                       continue;
-               }
-               scan_bridge(dt, bus, sub_bus, id_sel);
-       }
-}
-
-static void __init dt_pci_devices(struct iseries_flat_dt *dt)
-{
-       HvBusNumber bus;
-       char buf[32];
-       u32 buses[2];
-       int phb_num = 0;
-
-       /* Check all possible buses. */
-       for (bus = 0; bus < 256; bus++) {
-               int err = HvCallXm_testBus(bus);
-
-               if (err) {
-                       /*
-                        * Check for Unexpected Return code, a clue that
-                        * something has gone wrong.
-                        */
-                       if (err != 0x0301)
-                               DBG("Unexpected Return on Probe(0x%02X) "
-                                               "0x%04X\n", bus, err);
-                       continue;
-               }
-               DBG("bus %d appears to exist\n", bus);
-               snprintf(buf, 32, "pci@%d", phb_num);
-               dt_start_node(dt, buf);
-               dt_prop_str(dt, "device_type", device_type_pci);
-               dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
-               dt_prop_u32(dt, "#address-cells", 3);
-               dt_prop_u32(dt, "#size-cells", 2);
-               buses[0] = buses[1] = bus;
-               dt_prop_u32_list(dt, "bus-range", buses, 2);
-               scan_phb(dt, bus);
-               dt_end_node(dt);
-               phb_num++;
-       }
-}
-
-static void dt_finish(struct iseries_flat_dt *dt)
-{
-       dt_push_u32(dt, OF_DT_END);
-       dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;
-       klimit = ALIGN((unsigned long)dt_data, 8);
-}
-
-void * __init build_flat_dt(unsigned long phys_mem_size)
-{
-       struct iseries_flat_dt *iseries_dt;
-       u64 tmp[2];
-
-       iseries_dt = dt_init();
-
-       dt_start_node(iseries_dt, "");
-
-       dt_prop_u32(iseries_dt, "#address-cells", 2);
-       dt_prop_u32(iseries_dt, "#size-cells", 2);
-       dt_model(iseries_dt);
-
-       /* /memory */
-       dt_start_node(iseries_dt, "memory@0");
-       dt_prop_str(iseries_dt, "device_type", device_type_memory);
-       tmp[0] = 0;
-       tmp[1] = phys_mem_size;
-       dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
-       dt_end_node(iseries_dt);
-
-       /* /chosen */
-       dt_start_node(iseries_dt, "chosen");
-       dt_prop_str(iseries_dt, "bootargs", cmd_line);
-       dt_initrd(iseries_dt);
-       dt_end_node(iseries_dt);
-
-       dt_cpus(iseries_dt);
-
-       dt_vdevices(iseries_dt);
-       dt_pci_devices(iseries_dt);
-
-       dt_end_node(iseries_dt);
-
-       dt_finish(iseries_dt);
-
-       return iseries_dt;
-}
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
deleted file mode 100644 (file)
index f519ee1..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- *  Low level routines for legacy iSeries support.
- *
- *  Extracted from head_64.S
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC-64 platform, including trap and interrupt dispatch.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the 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 <asm/reg.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-#include <asm/ptrace.h>
-#include <asm/cputable.h>
-#include <asm/mmu.h>
-
-#include "exception.h"
-
-       .text
-
-       .globl system_reset_iSeries
-system_reset_iSeries:
-       bl      .relative_toc
-       mfspr   r13,SPRN_SPRG3          /* Get alpaca address */
-       LOAD_REG_ADDR(r23, alpaca)
-       li      r0,ALPACA_SIZE
-       sub     r23,r13,r23
-       divdu   r24,r23,r0              /* r24 has cpu number */
-       cmpwi   0,r24,0                 /* Are we processor 0? */
-       bne     1f
-       LOAD_REG_ADDR(r13, boot_paca)
-       mtspr   SPRN_SPRG_PACA,r13      /* Save it away for the future */
-       mfmsr   r23
-       ori     r23,r23,MSR_RI
-       mtmsrd  r23                     /* RI on */
-       b       .__start_initialization_iSeries /* Start up the first processor */
-1:     mfspr   r4,SPRN_CTRLF
-       li      r5,CTRL_RUNLATCH        /* Turn off the run light */
-       andc    r4,r4,r5
-       mtspr   SPRN_CTRLT,r4
-
-/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
-/* In the UP case we'll yield() later, and we will not access the paca anyway */
-#ifdef CONFIG_SMP
-iSeries_secondary_wait_paca:
-       HMT_LOW
-       LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
-       ld      r23,0(r23)
-
-       cmpdi   0,r23,0
-       bne     2f                      /* go on when the master is ready */
-
-       /* Keep poking the Hypervisor until we're released */
-       /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
-       lis     r3,0x8002
-       rldicr  r3,r3,32,15             /* r0 = (r3 << 32) & 0xffff000000000000 */
-       li      r0,-1                   /* r0=-1 indicates a Hypervisor call */
-       sc                              /* Invoke the hypervisor via a system call */
-       b       iSeries_secondary_wait_paca
-
-2:
-       HMT_MEDIUM
-       sync
-
-       LOAD_REG_ADDR(r3, nr_cpu_ids)   /* get number of pacas allocated */
-       lwz     r3,0(r3)                /* nr_cpus= or NR_CPUS can limit */
-       cmpld   0,r24,r3                /* is our cpu number allocated? */
-       bge     iSeries_secondary_yield /* no, yield forever */
-
-       /* Load our paca now that it's been allocated */
-       LOAD_REG_ADDR(r13, paca)
-       ld      r13,0(r13)
-       mulli   r0,r24,PACA_SIZE
-       add     r13,r13,r0
-       mtspr   SPRN_SPRG_PACA,r13      /* Save it away for the future */
-       mfmsr   r23
-       ori     r23,r23,MSR_RI
-       mtmsrd  r23                     /* RI on */
-
-iSeries_secondary_smp_loop:
-       lbz     r23,PACAPROCSTART(r13)  /* Test if this processor
-                                        * should start */
-       cmpwi   0,r23,0
-       bne     3f                      /* go on when we are told */
-
-       HMT_LOW
-       /* Let the Hypervisor know we are alive */
-       /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
-       lis     r3,0x8002
-       rldicr  r3,r3,32,15             /* r0 = (r3 << 32) & 0xffff000000000000 */
-       li      r0,-1                   /* r0=-1 indicates a Hypervisor call */
-       sc                              /* Invoke the hypervisor via a system call */
-       mfspr   r13,SPRN_SPRG_PACA      /* Put r13 back ???? */
-       b       iSeries_secondary_smp_loop /* wait for signal to start */
-
-3:
-       HMT_MEDIUM
-       sync
-       LOAD_REG_ADDR(r3,current_set)
-       sldi    r28,r24,3               /* get current_set[cpu#] */
-       ldx     r3,r3,r28
-       addi    r1,r3,THREAD_SIZE
-       subi    r1,r1,STACK_FRAME_OVERHEAD
-
-       b       __secondary_start               /* Loop until told to go */
-#endif /* CONFIG_SMP */
-
-iSeries_secondary_yield:
-       /* Yield the processor.  This is required for non-SMP kernels
-               which are running on multi-threaded machines. */
-       HMT_LOW
-       lis     r3,0x8000
-       rldicr  r3,r3,32,15             /* r3 = (r3 << 32) & 0xffff000000000000 */
-       addi    r3,r3,18                /* r3 = 0x8000000000000012 which is "yield" */
-       li      r4,0                    /* "yield timed" */
-       li      r5,-1                   /* "yield forever" */
-       li      r0,-1                   /* r0=-1 indicates a Hypervisor call */
-       sc                              /* Invoke the hypervisor via a system call */
-       mfspr   r13,SPRN_SPRG_PACA      /* Put r13 back ???? */
-       b       iSeries_secondary_yield /* If SMP not configured, secondaries
-                                        * loop forever */
-
-/***  ISeries-LPAR interrupt handlers ***/
-
-       STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
-
-       .globl data_access_iSeries
-data_access_iSeries:
-       mtspr   SPRN_SPRG_SCRATCH0,r13
-BEGIN_FTR_SECTION
-       mfspr   r13,SPRN_SPRG_PACA
-       std     r9,PACA_EXSLB+EX_R9(r13)
-       std     r10,PACA_EXSLB+EX_R10(r13)
-       mfspr   r10,SPRN_DAR
-       mfspr   r9,SPRN_DSISR
-       srdi    r10,r10,60
-       rlwimi  r10,r9,16,0x20
-       mfcr    r9
-       cmpwi   r10,0x2c
-       beq     .do_stab_bolted_iSeries
-       ld      r10,PACA_EXSLB+EX_R10(r13)
-       std     r11,PACA_EXGEN+EX_R11(r13)
-       ld      r11,PACA_EXSLB+EX_R9(r13)
-       std     r12,PACA_EXGEN+EX_R12(r13)
-       mfspr   r12,SPRN_SPRG_SCRATCH0
-       std     r10,PACA_EXGEN+EX_R10(r13)
-       std     r11,PACA_EXGEN+EX_R9(r13)
-       std     r12,PACA_EXGEN+EX_R13(r13)
-       EXCEPTION_PROLOG_ISERIES_1
-FTR_SECTION_ELSE
-       EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)
-       EXCEPTION_PROLOG_ISERIES_1
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
-       b       data_access_common
-
-.do_stab_bolted_iSeries:
-       std     r11,PACA_EXSLB+EX_R11(r13)
-       std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG_SCRATCH0
-       std     r10,PACA_EXSLB+EX_R13(r13)
-       EXCEPTION_PROLOG_ISERIES_1
-       b       .do_stab_bolted
-
-       .globl  data_access_slb_iSeries
-data_access_slb_iSeries:
-       mtspr   SPRN_SPRG_SCRATCH0,r13  /* save r13 */
-       mfspr   r13,SPRN_SPRG_PACA      /* get paca address into r13 */
-       std     r3,PACA_EXSLB+EX_R3(r13)
-       mfspr   r3,SPRN_DAR
-       std     r9,PACA_EXSLB+EX_R9(r13)
-       mfcr    r9
-#ifdef __DISABLED__
-       cmpdi   r3,0
-       bge     slb_miss_user_iseries
-#endif
-       std     r10,PACA_EXSLB+EX_R10(r13)
-       std     r11,PACA_EXSLB+EX_R11(r13)
-       std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG_SCRATCH0
-       std     r10,PACA_EXSLB+EX_R13(r13)
-       ld      r12,PACALPPACAPTR(r13)
-       ld      r12,LPPACASRR1(r12)
-       b       .slb_miss_realmode
-
-       STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
-
-       .globl  instruction_access_slb_iSeries
-instruction_access_slb_iSeries:
-       mtspr   SPRN_SPRG_SCRATCH0,r13  /* save r13 */
-       mfspr   r13,SPRN_SPRG_PACA      /* get paca address into r13 */
-       std     r3,PACA_EXSLB+EX_R3(r13)
-       ld      r3,PACALPPACAPTR(r13)
-       ld      r3,LPPACASRR0(r3)       /* get SRR0 value */
-       std     r9,PACA_EXSLB+EX_R9(r13)
-       mfcr    r9
-#ifdef __DISABLED__
-       cmpdi   r3,0
-       bge     slb_miss_user_iseries
-#endif
-       std     r10,PACA_EXSLB+EX_R10(r13)
-       std     r11,PACA_EXSLB+EX_R11(r13)
-       std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG_SCRATCH0
-       std     r10,PACA_EXSLB+EX_R13(r13)
-       ld      r12,PACALPPACAPTR(r13)
-       ld      r12,LPPACASRR1(r12)
-       b       .slb_miss_realmode
-
-#ifdef __DISABLED__
-slb_miss_user_iseries:
-       std     r10,PACA_EXGEN+EX_R10(r13)
-       std     r11,PACA_EXGEN+EX_R11(r13)
-       std     r12,PACA_EXGEN+EX_R12(r13)
-       mfspr   r10,SPRG_SCRATCH0
-       ld      r11,PACA_EXSLB+EX_R9(r13)
-       ld      r12,PACA_EXSLB+EX_R3(r13)
-       std     r10,PACA_EXGEN+EX_R13(r13)
-       std     r11,PACA_EXGEN+EX_R9(r13)
-       std     r12,PACA_EXGEN+EX_R3(r13)
-       EXCEPTION_PROLOG_ISERIES_1
-       b       slb_miss_user_common
-#endif
-
-       MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
-       STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
-       STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
-       STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
-       MASKABLE_EXCEPTION_ISERIES(decrementer)
-       STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
-       STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
-
-       .globl  system_call_iSeries
-system_call_iSeries:
-       mr      r9,r13
-       mfspr   r13,SPRN_SPRG_PACA
-       EXCEPTION_PROLOG_ISERIES_1
-       b       system_call_common
-
-       STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
-       STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
-       STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
-
-decrementer_iSeries_masked:
-       /* We may not have a valid TOC pointer in here. */
-       li      r11,1
-       ld      r12,PACALPPACAPTR(r13)
-       stb     r11,LPPACADECRINT(r12)
-       li      r12,-1
-       clrldi  r12,r12,33      /* set DEC to 0x7fffffff */
-       mtspr   SPRN_DEC,r12
-       /* fall through */
-
-hardware_interrupt_iSeries_masked:
-       mtcrf   0x80,r9         /* Restore regs */
-       ld      r12,PACALPPACAPTR(r13)
-       ld      r11,LPPACASRR0(r12)
-       ld      r12,LPPACASRR1(r12)
-       mtspr   SPRN_SRR0,r11
-       mtspr   SPRN_SRR1,r12
-       ld      r9,PACA_EXGEN+EX_R9(r13)
-       ld      r10,PACA_EXGEN+EX_R10(r13)
-       ld      r11,PACA_EXGEN+EX_R11(r13)
-       ld      r12,PACA_EXGEN+EX_R12(r13)
-       ld      r13,PACA_EXGEN+EX_R13(r13)
-       rfid
-       b       .       /* prevent speculative execution */
-
-_INIT_STATIC(__start_initialization_iSeries)
-       /* Clear out the BSS */
-       LOAD_REG_ADDR(r11,__bss_stop)
-       LOAD_REG_ADDR(r8,__bss_start)
-       sub     r11,r11,r8              /* bss size                     */
-       addi    r11,r11,7               /* round up to an even double word */
-       rldicl. r11,r11,61,3            /* shift right by 3             */
-       beq     4f
-       addi    r8,r8,-8
-       li      r0,0
-       mtctr   r11                     /* zero this many doublewords   */
-3:     stdu    r0,8(r8)
-       bdnz    3b
-4:
-       LOAD_REG_ADDR(r1,init_thread_union)
-       addi    r1,r1,THREAD_SIZE
-       li      r0,0
-       stdu    r0,-STACK_FRAME_OVERHEAD(r1)
-
-       bl      .iSeries_early_setup
-       bl      .early_setup
-
-       /* relocation is on at this point */
-
-       b       .start_here_common
diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h
deleted file mode 100644 (file)
index 50271b5..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H
-#define _ASM_POWERPC_ISERIES_EXCEPTION_H
-/*
- * Extracted from head_64.S
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC-64 platform, including trap and interrupt dispatch.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the 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 <asm/exception-64s.h>
-
-#define EXCEPTION_PROLOG_ISERIES_1                                     \
-       mfmsr   r10;                                                    \
-       ld      r12,PACALPPACAPTR(r13);                                 \
-       ld      r11,LPPACASRR0(r12);                                    \
-       ld      r12,LPPACASRR1(r12);                                    \
-       ori     r10,r10,MSR_RI;                                         \
-       mtmsrd  r10,1
-
-#define STD_EXCEPTION_ISERIES(label, area)                             \
-       .globl label##_iSeries;                                         \
-label##_iSeries:                                                       \
-       HMT_MEDIUM;                                                     \
-       mtspr   SPRN_SPRG_SCRATCH0,r13; /* save r13 */                  \
-       EXCEPTION_PROLOG_1(area, NOTEST, 0);                            \
-       EXCEPTION_PROLOG_ISERIES_1;                                     \
-       b       label##_common
-
-#define MASKABLE_EXCEPTION_ISERIES(label)                              \
-       .globl label##_iSeries;                                         \
-label##_iSeries:                                                       \
-       HMT_MEDIUM;                                                     \
-       mtspr   SPRN_SPRG_SCRATCH0,r13; /* save r13 */                  \
-       EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0);                      \
-       lbz     r10,PACASOFTIRQEN(r13);                                 \
-       cmpwi   0,r10,0;                                                \
-       beq-    label##_iSeries_masked;                                 \
-       EXCEPTION_PROLOG_ISERIES_1;                                     \
-       b       label##_common;                                         \
-
-#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
deleted file mode 100644 (file)
index 3ae66ab..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * iSeries hashtable management.
- *     Derived from pSeries_htab.c
- *
- * SMP scalability work:
- *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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 <asm/machdep.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/abs_addr.h>
-#include <linux/spinlock.h>
-
-#include "call_hpt.h"
-
-static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;
-
-/*
- * Very primitive algorithm for picking up a lock
- */
-static inline void iSeries_hlock(unsigned long slot)
-{
-       if (slot & 0x8)
-               slot = ~slot;
-       spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static inline void iSeries_hunlock(unsigned long slot)
-{
-       if (slot & 0x8)
-               slot = ~slot;
-       spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
-                        unsigned long pa, unsigned long rflags,
-                        unsigned long vflags, int psize, int ssize)
-{
-       long slot;
-       struct hash_pte lhpte;
-       int secondary = 0;
-
-       BUG_ON(psize != MMU_PAGE_4K);
-
-       /*
-        * The hypervisor tries both primary and secondary.
-        * If we are being called to insert in the secondary,
-        * it means we have already tried both primary and secondary,
-        * so we return failure immediately.
-        */
-       if (vflags & HPTE_V_SECONDARY)
-               return -1;
-
-       iSeries_hlock(hpte_group);
-
-       slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);
-       if (unlikely(lhpte.v & HPTE_V_VALID)) {
-               if (vflags & HPTE_V_BOLTED) {
-                       HvCallHpt_setSwBits(slot, 0x10, 0);
-                       HvCallHpt_setPp(slot, PP_RWXX);
-                       iSeries_hunlock(hpte_group);
-                       if (slot < 0)
-                               return 0x8 | (slot & 7);
-                       else
-                               return slot & 7;
-               }
-               BUG();
-       }
-
-       if (slot == -1) { /* No available entry found in either group */
-               iSeries_hunlock(hpte_group);
-               return -1;
-       }
-
-       if (slot < 0) {         /* MSB set means secondary group */
-               vflags |= HPTE_V_SECONDARY;
-               secondary = 1;
-               slot &= 0x7fffffffffffffff;
-       }
-
-
-       lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |
-               vflags | HPTE_V_VALID;
-       lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;
-
-       /* Now fill in the actual HPTE */
-       HvCallHpt_addValidate(slot, secondary, &lhpte);
-
-       iSeries_hunlock(hpte_group);
-
-       return (secondary << 3) | (slot & 7);
-}
-
-static unsigned long iSeries_hpte_getword0(unsigned long slot)
-{
-       struct hash_pte hpte;
-
-       HvCallHpt_get(&hpte, slot);
-       return hpte.v;
-}
-
-static long iSeries_hpte_remove(unsigned long hpte_group)
-{
-       unsigned long slot_offset;
-       int i;
-       unsigned long hpte_v;
-
-       /* Pick a random slot to start at */
-       slot_offset = mftb() & 0x7;
-
-       iSeries_hlock(hpte_group);
-
-       for (i = 0; i < HPTES_PER_GROUP; i++) {
-               hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);
-
-               if (! (hpte_v & HPTE_V_BOLTED)) {
-                       HvCallHpt_invalidateSetSwBitsGet(hpte_group +
-                                                        slot_offset, 0, 0);
-                       iSeries_hunlock(hpte_group);
-                       return i;
-               }
-
-               slot_offset++;
-               slot_offset &= 0x7;
-       }
-
-       iSeries_hunlock(hpte_group);
-
-       return -1;
-}
-
-/*
- * The HyperVisor expects the "flags" argument in this form:
- *     bits  0..59 : reserved
- *     bit      60 : N
- *     bits 61..63 : PP2,PP1,PP0
- */
-static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
-                       unsigned long va, int psize, int ssize, int local)
-{
-       struct hash_pte hpte;
-       unsigned long want_v;
-
-       iSeries_hlock(slot);
-
-       HvCallHpt_get(&hpte, slot);
-       want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);
-
-       if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {
-               /*
-                * Hypervisor expects bits as NPPP, which is
-                * different from how they are mapped in our PP.
-                */
-               HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));
-               iSeries_hunlock(slot);
-               return 0;
-       }
-       iSeries_hunlock(slot);
-
-       return -1;
-}
-
-/*
- * Functions used to find the PTE for a particular virtual address.
- * Only used during boot when bolting pages.
- *
- * Input : vpn      : virtual page number
- * Output: PTE index within the page table of the entry
- *         -1 on failure
- */
-static long iSeries_hpte_find(unsigned long vpn)
-{
-       struct hash_pte hpte;
-       long slot;
-
-       /*
-        * The HvCallHpt_findValid interface is as follows:
-        * 0xffffffffffffffff : No entry found.
-        * 0x00000000xxxxxxxx : Entry found in primary group, slot x
-        * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
-        */
-       slot = HvCallHpt_findValid(&hpte, vpn);
-       if (hpte.v & HPTE_V_VALID) {
-               if (slot < 0) {
-                       slot &= 0x7fffffffffffffff;
-                       slot = -slot;
-               }
-       } else
-               slot = -1;
-       return slot;
-}
-
-/*
- * Update the page protection bits. Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT. Assumes pages being operated on will not be stolen.
- * Does not work on large pages.
- *
- * No need to lock here because we should be the only user.
- */
-static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
-                                       int psize, int ssize)
-{
-       unsigned long vsid,va,vpn;
-       long slot;
-
-       BUG_ON(psize != MMU_PAGE_4K);
-
-       vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);
-       va = (vsid << 28) | (ea & 0x0fffffff);
-       vpn = va >> HW_PAGE_SHIFT;
-       slot = iSeries_hpte_find(vpn);
-       if (slot == -1)
-               panic("updateboltedpp: Could not find page to bolt\n");
-       HvCallHpt_setPp(slot, newpp);
-}
-
-static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
-                                   int psize, int ssize, int local)
-{
-       unsigned long hpte_v;
-       unsigned long avpn = va >> 23;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       iSeries_hlock(slot);
-
-       hpte_v = iSeries_hpte_getword0(slot);
-
-       if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))
-               HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
-
-       iSeries_hunlock(slot);
-
-       local_irq_restore(flags);
-}
-
-void __init hpte_init_iSeries(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++)
-               spin_lock_init(&iSeries_hlocks[i]);
-
-       ppc_md.hpte_invalidate  = iSeries_hpte_invalidate;
-       ppc_md.hpte_updatepp    = iSeries_hpte_updatepp;
-       ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
-       ppc_md.hpte_insert      = iSeries_hpte_insert;
-       ppc_md.hpte_remove      = iSeries_hpte_remove;
-}
diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S
deleted file mode 100644 (file)
index 07ae6ad..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * This file contains the code to perform calls to the
- * iSeries LPAR hypervisor
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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 <asm/ppc_asm.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>                /* XXX for STACK_FRAME_OVERHEAD */
-
-       .text
-
-/*
- * Hypervisor call
- *
- * Invoke the iSeries hypervisor via the System Call instruction
- * Parameters are passed to this routine in registers r3 - r10
- *
- * r3 contains the HV function to be called
- * r4-r10 contain the operands to the hypervisor function
- *
- */
-
-_GLOBAL(HvCall)
-_GLOBAL(HvCall0)
-_GLOBAL(HvCall1)
-_GLOBAL(HvCall2)
-_GLOBAL(HvCall3)
-_GLOBAL(HvCall4)
-_GLOBAL(HvCall5)
-_GLOBAL(HvCall6)
-_GLOBAL(HvCall7)
-
-
-       mfcr    r0
-       std     r0,-8(r1)
-       stdu    r1,-(STACK_FRAME_OVERHEAD+16)(r1)
-
-       /* r0 = 0xffffffffffffffff indicates a hypervisor call */
-
-       li      r0,-1
-
-       /* Invoke the hypervisor */
-
-       sc
-
-       ld      r1,0(r1)
-       ld      r0,-8(r1)
-       mtcrf   0xff,r0
-
-       /*  return to caller, return value in r3 */
-
-       blr
-
-_GLOBAL(HvCall0Ret16)
-_GLOBAL(HvCall1Ret16)
-_GLOBAL(HvCall2Ret16)
-_GLOBAL(HvCall3Ret16)
-_GLOBAL(HvCall4Ret16)
-_GLOBAL(HvCall5Ret16)
-_GLOBAL(HvCall6Ret16)
-_GLOBAL(HvCall7Ret16)
-
-       mfcr    r0
-       std     r0,-8(r1)
-       std     r31,-16(r1)
-       stdu    r1,-(STACK_FRAME_OVERHEAD+32)(r1)
-
-       mr      r31,r4
-       li      r0,-1
-       mr      r4,r5
-       mr      r5,r6
-       mr      r6,r7
-       mr      r7,r8
-       mr      r8,r9
-       mr      r9,r10
-
-       sc
-
-       std     r3,0(r31)
-       std     r4,8(r31)
-
-       mr      r3,r5
-
-       ld      r1,0(r1)
-       ld      r0,-8(r1)
-       mtcrf   0xff,r0
-       ld      r31,-16(r1)
-
-       blr
diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c
deleted file mode 100644 (file)
index f476d71..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <asm/page.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-
-void HvCall_writeLogBuffer(const void *buffer, u64 len)
-{
-       struct HvLpBufferList hv_buf;
-       u64 left_this_page;
-       u64 cur = virt_to_abs(buffer);
-
-       while (len) {
-               hv_buf.addr = cur;
-               left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur;
-               if (left_this_page > len)
-                       left_this_page = len;
-               hv_buf.len = left_this_page;
-               len -= left_this_page;
-               HvCall2(HvCallBaseWriteLogBuffer,
-                               virt_to_abs(&hv_buf),
-                               left_this_page);
-               cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE;
-       }
-}
diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c
deleted file mode 100644 (file)
index f62a0c5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2001  Kyle A. Lucke, IBM 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; 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/export.h>
-#include <asm/iseries/hv_lp_config.h>
-#include "it_lp_naca.h"
-
-HvLpIndex HvLpConfig_getLpIndex_outline(void)
-{
-       return HvLpConfig_getLpIndex();
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
-
-HvLpIndex HvLpConfig_getLpIndex(void)
-{
-       return itLpNaca.xLpIndex;
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex);
-
-HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
-{
-       return itLpNaca.xPrimaryLpIndex;
-}
-EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
deleted file mode 100644 (file)
index 2f3d911..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
- *
- * Rewrite, cleanup:
- *
- * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
- * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
- *
- * Dynamic DMA mapping support, iSeries-specific parts.
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/dma-mapping.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-
-#include <asm/iommu.h>
-#include <asm/vio.h>
-#include <asm/tce.h>
-#include <asm/machdep.h>
-#include <asm/abs_addr.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/iommu.h>
-
-static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
-               unsigned long uaddr, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
-{
-       u64 rc;
-       u64 tce, rpn;
-
-       while (npages--) {
-               rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
-               tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
-
-               if (tbl->it_type == TCE_VB) {
-                       /* Virtual Bus */
-                       tce |= TCE_VALID|TCE_ALLIO;
-                       if (direction != DMA_TO_DEVICE)
-                               tce |= TCE_VB_WRITE;
-               } else {
-                       /* PCI Bus */
-                       tce |= TCE_PCI_READ; /* Read allowed */
-                       if (direction != DMA_TO_DEVICE)
-                               tce |= TCE_PCI_WRITE;
-               }
-
-               rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);
-               if (rc)
-                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
-                                       rc);
-               index++;
-               uaddr += TCE_PAGE_SIZE;
-       }
-       return 0;
-}
-
-static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
-{
-       u64 rc;
-
-       while (npages--) {
-               rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
-               if (rc)
-                       panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
-                                       rc);
-               index++;
-       }
-}
-
-/*
- * Structure passed to HvCallXm_getTceTableParms
- */
-struct iommu_table_cb {
-       unsigned long   itc_busno;      /* Bus number for this tce table */
-       unsigned long   itc_start;      /* Will be NULL for secondary */
-       unsigned long   itc_totalsize;  /* Size (in pages) of whole table */
-       unsigned long   itc_offset;     /* Index into real tce table of the
-                                          start of our section */
-       unsigned long   itc_size;       /* Size (in pages) of our section */
-       unsigned long   itc_index;      /* Index of this tce table */
-       unsigned short  itc_maxtables;  /* Max num of tables for partition */
-       unsigned char   itc_virtbus;    /* Flag to indicate virtual bus */
-       unsigned char   itc_slotno;     /* IOA Tce Slot Index */
-       unsigned char   itc_rsvd[4];
-};
-
-/*
- * Call Hv with the architected data structure to get TCE table info.
- * info. Put the returned data into the Linux representation of the
- * TCE table data.
- * The Hardware Tce table comes in three flavors.
- * 1. TCE table shared between Buses.
- * 2. TCE table per Bus.
- * 3. TCE Table per IOA.
- */
-void iommu_table_getparms_iSeries(unsigned long busno,
-                                 unsigned char slotno,
-                                 unsigned char virtbus,
-                                 struct iommu_table* tbl)
-{
-       struct iommu_table_cb *parms;
-
-       parms = kzalloc(sizeof(*parms), GFP_KERNEL);
-       if (parms == NULL)
-               panic("PCI_DMA: TCE Table Allocation failed.");
-
-       parms->itc_busno = busno;
-       parms->itc_slotno = slotno;
-       parms->itc_virtbus = virtbus;
-
-       HvCallXm_getTceTableParms(iseries_hv_addr(parms));
-
-       if (parms->itc_size == 0)
-               panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
-
-       /* itc_size is in pages worth of table, it_size is in # of entries */
-       tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;
-       tbl->it_busno = parms->itc_busno;
-       tbl->it_offset = parms->itc_offset;
-       tbl->it_index = parms->itc_index;
-       tbl->it_blocksize = 1;
-       tbl->it_type = virtbus ? TCE_VB : TCE_PCI;
-
-       kfree(parms);
-}
-
-
-#ifdef CONFIG_PCI
-/*
- * This function compares the known tables to find an iommu_table
- * that has already been built for hardware TCEs.
- */
-static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
-{
-       struct device_node *node;
-
-       for (node = NULL; (node = of_find_all_nodes(node)); ) {
-               struct pci_dn *pdn = PCI_DN(node);
-               struct iommu_table *it;
-
-               if (pdn == NULL)
-                       continue;
-               it = pdn->iommu_table;
-               if ((it != NULL) &&
-                   (it->it_type == TCE_PCI) &&
-                   (it->it_offset == tbl->it_offset) &&
-                   (it->it_index == tbl->it_index) &&
-                   (it->it_size == tbl->it_size)) {
-                       of_node_put(node);
-                       return it;
-               }
-       }
-       return NULL;
-}
-
-
-static void pci_dma_dev_setup_iseries(struct pci_dev *pdev)
-{
-       struct iommu_table *tbl;
-       struct device_node *dn = pci_device_to_OF_node(pdev);
-       struct pci_dn *pdn = PCI_DN(dn);
-       const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
-
-       BUG_ON(lsn == NULL);
-
-       tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
-       iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
-
-       /* Look for existing tce table */
-       pdn->iommu_table = iommu_table_find(tbl);
-       if (pdn->iommu_table == NULL)
-               pdn->iommu_table = iommu_init_table(tbl, -1);
-       else
-               kfree(tbl);
-       set_iommu_table_base(&pdev->dev, pdn->iommu_table);
-}
-#else
-#define pci_dma_dev_setup_iseries      NULL
-#endif
-
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-
-void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
-{
-       return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle,
-                               DMA_BIT_MASK(32), flag, -1);
-}
-EXPORT_SYMBOL_GPL(iseries_hv_alloc);
-
-void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle)
-{
-       iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle);
-}
-EXPORT_SYMBOL_GPL(iseries_hv_free);
-
-dma_addr_t iseries_hv_map(void *vaddr, size_t size,
-                       enum dma_data_direction direction)
-{
-       return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr),
-                             (unsigned long)vaddr % PAGE_SIZE, size,
-                             DMA_BIT_MASK(32), direction, NULL);
-}
-
-void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
-                       enum dma_data_direction direction)
-{
-       iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL);
-}
-
-void __init iommu_vio_init(void)
-{
-       iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
-       veth_iommu_table.it_size /= 2;
-       vio_iommu_table = veth_iommu_table;
-       vio_iommu_table.it_offset += veth_iommu_table.it_size;
-
-       if (!iommu_init_table(&veth_iommu_table, -1))
-               printk("Virtual Bus VETH TCE table failed.\n");
-       if (!iommu_init_table(&vio_iommu_table, -1))
-               printk("Virtual Bus VIO TCE table failed.\n");
-}
-
-struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev)
-{
-       if (strcmp(dev->type, "network") == 0)
-               return &veth_iommu_table;
-       return &vio_iommu_table;
-}
-
-void iommu_init_early_iSeries(void)
-{
-       ppc_md.tce_build = tce_build_iSeries;
-       ppc_md.tce_free  = tce_free_iSeries;
-
-       ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries;
-       set_pci_dma_ops(&dma_iommu_ops);
-}
diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h
deleted file mode 100644 (file)
index 83e4ca4..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ISERIES_IPL_PARMS_H
-#define _ISERIES_IPL_PARMS_H
-
-/*
- *     This struct maps the IPL Parameters DMA'd from the SP.
- *
- * Warning:
- *     This data must map in exactly 64 bytes and match the architecture for
- *     the IPL parms
- */
-
-#include <asm/types.h>
-
-struct ItIplParmsReal {
-       u8      xFormat;                // Defines format of IplParms   x00-x00
-       u8      xRsvd01:6;              // Reserved                     x01-x01
-       u8      xAlternateSearch:1;     // Alternate search indicator   ...
-       u8      xUaSupplied:1;          // UA Supplied on programmed IPL...
-       u8      xLsUaFormat;            // Format byte for UA           x02-x02
-       u8      xRsvd02;                // Reserved                     x03-x03
-       u32     xLsUa;                  // LS UA                        x04-x07
-       u32     xUnusedLsLid;           // First OS LID to load         x08-x0B
-       u16     xLsBusNumber;           // LS Bus Number                x0C-x0D
-       u8      xLsCardAdr;             // LS Card Address              x0E-x0E
-       u8      xLsBoardAdr;            // LS Board Address             x0F-x0F
-       u32     xRsvd03;                // Reserved                     x10-x13
-       u8      xSpcnPresent:1;         // SPCN present                 x14-x14
-       u8      xCpmPresent:1;          // CPM present                  ...
-       u8      xRsvd04:6;              // Reserved                     ...
-       u8      xRsvd05:4;              // Reserved                     x15-x15
-       u8      xKeyLock:4;             // Keylock setting              ...
-       u8      xRsvd06:6;              // Reserved                     x16-x16
-       u8      xIplMode:2;             // Ipl mode (A|B|C|D)           ...
-       u8      xHwIplType;             // Fast v slow v slow EC HW IPL x17-x17
-       u16     xCpmEnabledIpl:1;       // CPM in effect when IPL initiatedx18-x19
-       u16     xPowerOnResetIpl:1;     // Indicate POR condition       ...
-       u16     xMainStorePreserved:1;  // Main Storage is preserved    ...
-       u16     xRsvd07:13;             // Reserved                     ...
-       u16     xIplSource:16;          // Ipl source                   x1A-x1B
-       u8      xIplReason:8;           // Reason for this IPL          x1C-x1C
-       u8      xRsvd08;                // Reserved                     x1D-x1D
-       u16     xRsvd09;                // Reserved                     x1E-x1F
-       u16     xSysBoxType;            // System Box Type              x20-x21
-       u16     xSysProcType;           // System Processor Type        x22-x23
-       u32     xRsvd10;                // Reserved                     x24-x27
-       u64     xRsvd11;                // Reserved                     x28-x2F
-       u64     xRsvd12;                // Reserved                     x30-x37
-       u64     xRsvd13;                // Reserved                     x38-x3F
-};
-
-#endif /* _ISERIES_IPL_PARMS_H */
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
deleted file mode 100644 (file)
index 05ce516..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * This module supports the iSeries PCI bus interrupt handling
- * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>
- * Copyright (C) 2004-2005 IBM 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; 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
- *
- * Change Activity:
- *   Created, December 13, 2000 by Wayne Holm
- * End Change Activity
- */
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-
-#include <asm/paca.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#ifdef CONFIG_PCI
-
-enum pci_event_type {
-       pe_bus_created          = 0,    /* PHB has been created */
-       pe_bus_error            = 1,    /* PHB has failed */
-       pe_bus_failed           = 2,    /* Msg to Secondary, Primary failed bus */
-       pe_node_failed          = 4,    /* Multi-adapter bridge has failed */
-       pe_node_recovered       = 5,    /* Multi-adapter bridge has recovered */
-       pe_bus_recovered        = 12,   /* PHB has been recovered */
-       pe_unquiese_bus         = 18,   /* Secondary bus unqiescing */
-       pe_bridge_error         = 21,   /* Bridge Error */
-       pe_slot_interrupt       = 22    /* Slot interrupt */
-};
-
-struct pci_event {
-       struct HvLpEvent event;
-       union {
-               u64 __align;            /* Align on an 8-byte boundary */
-               struct {
-                       u32             fisr;
-                       HvBusNumber     bus_number;
-                       HvSubBusNumber  sub_bus_number;
-                       HvAgentId       dev_id;
-               } slot;
-               struct {
-                       HvBusNumber     bus_number;
-                       HvSubBusNumber  sub_bus_number;
-               } bus;
-               struct {
-                       HvBusNumber     bus_number;
-                       HvSubBusNumber  sub_bus_number;
-                       HvAgentId       dev_id;
-               } node;
-       } data;
-};
-
-static DEFINE_SPINLOCK(pending_irqs_lock);
-static int num_pending_irqs;
-static int pending_irqs[NR_IRQS];
-
-static void int_received(struct pci_event *event)
-{
-       int irq;
-
-       switch (event->event.xSubtype) {
-       case pe_slot_interrupt:
-               irq = event->event.xCorrelationToken;
-               if (irq < NR_IRQS) {
-                       spin_lock(&pending_irqs_lock);
-                       pending_irqs[irq]++;
-                       num_pending_irqs++;
-                       spin_unlock(&pending_irqs_lock);
-               } else {
-                       printk(KERN_WARNING "int_received: bad irq number %d\n",
-                                       irq);
-                       HvCallPci_eoi(event->data.slot.bus_number,
-                                       event->data.slot.sub_bus_number,
-                                       event->data.slot.dev_id);
-               }
-               break;
-               /* Ignore error recovery events for now */
-       case pe_bus_created:
-               printk(KERN_INFO "int_received: system bus %d created\n",
-                       event->data.bus.bus_number);
-               break;
-       case pe_bus_error:
-       case pe_bus_failed:
-               printk(KERN_INFO "int_received: system bus %d failed\n",
-                       event->data.bus.bus_number);
-               break;
-       case pe_bus_recovered:
-       case pe_unquiese_bus:
-               printk(KERN_INFO "int_received: system bus %d recovered\n",
-                       event->data.bus.bus_number);
-               break;
-       case pe_node_failed:
-       case pe_bridge_error:
-               printk(KERN_INFO
-                       "int_received: multi-adapter bridge %d/%d/%d failed\n",
-                       event->data.node.bus_number,
-                       event->data.node.sub_bus_number,
-                       event->data.node.dev_id);
-               break;
-       case pe_node_recovered:
-               printk(KERN_INFO
-                       "int_received: multi-adapter bridge %d/%d/%d recovered\n",
-                       event->data.node.bus_number,
-                       event->data.node.sub_bus_number,
-                       event->data.node.dev_id);
-               break;
-       default:
-               printk(KERN_ERR
-                       "int_received: unrecognized event subtype 0x%x\n",
-                       event->event.xSubtype);
-               break;
-       }
-}
-
-static void pci_event_handler(struct HvLpEvent *event)
-{
-       if (event && (event->xType == HvLpEvent_Type_PciIo)) {
-               if (hvlpevent_is_int(event))
-                       int_received((struct pci_event *)event);
-               else
-                       printk(KERN_ERR
-                               "pci_event_handler: unexpected ack received\n");
-       } else if (event)
-               printk(KERN_ERR
-                       "pci_event_handler: Unrecognized PCI event type 0x%x\n",
-                       (int)event->xType);
-       else
-               printk(KERN_ERR "pci_event_handler: NULL event received\n");
-}
-
-#define REAL_IRQ_TO_SUBBUS(irq)        (((irq) >> 14) & 0xff)
-#define REAL_IRQ_TO_BUS(irq)   ((((irq) >> 6) & 0xff) + 1)
-#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
-#define REAL_IRQ_TO_FUNC(irq)  ((irq) & 7)
-
-/*
- * This will be called by device drivers (via enable_IRQ)
- * to enable INTA in the bridge interrupt status register.
- */
-static void iseries_enable_IRQ(struct irq_data *d)
-{
-       u32 bus, dev_id, function, mask;
-       const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-       /* The IRQ has already been locked by the caller */
-       bus = REAL_IRQ_TO_BUS(rirq);
-       function = REAL_IRQ_TO_FUNC(rirq);
-       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-       /* Unmask secondary INTA */
-       mask = 0x80000000;
-       HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-/* This is called by iseries_activate_IRQs */
-static unsigned int iseries_startup_IRQ(struct irq_data *d)
-{
-       u32 bus, dev_id, function, mask;
-       const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-       bus = REAL_IRQ_TO_BUS(rirq);
-       function = REAL_IRQ_TO_FUNC(rirq);
-       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-       /* Link the IRQ number to the bridge */
-       HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);
-
-       /* Unmask bridge interrupts in the FISR */
-       mask = 0x01010000 << function;
-       HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
-       iseries_enable_IRQ(d);
-       return 0;
-}
-
-/*
- * This is called out of iSeries_fixup to activate interrupt
- * generation for usable slots
- */
-void __init iSeries_activate_IRQs()
-{
-       int irq;
-       unsigned long flags;
-
-       for_each_irq (irq) {
-               struct irq_desc *desc = irq_to_desc(irq);
-               struct irq_chip *chip;
-
-               if (!desc)
-                       continue;
-
-               chip = irq_desc_get_chip(desc);
-               if (chip && chip->irq_startup) {
-                       raw_spin_lock_irqsave(&desc->lock, flags);
-                       chip->irq_startup(&desc->irq_data);
-                       raw_spin_unlock_irqrestore(&desc->lock, flags);
-               }
-       }
-}
-
-/*  this is not called anywhere currently */
-static void iseries_shutdown_IRQ(struct irq_data *d)
-{
-       u32 bus, dev_id, function, mask;
-       const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-       /* irq should be locked by the caller */
-       bus = REAL_IRQ_TO_BUS(rirq);
-       function = REAL_IRQ_TO_FUNC(rirq);
-       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-       /* Invalidate the IRQ number in the bridge */
-       HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
-
-       /* Mask bridge interrupts in the FISR */
-       mask = 0x01010000 << function;
-       HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
-}
-
-/*
- * This will be called by device drivers (via disable_IRQ)
- * to disable INTA in the bridge interrupt status register.
- */
-static void iseries_disable_IRQ(struct irq_data *d)
-{
-       u32 bus, dev_id, function, mask;
-       const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-       /* The IRQ has already been locked by the caller */
-       bus = REAL_IRQ_TO_BUS(rirq);
-       function = REAL_IRQ_TO_FUNC(rirq);
-       dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
-       /* Mask secondary INTA   */
-       mask = 0x80000000;
-       HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-static void iseries_end_IRQ(struct irq_data *d)
-{
-       unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
-       HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
-               (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
-}
-
-static struct irq_chip iseries_pic = {
-       .name           = "iSeries",
-       .irq_startup    = iseries_startup_IRQ,
-       .irq_shutdown   = iseries_shutdown_IRQ,
-       .irq_unmask     = iseries_enable_IRQ,
-       .irq_mask       = iseries_disable_IRQ,
-       .irq_eoi        = iseries_end_IRQ
-};
-
-/*
- * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
- * It calculates the irq value for the slot.
- * Note that sub_bus is always 0 (at the moment at least).
- */
-int __init iSeries_allocate_IRQ(HvBusNumber bus,
-               HvSubBusNumber sub_bus, u32 bsubbus)
-{
-       unsigned int realirq;
-       u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
-       u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
-
-       realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
-               + function;
-
-       return irq_create_mapping(NULL, realirq);
-}
-
-#endif /* CONFIG_PCI */
-
-/*
- * Get the next pending IRQ.
- */
-unsigned int iSeries_get_irq(void)
-{
-       int irq = NO_IRQ_IGNORE;
-
-#ifdef CONFIG_SMP
-       if (get_lppaca()->int_dword.fields.ipi_cnt) {
-               get_lppaca()->int_dword.fields.ipi_cnt = 0;
-               smp_ipi_demux();
-       }
-#endif /* CONFIG_SMP */
-       if (hvlpevent_is_pending())
-               process_hvlpevents();
-
-#ifdef CONFIG_PCI
-       if (num_pending_irqs) {
-               spin_lock(&pending_irqs_lock);
-               for (irq = 0; irq < NR_IRQS; irq++) {
-                       if (pending_irqs[irq]) {
-                               pending_irqs[irq]--;
-                               num_pending_irqs--;
-                               break;
-                       }
-               }
-               spin_unlock(&pending_irqs_lock);
-               if (irq >= NR_IRQS)
-                       irq = NO_IRQ_IGNORE;
-       }
-#endif
-
-       return irq;
-}
-
-#ifdef CONFIG_PCI
-
-static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq,
-                               irq_hw_number_t hw)
-{
-       irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
-
-       return 0;
-}
-
-static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np)
-{
-       /* Match all */
-       return 1;
-}
-
-static const struct irq_domain_ops iseries_irq_domain_ops = {
-       .map = iseries_irq_host_map,
-       .match = iseries_irq_host_match,
-};
-
-/*
- * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c
- * It must be called before the bus walk.
- */
-void __init iSeries_init_IRQ(void)
-{
-       /* Register PCI event handler and open an event path */
-       struct irq_domain *host;
-       int ret;
-
-       /*
-        * The Hypervisor only allows us up to 256 interrupt
-        * sources (the irq number is passed in a u8).
-        */
-       irq_set_virq_count(256);
-
-       /* Create irq host. No need for a revmap since HV will give us
-        * back our virtual irq number
-        */
-       host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);
-       BUG_ON(host == NULL);
-       irq_set_default_host(host);
-
-       ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
-                       &pci_event_handler);
-       if (ret == 0) {
-               ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
-               if (ret != 0)
-                       printk(KERN_ERR "iseries_init_IRQ: open event path "
-                                       "failed with rc 0x%x\n", ret);
-       } else
-               printk(KERN_ERR "iseries_init_IRQ: register handler "
-                               "failed with rc 0x%x\n", ret);
-}
-
-#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
deleted file mode 100644 (file)
index a1c2360..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef        _ISERIES_IRQ_H
-#define        _ISERIES_IRQ_H
-
-#ifdef CONFIG_PCI
-extern void iSeries_init_IRQ(void);
-extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
-extern void iSeries_activate_IRQs(void);
-#else
-#define iSeries_init_IRQ       NULL
-#endif
-extern unsigned int iSeries_get_irq(void);
-
-#endif /* _ISERIES_IRQ_H */
diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
deleted file mode 100644 (file)
index 6de9097..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2002  Dave Boutcher IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-
-/*
- *     This struct maps the panel information
- *
- * Warning:
- *     This data must match the architecture for the panel information
- */
-
-#include <asm/types.h>
-
-struct ItExtVpdPanel {
-       /* Definition of the Extended Vpd On Panel Data Area */
-       char    systemSerial[8];
-       char    mfgID[4];
-       char    reserved1[24];
-       char    machineType[4];
-       char    systemID[6];
-       char    somUniqueCnt[4];
-       char    serialNumberCount;
-       char    reserved2[7];
-       u16     bbu3;
-       u16     bbu2;
-       u16     bbu1;
-       char    xLocationLabel[8];
-       u8      xRsvd1[6];
-       u16     xFrameId;
-       u8      xRsvd2[48];
-};
-
-extern struct ItExtVpdPanel    xItExtVpdPanel;
-
-#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */
diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h
deleted file mode 100644 (file)
index cf6dcf6..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H
-#define _PLATFORMS_ISERIES_IT_LP_NACA_H
-
-#include <linux/types.h>
-
-/*
- *     This control block contains the data that is shared between the
- *     hypervisor (PLIC) and the OS.
- */
-
-struct ItLpNaca {
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-       u32     xDesc;                  // Eye catcher                  x00-x03
-       u16     xSize;                  // Size of this class           x04-x05
-       u16     xIntHdlrOffset;         // Offset to IntHdlr array      x06-x07
-       u8      xMaxIntHdlrEntries;     // Number of entries in array   x08-x08
-       u8      xPrimaryLpIndex;        // LP Index of Primary          x09-x09
-       u8      xServiceLpIndex;        // LP Ind of Service Focal Pointx0A-x0A
-       u8      xLpIndex;               // LP Index                     x0B-x0B
-       u16     xMaxLpQueues;           // Number of allocated queues   x0C-x0D
-       u16     xLpQueueOffset;         // Offset to start of LP queues x0E-x0F
-       u8      xPirEnvironMode;        // Piranha or hardware          x10-x10
-       u8      xPirConsoleMode;        // Piranha console indicator    x11-x11
-       u8      xPirDasdMode;           // Piranha dasd indicator       x12-x12
-       u8      xRsvd1_0[5];            // Reserved for Piranha related x13-x17
-       u8      flags;                  // flags, see below             x18-x1F
-       u8      xSpVpdFormat;           // VPD areas are in CSP format  ...
-       u8      xIntProcRatio;          // Ratio of int procs to procs  ...
-       u8      xRsvd1_2[5];            // Reserved                     ...
-       u16     xRsvd1_3;               // Reserved                     x20-x21
-       u16     xPlicVrmIndex;          // VRM index of PLIC            x22-x23
-       u16     xMinSupportedSlicVrmInd;// Min supported OS VRM index   x24-x25
-       u16     xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27
-       u64     xLoadAreaAddr;          // ER address of load area      x28-x2F
-       u32     xLoadAreaChunks;        // Chunks for the load area     x30-x33
-       u32     xPaseSysCallCRMask;     // Mask used to test CR before  x34-x37
-                                       // doing an ASR switch on PASE
-                                       // system call.
-       u64     xSlicSegmentTablePtr;   // Pointer to Slic seg table.   x38-x3f
-       u8      xRsvd1_4[64];           //                              x40-x7F
-
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-       u8      xRsvd2_0[128];          // Reserved                     x00-x7F
-
-// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
-// NB: Padding required to keep xInterruptHdlr at x300 which is required
-// for v4r4 PLIC.
-       u8      xOldLpQueue[128];       // LP Queue needed for v4r4     100-17F
-       u8      xRsvd3_0[384];          // Reserved                     180-2FF
-
-// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
-//  handlers
-       u64     xInterruptHdlr[32];     // Interrupt handlers           300-x3FF
-};
-
-extern struct ItLpNaca         itLpNaca;
-
-#define ITLPNACA_LPAR          0x80    /* Is LPAR installed on the system */
-#define ITLPNACA_PARTITIONED   0x40    /* Is the system partitioned */
-#define ITLPNACA_HWSYNCEDTBS   0x20    /* Hardware synced TBs */
-#define ITLPNACA_HMTINT                0x10    /* Utilize MHT for interrupts */
-
-#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c
deleted file mode 100644 (file)
index 997e234..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * (C) 2001-2005 PPC 64 Team, IBM Corp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the 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/export.h>
-
-#include <asm/hw_irq.h>
-#include <asm/iseries/hv_call_sc.h>
-
-EXPORT_SYMBOL(HvCall0);
-EXPORT_SYMBOL(HvCall1);
-EXPORT_SYMBOL(HvCall2);
-EXPORT_SYMBOL(HvCall3);
-EXPORT_SYMBOL(HvCall4);
-EXPORT_SYMBOL(HvCall5);
-EXPORT_SYMBOL(HvCall6);
-EXPORT_SYMBOL(HvCall7);
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
deleted file mode 100644 (file)
index 00e0ec8..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2001 Mike Corrigan, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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/types.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/abs_addr.h>
-#include <asm/lppaca.h>
-#include <asm/paca.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/alpaca.h>
-
-#include "naca.h"
-#include "vpd_areas.h"
-#include "spcomm_area.h"
-#include "ipl_parms.h"
-#include "processor_vpd.h"
-#include "release_data.h"
-#include "it_exp_vpd_panel.h"
-#include "it_lp_naca.h"
-
-/* The HvReleaseData is the root of the information shared between
- * the hypervisor and Linux.
- */
-const struct HvReleaseData hvReleaseData = {
-       .xDesc = 0xc8a5d9c4,    /* "HvRD" ebcdic */
-       .xSize = sizeof(struct HvReleaseData),
-       .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
-       .xSlicNacaAddr = &naca,         /* 64-bit Naca address */
-       .xMsNucDataOffset = LPARMAP_PHYS,
-       .xFlags = HVREL_TAGSINACTIVE    /* tags inactive       */
-                                       /* 64 bit              */
-                                       /* shared processors   */
-                                       /* HMT allowed         */
-                 | 6,                  /* TEMP: This allows non-GA driver */
-       .xVrmIndex = 4,                 /* We are v5r2m0               */
-       .xMinSupportedPlicVrmIndex = 3,         /* v5r1m0 */
-       .xMinCompatablePlicVrmIndex = 3,        /* v5r1m0 */
-       .xVrmName = { 0xd3, 0x89, 0x95, 0xa4,   /* "Linux 2.4.64" ebcdic */
-               0xa7, 0x40, 0xf2, 0x4b,
-               0xf4, 0x4b, 0xf6, 0xf4 },
-};
-
-/*
- * The NACA.  The first dword of the naca is required by the iSeries
- * hypervisor to point to itVpdAreas.  The hypervisor finds the NACA
- * through the pointer in hvReleaseData.
- */
-struct naca_struct naca = {
-       .xItVpdAreas = &itVpdAreas,
-       .xRamDisk = 0,
-       .xRamDiskSize = 0,
-};
-
-struct ItLpRegSave {
-       u32     xDesc;          // Eye catcher  "LpRS" ebcdic   000-003
-       u16     xSize;          // Size of this class           004-005
-       u8      xInUse;         // Area is live                 006-007
-       u8      xRsvd1[9];      // Reserved                     007-00F
-
-       u8      xFixedRegSave[352]; // Fixed Register Save Area 010-16F
-       u32     xCTRL;          // Control Register             170-173
-       u32     xDEC;           // Decrementer                  174-177
-       u32     xFPSCR;         // FP Status and Control Reg    178-17B
-       u32     xPVR;           // Processor Version Number     17C-17F
-
-       u64     xMMCR0;         // Monitor Mode Control Reg 0   180-187
-       u32     xPMC1;          // Perf Monitor Counter 1       188-18B
-       u32     xPMC2;          // Perf Monitor Counter 2       18C-18F
-       u32     xPMC3;          // Perf Monitor Counter 3       190-193
-       u32     xPMC4;          // Perf Monitor Counter 4       194-197
-       u32     xPIR;           // Processor ID Reg             198-19B
-
-       u32     xMMCR1;         // Monitor Mode Control Reg 1   19C-19F
-       u32     xMMCRA;         // Monitor Mode Control Reg A   1A0-1A3
-       u32     xPMC5;          // Perf Monitor Counter 5       1A4-1A7
-       u32     xPMC6;          // Perf Monitor Counter 6       1A8-1AB
-       u32     xPMC7;          // Perf Monitor Counter 7       1AC-1AF
-       u32     xPMC8;          // Perf Monitor Counter 8       1B0-1B3
-       u32     xTSC;           // Thread Switch Control        1B4-1B7
-       u32     xTST;           // Thread Switch Timeout        1B8-1BB
-       u32     xRsvd;          // Reserved                     1BC-1BF
-
-       u64     xACCR;          // Address Compare Control Reg  1C0-1C7
-       u64     xIMR;           // Instruction Match Register   1C8-1CF
-       u64     xSDR1;          // Storage Description Reg 1    1D0-1D7
-       u64     xSPRG0;         // Special Purpose Reg General0 1D8-1DF
-       u64     xSPRG1;         // Special Purpose Reg General1 1E0-1E7
-       u64     xSPRG2;         // Special Purpose Reg General2 1E8-1EF
-       u64     xSPRG3;         // Special Purpose Reg General3 1F0-1F7
-       u64     xTB;            // Time Base Register           1F8-1FF
-
-       u64     xFPR[32];       // Floating Point Registers     200-2FF
-
-       u64     xMSR;           // Machine State Register       300-307
-       u64     xNIA;           // Next Instruction Address     308-30F
-
-       u64     xDABR;          // Data Address Breakpoint Reg  310-317
-       u64     xIABR;          // Inst Address Breakpoint Reg  318-31F
-
-       u64     xHID0;          // HW Implementation Dependent0 320-327
-
-       u64     xHID4;          // HW Implementation Dependent4 328-32F
-       u64     xSCOMd;         // SCON Data Reg (SPRG4)        330-337
-       u64     xSCOMc;         // SCON Command Reg (SPRG5)     338-33F
-       u64     xSDAR;          // Sample Data Address Register 340-347
-       u64     xSIAR;          // Sample Inst Address Register 348-34F
-
-       u8      xRsvd3[176];    // Reserved                     350-3FF
-};
-
-extern void system_reset_iSeries(void);
-extern void machine_check_iSeries(void);
-extern void data_access_iSeries(void);
-extern void instruction_access_iSeries(void);
-extern void hardware_interrupt_iSeries(void);
-extern void alignment_iSeries(void);
-extern void program_check_iSeries(void);
-extern void fp_unavailable_iSeries(void);
-extern void decrementer_iSeries(void);
-extern void trap_0a_iSeries(void);
-extern void trap_0b_iSeries(void);
-extern void system_call_iSeries(void);
-extern void single_step_iSeries(void);
-extern void trap_0e_iSeries(void);
-extern void performance_monitor_iSeries(void);
-extern void data_access_slb_iSeries(void);
-extern void instruction_access_slb_iSeries(void);
-
-struct ItLpNaca itLpNaca = {
-       .xDesc = 0xd397d581,            /* "LpNa" ebcdic */
-       .xSize = 0x0400,                /* size of ItLpNaca */
-       .xIntHdlrOffset = 0x0300,       /* offset to int array */
-       .xMaxIntHdlrEntries = 19,       /* # ents */
-       .xPrimaryLpIndex = 0,           /* Part # of primary */
-       .xServiceLpIndex = 0,           /* Part # of serv */
-       .xLpIndex = 0,                  /* Part # of me */
-       .xMaxLpQueues = 0,              /* # of LP queues */
-       .xLpQueueOffset = 0x100,        /* offset of start of LP queues */
-       .xPirEnvironMode = 0,           /* Piranha stuff */
-       .xPirConsoleMode = 0,
-       .xPirDasdMode = 0,
-       .flags = 0,
-       .xSpVpdFormat = 0,
-       .xIntProcRatio = 0,
-       .xPlicVrmIndex = 0,             /* VRM index of PLIC */
-       .xMinSupportedSlicVrmInd = 0,   /* min supported SLIC */
-       .xMinCompatableSlicVrmInd = 0,  /* min compat SLIC */
-       .xLoadAreaAddr = 0,             /* 64-bit addr of load area */
-       .xLoadAreaChunks = 0,           /* chunks for load area */
-       .xPaseSysCallCRMask = 0,        /* PASE mask */
-       .xSlicSegmentTablePtr = 0,      /* seg table */
-       .xOldLpQueue = { 0 },           /* Old LP Queue */
-       .xInterruptHdlr = {
-               (u64)system_reset_iSeries,      /* 0x100 System Reset */
-               (u64)machine_check_iSeries,     /* 0x200 Machine Check */
-               (u64)data_access_iSeries,       /* 0x300 Data Access */
-               (u64)instruction_access_iSeries, /* 0x400 Instruction Access */
-               (u64)hardware_interrupt_iSeries, /* 0x500 External */
-               (u64)alignment_iSeries,         /* 0x600 Alignment */
-               (u64)program_check_iSeries,     /* 0x700 Program Check */
-               (u64)fp_unavailable_iSeries,    /* 0x800 FP Unavailable */
-               (u64)decrementer_iSeries,       /* 0x900 Decrementer */
-               (u64)trap_0a_iSeries,           /* 0xa00 Trap 0A */
-               (u64)trap_0b_iSeries,           /* 0xb00 Trap 0B */
-               (u64)system_call_iSeries,       /* 0xc00 System Call */
-               (u64)single_step_iSeries,       /* 0xd00 Single Step */
-               (u64)trap_0e_iSeries,           /* 0xe00 Trap 0E */
-               (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */
-               0,                              /* int 0x1000 */
-               0,                              /* int 0x1010 */
-               0,                              /* int 0x1020 CPU ctls */
-               (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */
-               (u64)data_access_slb_iSeries,   /* 0x380 D-SLB */
-               (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
-       }
-};
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
-
-#define maxPhysicalProcessors 32
-
-struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
-       {
-               .xInstCacheOperandSize = 32,
-               .xDataCacheOperandSize = 32,
-               .xProcFreq     = 50000000,
-               .xTimeBaseFreq = 50000000,
-               .xPVR = 0x3600
-       }
-};
-
-/* Space for Main Store Vpd 27,200 bytes */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-u64    xMsVpd[3400] __attribute__((__section__(".data")));
-
-/* Space for Recovery Log Buffer */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static u64    xRecoveryLogBuffer[32] __attribute__((__section__(".data")));
-
-static const struct SpCommArea xSpCommArea = {
-       .xDesc = 0xE2D7C3C2,
-       .xFormat = 1,
-};
-
-static const struct ItLpRegSave iseries_reg_save[] = {
-       [0 ... (NR_CPUS-1)] = {
-               .xDesc = 0xd397d9e2,    /* "LpRS" */
-               .xSize = sizeof(struct ItLpRegSave),
-       },
-};
-
-#define ALPACA_INIT(number)                                            \
-{                                                                      \
-       .lppaca_ptr = &lppaca[number],                                  \
-       .reg_save_ptr = &iseries_reg_save[number],                      \
-}
-
-const struct alpaca alpaca[] = {
-       ALPACA_INIT( 0),
-#if NR_CPUS > 1
-       ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3),
-#if NR_CPUS > 4
-       ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7),
-#if NR_CPUS > 8
-       ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11),
-       ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15),
-       ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19),
-       ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23),
-       ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27),
-       ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31),
-#if NR_CPUS > 32
-       ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35),
-       ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39),
-       ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43),
-       ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47),
-       ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51),
-       ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55),
-       ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59),
-       ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63),
-#endif
-#endif
-#endif
-#endif
-};
-
-/* The LparMap data is now located at offset 0x6000 in head.S
- * It was put there so that the HvReleaseData could address it
- * with a 32-bit offset as required by the iSeries hypervisor
- *
- * The Naca has a pointer to the ItVpdAreas.  The hypervisor finds
- * the Naca via the HvReleaseData area.  The HvReleaseData has the
- * offset into the Naca of the pointer to the ItVpdAreas.
- */
-const struct ItVpdAreas itVpdAreas = {
-       .xSlicDesc = 0xc9a3e5c1,                /* "ItVA" */
-       .xSlicSize = sizeof(struct ItVpdAreas),
-       .xSlicVpdEntries = ItVpdMaxEntries,     /* # VPD array entries */
-       .xSlicDmaEntries = ItDmaMaxEntries,     /* # DMA array entries */
-       .xSlicMaxLogicalProcs = NR_CPUS * 2,    /* Max logical procs */
-       .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */
-       .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),
-       .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),
-       .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),
-       .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),
-       .xSlicMaxSlotLabels = 0,                /* max slot labels */
-       .xSlicMaxLpQueues = 1,                  /* max LP queues */
-       .xPlicDmaLens = { 0 },                  /* DMA lengths */
-       .xPlicDmaToks = { 0 },                  /* DMA tokens */
-       .xSlicVpdLens = {                       /* VPD lengths */
-               0,0,0,                  /*  0 - 2 */
-               sizeof(xItExtVpdPanel), /*       3 Extended VPD   */
-               sizeof(struct alpaca),  /*       4 length of (fake) Paca  */
-               0,                      /*       5 */
-               sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
-               26992,                  /*       7 length of MS VPD */
-               0,                      /*       8 */
-               sizeof(struct ItLpNaca),/*       9 length of LP Naca */
-               0,                      /*      10 */
-               256,                    /*      11 length of Recovery Log Buf */
-               sizeof(struct SpCommArea), /*   12 length of SP Comm Area */
-               0,0,0,                  /* 13 - 15 */
-               sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
-               0,0,0,0,0,0,            /* 17 - 22  */
-               sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
-               0,0                     /* 24 - 25 */
-               },
-       .xSlicVpdAdrs = {                       /* VPD addresses */
-               0,0,0,                  /*       0 -  2 */
-               &xItExtVpdPanel,        /*       3 Extended VPD */
-               &alpaca[0],             /*       4 first (fake) Paca */
-               0,                      /*       5 */
-               &xItIplParmsReal,       /*       6 IPL parms */
-               &xMsVpd,                /*       7 MS Vpd */
-               0,                      /*       8 */
-               &itLpNaca,              /*       9 LpNaca */
-               0,                      /*      10 */
-               &xRecoveryLogBuffer,    /*      11 Recovery Log Buffer */
-               &xSpCommArea,           /*      12 SP Comm Area */
-               0,0,0,                  /* 13 - 15 */
-               &xIoHriProcessorVpd,    /*      16 Proc Vpd */
-               0,0,0,0,0,0,            /* 17 - 22 */
-               &hvlpevent_queue,       /*      23 Lp Queue */
-               0,0
-       }
-};
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
deleted file mode 100644 (file)
index 202e227..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2001 Mike Corrigan  IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-
-#include <asm/system.h>
-#include <asm/paca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include "it_lp_naca.h"
-
-/*
- * The LpQueue is used to pass event data from the hypervisor to
- * the partition.  This is where I/O interrupt events are communicated.
- *
- * It is written to by the hypervisor so cannot end up in the BSS.
- */
-struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
-
-DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
-
-static char *event_types[HvLpEvent_Type_NumTypes] = {
-       "Hypervisor",
-       "Machine Facilities",
-       "Session Manager",
-       "SPD I/O",
-       "Virtual Bus",
-       "PCI I/O",
-       "RIO I/O",
-       "Virtual Lan",
-       "Virtual I/O"
-};
-
-/* Array of LpEvent handler functions */
-static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
-static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
-
-static struct HvLpEvent * get_next_hvlpevent(void)
-{
-       struct HvLpEvent * event;
-       event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
-       if (hvlpevent_is_valid(event)) {
-               /* rmb() needed only for weakly consistent machines (regatta) */
-               rmb();
-               /* Set pointer to next potential event */
-               hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 +
-                               IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) *
-                                       IT_LP_EVENT_ALIGN;
-
-               /* Wrap to beginning if no room at end */
-               if (hvlpevent_queue.hq_current_event >
-                               hvlpevent_queue.hq_last_event) {
-                       hvlpevent_queue.hq_current_event =
-                               hvlpevent_queue.hq_event_stack;
-               }
-       } else {
-               event = NULL;
-       }
-
-       return event;
-}
-
-static unsigned long spread_lpevents = NR_CPUS;
-
-int hvlpevent_is_pending(void)
-{
-       struct HvLpEvent *next_event;
-
-       if (smp_processor_id() >= spread_lpevents)
-               return 0;
-
-       next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
-       return hvlpevent_is_valid(next_event) ||
-               hvlpevent_queue.hq_overflow_pending;
-}
-
-static void hvlpevent_clear_valid(struct HvLpEvent * event)
-{
-       /* Tell the Hypervisor that we're done with this event.
-        * Also clear bits within this event that might look like valid bits.
-        * ie. on 64-byte boundaries.
-        */
-       struct HvLpEvent *tmp;
-       unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) /
-                               IT_LP_EVENT_ALIGN) - 1;
-
-       switch (extra) {
-       case 3:
-               tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN);
-               hvlpevent_invalidate(tmp);
-       case 2:
-               tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN);
-               hvlpevent_invalidate(tmp);
-       case 1:
-               tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN);
-               hvlpevent_invalidate(tmp);
-       }
-
-       mb();
-
-       hvlpevent_invalidate(event);
-}
-
-void process_hvlpevents(void)
-{
-       struct HvLpEvent * event;
-
- restart:
-       /* If we have recursed, just return */
-       if (!spin_trylock(&hvlpevent_queue.hq_lock))
-               return;
-
-       for (;;) {
-               event = get_next_hvlpevent();
-               if (event) {
-                       /* Call appropriate handler here, passing
-                        * a pointer to the LpEvent.  The handler
-                        * must make a copy of the LpEvent if it
-                        * needs it in a bottom half. (perhaps for
-                        * an ACK)
-                        *
-                        *  Handlers are responsible for ACK processing
-                        *
-                        * The Hypervisor guarantees that LpEvents will
-                        * only be delivered with types that we have
-                        * registered for, so no type check is necessary
-                        * here!
-                        */
-                       if (event->xType < HvLpEvent_Type_NumTypes)
-                               __get_cpu_var(hvlpevent_counts)[event->xType]++;
-                       if (event->xType < HvLpEvent_Type_NumTypes &&
-                                       lpEventHandler[event->xType])
-                               lpEventHandler[event->xType](event);
-                       else {
-                               u8 type = event->xType;
-
-                               /*
-                                * Don't printk in the spinlock as printk
-                                * may require ack events form the HV to send
-                                * any characters there.
-                                */
-                               hvlpevent_clear_valid(event);
-                               spin_unlock(&hvlpevent_queue.hq_lock);
-                               printk(KERN_INFO
-                                       "Unexpected Lp Event type=%d\n", type);
-                               goto restart;
-                       }
-
-                       hvlpevent_clear_valid(event);
-               } else if (hvlpevent_queue.hq_overflow_pending)
-                       /*
-                        * No more valid events. If overflow events are
-                        * pending process them
-                        */
-                       HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index);
-               else
-                       break;
-       }
-
-       spin_unlock(&hvlpevent_queue.hq_lock);
-}
-
-static int set_spread_lpevents(char *str)
-{
-       unsigned long val = simple_strtoul(str, NULL, 0);
-
-       /*
-        * The parameter is the number of processors to share in processing
-        * lp events.
-        */
-       if (( val > 0) && (val <= NR_CPUS)) {
-               spread_lpevents = val;
-               printk("lpevent processing spread over %ld processors\n", val);
-       } else {
-               printk("invalid spread_lpevents %ld\n", val);
-       }
-
-       return 1;
-}
-__setup("spread_lpevents=", set_spread_lpevents);
-
-void __init setup_hvlpevent_queue(void)
-{
-       void *eventStack;
-
-       spin_lock_init(&hvlpevent_queue.hq_lock);
-
-       /* Allocate a page for the Event Stack. */
-       eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE);
-       memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE);
-
-       /* Invoke the hypervisor to initialize the event stack */
-       HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE);
-
-       hvlpevent_queue.hq_event_stack = eventStack;
-       hvlpevent_queue.hq_current_event = eventStack;
-       hvlpevent_queue.hq_last_event = (char *)eventStack +
-               (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE);
-       hvlpevent_queue.hq_index = 0;
-}
-
-/* Register a handler for an LpEvent type */
-int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler)
-{
-       if (eventType < HvLpEvent_Type_NumTypes) {
-               lpEventHandler[eventType] = handler;
-               return 0;
-       }
-       return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_registerHandler);
-
-int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType)
-{
-       might_sleep();
-
-       if (eventType < HvLpEvent_Type_NumTypes) {
-               if (!lpEventHandlerPaths[eventType]) {
-                       lpEventHandler[eventType] = NULL;
-                       /*
-                        * We now sleep until all other CPUs have scheduled.
-                        * This ensures that the deletion is seen by all
-                        * other CPUs, and that the deleted handler isn't
-                        * still running on another CPU when we return.
-                        */
-                       synchronize_sched();
-                       return 0;
-               }
-       }
-       return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
-
-/*
- * lpIndex is the partition index of the target partition.
- * needed only for VirtualIo, VirtualLan and SessionMgr.  Zero
- * indicates to use our partition index - for the other types.
- */
-int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
-       if ((eventType < HvLpEvent_Type_NumTypes) &&
-                       lpEventHandler[eventType]) {
-               if (lpIndex == 0)
-                       lpIndex = itLpNaca.xLpIndex;
-               HvCallEvent_openLpEventPath(lpIndex, eventType);
-               ++lpEventHandlerPaths[eventType];
-               return 0;
-       }
-       return 1;
-}
-
-int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
-       if ((eventType < HvLpEvent_Type_NumTypes) &&
-                       lpEventHandler[eventType] &&
-                       lpEventHandlerPaths[eventType]) {
-               if (lpIndex == 0)
-                       lpIndex = itLpNaca.xLpIndex;
-               HvCallEvent_closeLpEventPath(lpIndex, eventType);
-               --lpEventHandlerPaths[eventType];
-               return 0;
-       }
-       return 1;
-}
-
-static int proc_lpevents_show(struct seq_file *m, void *v)
-{
-       int cpu, i;
-       unsigned long sum;
-       static unsigned long cpu_totals[NR_CPUS];
-
-       /* FIXME: do we care that there's no locking here? */
-       sum = 0;
-       for_each_online_cpu(cpu) {
-               cpu_totals[cpu] = 0;
-               for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
-                       cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
-               }
-               sum += cpu_totals[cpu];
-       }
-
-       seq_printf(m, "LpEventQueue 0\n");
-       seq_printf(m, "  events processed:\t%lu\n", sum);
-
-       for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
-               sum = 0;
-               for_each_online_cpu(cpu) {
-                       sum += per_cpu(hvlpevent_counts, cpu)[i];
-               }
-
-               seq_printf(m, "    %-20s %10lu\n", event_types[i], sum);
-       }
-
-       seq_printf(m, "\n  events processed by processor:\n");
-
-       for_each_online_cpu(cpu) {
-               seq_printf(m, "    CPU%02d  %10lu\n", cpu, cpu_totals[cpu]);
-       }
-
-       return 0;
-}
-
-static int proc_lpevents_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_lpevents_show, NULL);
-}
-
-static const struct file_operations proc_lpevents_operations = {
-       .open           = proc_lpevents_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init proc_lpevents_init(void)
-{
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-
-       proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL,
-                   &proc_lpevents_operations);
-       return 0;
-}
-__initcall(proc_lpevents_init);
-
diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h
deleted file mode 100644 (file)
index 1a7a3f5..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#ifndef _ISERIES_MAIN_STORE_H
-#define _ISERIES_MAIN_STORE_H
-
-/* Main Store Vpd for Condor,iStar,sStar */
-struct IoHriMainStoreSegment4 {
-       u8      msArea0Exists:1;
-       u8      msArea1Exists:1;
-       u8      msArea2Exists:1;
-       u8      msArea3Exists:1;
-       u8      reserved1:4;
-       u8      reserved2;
-
-       u8      msArea0Functional:1;
-       u8      msArea1Functional:1;
-       u8      msArea2Functional:1;
-       u8      msArea3Functional:1;
-       u8      reserved3:4;
-       u8      reserved4;
-
-       u32     totalMainStore;
-
-       u64     msArea0Ptr;
-       u64     msArea1Ptr;
-       u64     msArea2Ptr;
-       u64     msArea3Ptr;
-
-       u32     cardProductionLevel;
-
-       u32     msAdrHole;
-
-       u8      msArea0HasRiserVpd:1;
-       u8      msArea1HasRiserVpd:1;
-       u8      msArea2HasRiserVpd:1;
-       u8      msArea3HasRiserVpd:1;
-       u8      reserved5:4;
-       u8      reserved6;
-       u16     reserved7;
-
-       u8      reserved8[28];
-
-       u64     nonInterleavedBlocksStartAdr;
-       u64     nonInterleavedBlocksEndAdr;
-};
-
-/* Main Store VPD for Power4 */
-struct __attribute((packed)) IoHriMainStoreChipInfo1 {
-       u32     chipMfgID;
-       char    chipECLevel[4];
-};
-
-struct IoHriMainStoreVpdIdData {
-       char    typeNumber[4];
-       char    modelNumber[4];
-       char    partNumber[12];
-       char    serialNumber[12];
-};
-
-struct __attribute((packed)) IoHriMainStoreVpdFruData {
-       char    fruLabel[8];
-       u8      numberOfSlots;
-       u8      pluggingType;
-       u16     slotMapIndex;
-};
-
-struct  __attribute((packed)) IoHriMainStoreAdrRangeBlock {
-       void    *blockStart;
-       void    *blockEnd;
-       u32     blockProcChipId;
-};
-
-#define MaxAreaAdrRangeBlocks 4
-
-struct __attribute((packed)) IoHriMainStoreArea4 {
-       u32     msVpdFormat;
-       u8      containedVpdType;
-       u8      reserved1;
-       u16     reserved2;
-
-       u64     msExists;
-       u64     msFunctional;
-
-       u32     memorySize;
-       u32     procNodeId;
-
-       u32     numAdrRangeBlocks;
-       struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks];
-
-       struct IoHriMainStoreChipInfo1  chipInfo0;
-       struct IoHriMainStoreChipInfo1  chipInfo1;
-       struct IoHriMainStoreChipInfo1  chipInfo2;
-       struct IoHriMainStoreChipInfo1  chipInfo3;
-       struct IoHriMainStoreChipInfo1  chipInfo4;
-       struct IoHriMainStoreChipInfo1  chipInfo5;
-       struct IoHriMainStoreChipInfo1  chipInfo6;
-       struct IoHriMainStoreChipInfo1  chipInfo7;
-
-       void    *msRamAreaArray;
-       u32     msRamAreaArrayNumEntries;
-       u32     msRamAreaArrayEntrySize;
-
-       u32     numaDimmExists;
-       u32     numaDimmFunctional;
-       void    *numaDimmArray;
-       u32     numaDimmArrayNumEntries;
-       u32     numaDimmArrayEntrySize;
-
-       struct IoHriMainStoreVpdIdData idData;
-
-       u64     powerData;
-       u64     cardAssemblyPartNum;
-       u64     chipSerialNum;
-
-       u64     reserved3;
-       char    reserved4[16];
-
-       struct IoHriMainStoreVpdFruData fruData;
-
-       u8      vpdPortNum;
-       u8      reserved5;
-       u8      frameId;
-       u8      rackUnit;
-       char    asciiKeywordVpd[256];
-       u32     reserved6;
-};
-
-
-struct IoHriMainStoreSegment5 {
-       u16     reserved1;
-       u8      reserved2;
-       u8      msVpdFormat;
-
-       u32     totalMainStore;
-       u64     maxConfiguredMsAdr;
-
-       struct IoHriMainStoreArea4      *msAreaArray;
-       u32     msAreaArrayNumEntries;
-       u32     msAreaArrayEntrySize;
-
-       u32     msAreaExists;
-       u32     msAreaFunctional;
-
-       u64     reserved3;
-};
-
-extern u64     xMsVpd[];
-
-#endif /* _ISERIES_MAIN_STORE_H */
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
deleted file mode 100644 (file)
index 254c1fc..0000000
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation
- * Copyright (C) 2004-2005 Stephen Rothwell  IBM Corporation
- *
- * This modules exists as an interface between a Linux secondary partition
- * running on an iSeries and the primary partition's Virtual Service
- * Processor (VSP) object.  The VSP has final authority over powering on/off
- * all partitions in the iSeries.  It also provides miscellaneous low-level
- * machine facility type operations.
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-
-#include <asm/time.h>
-#include <asm/uaccess.h>
-#include <asm/paca.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/it_lp_queue.h>
-
-#include "setup.h"
-
-static int mf_initialized;
-
-/*
- * This is the structure layout for the Machine Facilities LPAR event
- * flows.
- */
-struct vsp_cmd_data {
-       u64 token;
-       u16 cmd;
-       HvLpIndex lp_index;
-       u8 result_code;
-       u32 reserved;
-       union {
-               u64 state;      /* GetStateOut */
-               u64 ipl_type;   /* GetIplTypeOut, Function02SelectIplTypeIn */
-               u64 ipl_mode;   /* GetIplModeOut, Function02SelectIplModeIn */
-               u64 page[4];    /* GetSrcHistoryIn */
-               u64 flag;       /* GetAutoIplWhenPrimaryIplsOut,
-                                  SetAutoIplWhenPrimaryIplsIn,
-                                  WhiteButtonPowerOffIn,
-                                  Function08FastPowerOffIn,
-                                  IsSpcnRackPowerIncompleteOut */
-               struct {
-                       u64 token;
-                       u64 address_type;
-                       u64 side;
-                       u32 length;
-                       u32 offset;
-               } kern;         /* SetKernelImageIn, GetKernelImageIn,
-                                  SetKernelCmdLineIn, GetKernelCmdLineIn */
-               u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */
-               u8 reserved[80];
-       } sub_data;
-};
-
-struct vsp_rsp_data {
-       struct completion com;
-       struct vsp_cmd_data *response;
-};
-
-struct alloc_data {
-       u16 size;
-       u16 type;
-       u32 count;
-       u16 reserved1;
-       u8 reserved2;
-       HvLpIndex target_lp;
-};
-
-struct ce_msg_data;
-
-typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
-
-struct ce_msg_comp_data {
-       ce_msg_comp_hdlr handler;
-       void *token;
-};
-
-struct ce_msg_data {
-       u8 ce_msg[12];
-       char reserved[4];
-       struct ce_msg_comp_data *completion;
-};
-
-struct io_mf_lp_event {
-       struct HvLpEvent hp_lp_event;
-       u16 subtype_result_code;
-       u16 reserved1;
-       u32 reserved2;
-       union {
-               struct alloc_data alloc;
-               struct ce_msg_data ce_msg;
-               struct vsp_cmd_data vsp_cmd;
-       } data;
-};
-
-#define subtype_data(a, b, c, d)       \
-               (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
-
-/*
- * All outgoing event traffic is kept on a FIFO queue.  The first
- * pointer points to the one that is outstanding, and all new
- * requests get stuck on the end.  Also, we keep a certain number of
- * preallocated pending events so that we can operate very early in
- * the boot up sequence (before kmalloc is ready).
- */
-struct pending_event {
-       struct pending_event *next;
-       struct io_mf_lp_event event;
-       MFCompleteHandler hdlr;
-       char dma_data[72];
-       unsigned dma_data_length;
-       unsigned remote_address;
-};
-static spinlock_t pending_event_spinlock;
-static struct pending_event *pending_event_head;
-static struct pending_event *pending_event_tail;
-static struct pending_event *pending_event_avail;
-#define PENDING_EVENT_PREALLOC_LEN 16
-static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN];
-
-/*
- * Put a pending event onto the available queue, so it can get reused.
- * Attention! You must have the pending_event_spinlock before calling!
- */
-static void free_pending_event(struct pending_event *ev)
-{
-       if (ev != NULL) {
-               ev->next = pending_event_avail;
-               pending_event_avail = ev;
-       }
-}
-
-/*
- * Enqueue the outbound event onto the stack.  If the queue was
- * empty to begin with, we must also issue it via the Hypervisor
- * interface.  There is a section of code below that will touch
- * the first stack pointer without the protection of the pending_event_spinlock.
- * This is OK, because we know that nobody else will be modifying
- * the first pointer when we do this.
- */
-static int signal_event(struct pending_event *ev)
-{
-       int rc = 0;
-       unsigned long flags;
-       int go = 1;
-       struct pending_event *ev1;
-       HvLpEvent_Rc hv_rc;
-
-       /* enqueue the event */
-       if (ev != NULL) {
-               ev->next = NULL;
-               spin_lock_irqsave(&pending_event_spinlock, flags);
-               if (pending_event_head == NULL)
-                       pending_event_head = ev;
-               else {
-                       go = 0;
-                       pending_event_tail->next = ev;
-               }
-               pending_event_tail = ev;
-               spin_unlock_irqrestore(&pending_event_spinlock, flags);
-       }
-
-       /* send the event */
-       while (go) {
-               go = 0;
-
-               /* any DMA data to send beforehand? */
-               if (pending_event_head->dma_data_length > 0)
-                       HvCallEvent_dmaToSp(pending_event_head->dma_data,
-                                       pending_event_head->remote_address,
-                                       pending_event_head->dma_data_length,
-                                       HvLpDma_Direction_LocalToRemote);
-
-               hv_rc = HvCallEvent_signalLpEvent(
-                               &pending_event_head->event.hp_lp_event);
-               if (hv_rc != HvLpEvent_Rc_Good) {
-                       printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
-                                       "failed with %d\n", (int)hv_rc);
-
-                       spin_lock_irqsave(&pending_event_spinlock, flags);
-                       ev1 = pending_event_head;
-                       pending_event_head = pending_event_head->next;
-                       if (pending_event_head != NULL)
-                               go = 1;
-                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
-                       if (ev1 == ev)
-                               rc = -EIO;
-                       else if (ev1->hdlr != NULL)
-                               (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
-
-                       spin_lock_irqsave(&pending_event_spinlock, flags);
-                       free_pending_event(ev1);
-                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-               }
-       }
-
-       return rc;
-}
-
-/*
- * Allocate a new pending_event structure, and initialize it.
- */
-static struct pending_event *new_pending_event(void)
-{
-       struct pending_event *ev = NULL;
-       HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
-       unsigned long flags;
-       struct HvLpEvent *hev;
-
-       spin_lock_irqsave(&pending_event_spinlock, flags);
-       if (pending_event_avail != NULL) {
-               ev = pending_event_avail;
-               pending_event_avail = pending_event_avail->next;
-       }
-       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-       if (ev == NULL) {
-               ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
-               if (ev == NULL) {
-                       printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
-                                       sizeof(struct pending_event));
-                       return NULL;
-               }
-       }
-       memset(ev, 0, sizeof(struct pending_event));
-       hev = &ev->event.hp_lp_event;
-       hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT;
-       hev->xType = HvLpEvent_Type_MachineFac;
-       hev->xSourceLp = HvLpConfig_getLpIndex();
-       hev->xTargetLp = primary_lp;
-       hev->xSizeMinus1 = sizeof(ev->event) - 1;
-       hev->xRc = HvLpEvent_Rc_Good;
-       hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
-                       HvLpEvent_Type_MachineFac);
-       hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
-                       HvLpEvent_Type_MachineFac);
-
-       return ev;
-}
-
-static int __maybe_unused
-signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
-{
-       struct pending_event *ev = new_pending_event();
-       int rc;
-       struct vsp_rsp_data response;
-
-       if (ev == NULL)
-               return -ENOMEM;
-
-       init_completion(&response.com);
-       response.response = vsp_cmd;
-       ev->event.hp_lp_event.xSubtype = 6;
-       ev->event.hp_lp_event.x.xSubtypeData =
-               subtype_data('M', 'F',  'V',  'I');
-       ev->event.data.vsp_cmd.token = (u64)&response;
-       ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
-       ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
-       ev->event.data.vsp_cmd.result_code = 0xFF;
-       ev->event.data.vsp_cmd.reserved = 0;
-       memcpy(&(ev->event.data.vsp_cmd.sub_data),
-                       &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
-       mb();
-
-       rc = signal_event(ev);
-       if (rc == 0)
-               wait_for_completion(&response.com);
-       return rc;
-}
-
-
-/*
- * Send a 12-byte CE message to the primary partition VSP object
- */
-static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
-{
-       struct pending_event *ev = new_pending_event();
-
-       if (ev == NULL)
-               return -ENOMEM;
-
-       ev->event.hp_lp_event.xSubtype = 0;
-       ev->event.hp_lp_event.x.xSubtypeData =
-               subtype_data('M',  'F',  'C',  'E');
-       memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
-       ev->event.data.ce_msg.completion = completion;
-       return signal_event(ev);
-}
-
-/*
- * Send a 12-byte CE message (with no data) to the primary partition VSP object
- */
-static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
-{
-       u8 ce_msg[12];
-
-       memset(ce_msg, 0, sizeof(ce_msg));
-       ce_msg[3] = ce_op;
-       return signal_ce_msg(ce_msg, completion);
-}
-
-/*
- * Send a 12-byte CE message and DMA data to the primary partition VSP object
- */
-static int dma_and_signal_ce_msg(char *ce_msg,
-               struct ce_msg_comp_data *completion, void *dma_data,
-               unsigned dma_data_length, unsigned remote_address)
-{
-       struct pending_event *ev = new_pending_event();
-
-       if (ev == NULL)
-               return -ENOMEM;
-
-       ev->event.hp_lp_event.xSubtype = 0;
-       ev->event.hp_lp_event.x.xSubtypeData =
-               subtype_data('M', 'F', 'C', 'E');
-       memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
-       ev->event.data.ce_msg.completion = completion;
-       memcpy(ev->dma_data, dma_data, dma_data_length);
-       ev->dma_data_length = dma_data_length;
-       ev->remote_address = remote_address;
-       return signal_event(ev);
-}
-
-/*
- * Initiate a nice (hopefully) shutdown of Linux.  We simply are
- * going to try and send the init process a SIGINT signal.  If
- * this fails (why?), we'll simply force it off in a not-so-nice
- * manner.
- */
-static int shutdown(void)
-{
-       int rc = kill_cad_pid(SIGINT, 1);
-
-       if (rc) {
-               printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
-                               "hard shutdown commencing\n", rc);
-               mf_power_off();
-       } else
-               printk(KERN_INFO "mf.c: init has been successfully notified "
-                               "to proceed with shutdown\n");
-       return rc;
-}
-
-/*
- * The primary partition VSP object is sending us a new
- * event flow.  Handle it...
- */
-static void handle_int(struct io_mf_lp_event *event)
-{
-       struct ce_msg_data *ce_msg_data;
-       struct ce_msg_data *pce_msg_data;
-       unsigned long flags;
-       struct pending_event *pev;
-
-       /* ack the interrupt */
-       event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
-       HvCallEvent_ackLpEvent(&event->hp_lp_event);
-
-       /* process interrupt */
-       switch (event->hp_lp_event.xSubtype) {
-       case 0: /* CE message */
-               ce_msg_data = &event->data.ce_msg;
-               switch (ce_msg_data->ce_msg[3]) {
-               case 0x5B:      /* power control notification */
-                       if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
-                               printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
-                               if (shutdown() == 0)
-                                       signal_ce_msg_simple(0xDB, NULL);
-                       }
-                       break;
-               case 0xC0:      /* get time */
-                       spin_lock_irqsave(&pending_event_spinlock, flags);
-                       pev = pending_event_head;
-                       if (pev != NULL)
-                               pending_event_head = pending_event_head->next;
-                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-                       if (pev == NULL)
-                               break;
-                       pce_msg_data = &pev->event.data.ce_msg;
-                       if (pce_msg_data->ce_msg[3] != 0x40)
-                               break;
-                       if (pce_msg_data->completion != NULL) {
-                               ce_msg_comp_hdlr handler =
-                                       pce_msg_data->completion->handler;
-                               void *token = pce_msg_data->completion->token;
-
-                               if (handler != NULL)
-                                       (*handler)(token, ce_msg_data);
-                       }
-                       spin_lock_irqsave(&pending_event_spinlock, flags);
-                       free_pending_event(pev);
-                       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-                       /* send next waiting event */
-                       if (pending_event_head != NULL)
-                               signal_event(NULL);
-                       break;
-               }
-               break;
-       case 1: /* IT sys shutdown */
-               printk(KERN_INFO "mf.c: Commencing system shutdown\n");
-               shutdown();
-               break;
-       }
-}
-
-/*
- * The primary partition VSP object is acknowledging the receipt
- * of a flow we sent to them.  If there are other flows queued
- * up, we must send another one now...
- */
-static void handle_ack(struct io_mf_lp_event *event)
-{
-       unsigned long flags;
-       struct pending_event *two = NULL;
-       unsigned long free_it = 0;
-       struct ce_msg_data *ce_msg_data;
-       struct ce_msg_data *pce_msg_data;
-       struct vsp_rsp_data *rsp;
-
-       /* handle current event */
-       if (pending_event_head == NULL) {
-               printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
-               return;
-       }
-
-       switch (event->hp_lp_event.xSubtype) {
-       case 0:     /* CE msg */
-               ce_msg_data = &event->data.ce_msg;
-               if (ce_msg_data->ce_msg[3] != 0x40) {
-                       free_it = 1;
-                       break;
-               }
-               if (ce_msg_data->ce_msg[2] == 0)
-                       break;
-               free_it = 1;
-               pce_msg_data = &pending_event_head->event.data.ce_msg;
-               if (pce_msg_data->completion != NULL) {
-                       ce_msg_comp_hdlr handler =
-                               pce_msg_data->completion->handler;
-                       void *token = pce_msg_data->completion->token;
-
-                       if (handler != NULL)
-                               (*handler)(token, ce_msg_data);
-               }
-               break;
-       case 4: /* allocate */
-       case 5: /* deallocate */
-               if (pending_event_head->hdlr != NULL)
-                       (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
-               free_it = 1;
-               break;
-       case 6:
-               free_it = 1;
-               rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
-               if (rsp == NULL) {
-                       printk(KERN_ERR "mf.c: no rsp\n");
-                       break;
-               }
-               if (rsp->response != NULL)
-                       memcpy(rsp->response, &event->data.vsp_cmd,
-                                       sizeof(event->data.vsp_cmd));
-               complete(&rsp->com);
-               break;
-       }
-
-       /* remove from queue */
-       spin_lock_irqsave(&pending_event_spinlock, flags);
-       if ((pending_event_head != NULL) && (free_it == 1)) {
-               struct pending_event *oldHead = pending_event_head;
-
-               pending_event_head = pending_event_head->next;
-               two = pending_event_head;
-               free_pending_event(oldHead);
-       }
-       spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
-       /* send next waiting event */
-       if (two != NULL)
-               signal_event(NULL);
-}
-
-/*
- * This is the generic event handler we are registering with
- * the Hypervisor.  Ensure the flows are for us, and then
- * parse it enough to know if it is an interrupt or an
- * acknowledge.
- */
-static void hv_handler(struct HvLpEvent *event)
-{
-       if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
-               if (hvlpevent_is_ack(event))
-                       handle_ack((struct io_mf_lp_event *)event);
-               else
-                       handle_int((struct io_mf_lp_event *)event);
-       } else
-               printk(KERN_ERR "mf.c: alien event received\n");
-}
-
-/*
- * Global kernel interface to allocate and seed events into the
- * Hypervisor.
- */
-void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
-               unsigned size, unsigned count, MFCompleteHandler hdlr,
-               void *user_token)
-{
-       struct pending_event *ev = new_pending_event();
-       int rc;
-
-       if (ev == NULL) {
-               rc = -ENOMEM;
-       } else {
-               ev->event.hp_lp_event.xSubtype = 4;
-               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
-               ev->event.hp_lp_event.x.xSubtypeData =
-                       subtype_data('M', 'F', 'M', 'A');
-               ev->event.data.alloc.target_lp = target_lp;
-               ev->event.data.alloc.type = type;
-               ev->event.data.alloc.size = size;
-               ev->event.data.alloc.count = count;
-               ev->hdlr = hdlr;
-               rc = signal_event(ev);
-       }
-       if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_allocate_lp_events);
-
-/*
- * Global kernel interface to unseed and deallocate events already in
- * Hypervisor.
- */
-void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
-               unsigned count, MFCompleteHandler hdlr, void *user_token)
-{
-       struct pending_event *ev = new_pending_event();
-       int rc;
-
-       if (ev == NULL)
-               rc = -ENOMEM;
-       else {
-               ev->event.hp_lp_event.xSubtype = 5;
-               ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
-               ev->event.hp_lp_event.x.xSubtypeData =
-                       subtype_data('M', 'F', 'M', 'D');
-               ev->event.data.alloc.target_lp = target_lp;
-               ev->event.data.alloc.type = type;
-               ev->event.data.alloc.count = count;
-               ev->hdlr = hdlr;
-               rc = signal_event(ev);
-       }
-       if ((rc != 0) && (hdlr != NULL))
-               (*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_deallocate_lp_events);
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to power this partition off.
- */
-void mf_power_off(void)
-{
-       printk(KERN_INFO "mf.c: Down it goes...\n");
-       signal_ce_msg_simple(0x4d, NULL);
-       for (;;)
-               ;
-}
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to reboot this partition.
- */
-void mf_reboot(char *cmd)
-{
-       printk(KERN_INFO "mf.c: Preparing to bounce...\n");
-       signal_ce_msg_simple(0x4e, NULL);
-       for (;;)
-               ;
-}
-
-/*
- * Display a single word SRC onto the VSP control panel.
- */
-void mf_display_src(u32 word)
-{
-       u8 ce[12];
-
-       memset(ce, 0, sizeof(ce));
-       ce[3] = 0x4a;
-       ce[7] = 0x01;
-       ce[8] = word >> 24;
-       ce[9] = word >> 16;
-       ce[10] = word >> 8;
-       ce[11] = word;
-       signal_ce_msg(ce, NULL);
-}
-
-/*
- * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
- */
-static __init void mf_display_progress_src(u16 value)
-{
-       u8 ce[12];
-       u8 src[72];
-
-       memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12);
-       memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
-               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
-               "\x00\x00\x00\x00PROGxxxx                        ",
-               72);
-       src[6] = value >> 8;
-       src[7] = value & 255;
-       src[44] = "0123456789ABCDEF"[(value >> 12) & 15];
-       src[45] = "0123456789ABCDEF"[(value >> 8) & 15];
-       src[46] = "0123456789ABCDEF"[(value >> 4) & 15];
-       src[47] = "0123456789ABCDEF"[value & 15];
-       dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);
-}
-
-/*
- * Clear the VSP control panel.  Used to "erase" an SRC that was
- * previously displayed.
- */
-static void mf_clear_src(void)
-{
-       signal_ce_msg_simple(0x4b, NULL);
-}
-
-void __init mf_display_progress(u16 value)
-{
-       if (!mf_initialized)
-               return;
-
-       if (0xFFFF == value)
-               mf_clear_src();
-       else
-               mf_display_progress_src(value);
-}
-
-/*
- * Initialization code here.
- */
-void __init mf_init(void)
-{
-       int i;
-
-       spin_lock_init(&pending_event_spinlock);
-
-       for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++)
-               free_pending_event(&pending_event_prealloc[i]);
-
-       HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
-
-       /* virtual continue ack */
-       signal_ce_msg_simple(0x57, NULL);
-
-       mf_initialized = 1;
-       mb();
-
-       printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
-                       "initialized\n");
-}
-
-struct rtc_time_data {
-       struct completion com;
-       struct ce_msg_data ce_msg;
-       int rc;
-};
-
-static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
-       struct rtc_time_data *rtc = token;
-
-       memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
-       rtc->rc = 0;
-       complete(&rtc->com);
-}
-
-static int mf_set_rtc(struct rtc_time *tm)
-{
-       char ce_time[12];
-       u8 day, mon, hour, min, sec, y1, y2;
-       unsigned year;
-
-       year = 1900 + tm->tm_year;
-       y1 = year / 100;
-       y2 = year % 100;
-
-       sec = tm->tm_sec;
-       min = tm->tm_min;
-       hour = tm->tm_hour;
-       day = tm->tm_mday;
-       mon = tm->tm_mon + 1;
-
-       sec = bin2bcd(sec);
-       min = bin2bcd(min);
-       hour = bin2bcd(hour);
-       mon = bin2bcd(mon);
-       day = bin2bcd(day);
-       y1 = bin2bcd(y1);
-       y2 = bin2bcd(y2);
-
-       memset(ce_time, 0, sizeof(ce_time));
-       ce_time[3] = 0x41;
-       ce_time[4] = y1;
-       ce_time[5] = y2;
-       ce_time[6] = sec;
-       ce_time[7] = min;
-       ce_time[8] = hour;
-       ce_time[10] = day;
-       ce_time[11] = mon;
-
-       return signal_ce_msg(ce_time, NULL);
-}
-
-static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
-{
-       tm->tm_wday = 0;
-       tm->tm_yday = 0;
-       tm->tm_isdst = 0;
-       if (rc) {
-               tm->tm_sec = 0;
-               tm->tm_min = 0;
-               tm->tm_hour = 0;
-               tm->tm_mday = 15;
-               tm->tm_mon = 5;
-               tm->tm_year = 52;
-               return rc;
-       }
-
-       if ((ce_msg[2] == 0xa9) ||
-           (ce_msg[2] == 0xaf)) {
-               /* TOD clock is not set */
-               tm->tm_sec = 1;
-               tm->tm_min = 1;
-               tm->tm_hour = 1;
-               tm->tm_mday = 10;
-               tm->tm_mon = 8;
-               tm->tm_year = 71;
-               mf_set_rtc(tm);
-       }
-       {
-               u8 year = ce_msg[5];
-               u8 sec = ce_msg[6];
-               u8 min = ce_msg[7];
-               u8 hour = ce_msg[8];
-               u8 day = ce_msg[10];
-               u8 mon = ce_msg[11];
-
-               sec = bcd2bin(sec);
-               min = bcd2bin(min);
-               hour = bcd2bin(hour);
-               day = bcd2bin(day);
-               mon = bcd2bin(mon);
-               year = bcd2bin(year);
-
-               if (year <= 69)
-                       year += 100;
-
-               tm->tm_sec = sec;
-               tm->tm_min = min;
-               tm->tm_hour = hour;
-               tm->tm_mday = day;
-               tm->tm_mon = mon;
-               tm->tm_year = year;
-       }
-
-       return 0;
-}
-
-static int mf_get_rtc(struct rtc_time *tm)
-{
-       struct ce_msg_comp_data ce_complete;
-       struct rtc_time_data rtc_data;
-       int rc;
-
-       memset(&ce_complete, 0, sizeof(ce_complete));
-       memset(&rtc_data, 0, sizeof(rtc_data));
-       init_completion(&rtc_data.com);
-       ce_complete.handler = &get_rtc_time_complete;
-       ce_complete.token = &rtc_data;
-       rc = signal_ce_msg_simple(0x40, &ce_complete);
-       if (rc)
-               return rc;
-       wait_for_completion(&rtc_data.com);
-       return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-struct boot_rtc_time_data {
-       int busy;
-       struct ce_msg_data ce_msg;
-       int rc;
-};
-
-static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
-       struct boot_rtc_time_data *rtc = token;
-
-       memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
-       rtc->rc = 0;
-       rtc->busy = 0;
-}
-
-static int mf_get_boot_rtc(struct rtc_time *tm)
-{
-       struct ce_msg_comp_data ce_complete;
-       struct boot_rtc_time_data rtc_data;
-       int rc;
-
-       memset(&ce_complete, 0, sizeof(ce_complete));
-       memset(&rtc_data, 0, sizeof(rtc_data));
-       rtc_data.busy = 1;
-       ce_complete.handler = &get_boot_rtc_time_complete;
-       ce_complete.token = &rtc_data;
-       rc = signal_ce_msg_simple(0x40, &ce_complete);
-       if (rc)
-               return rc;
-       /* We need to poll here as we are not yet taking interrupts */
-       while (rtc_data.busy) {
-               if (hvlpevent_is_pending())
-                       process_hvlpevents();
-       }
-       return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-#ifdef CONFIG_PROC_FS
-static int mf_cmdline_proc_show(struct seq_file *m, void *v)
-{
-       char *page, *p;
-       struct vsp_cmd_data vsp_cmd;
-       int rc;
-       dma_addr_t dma_addr;
-
-       /* The HV appears to return no more than 256 bytes of command line */
-       page = kmalloc(256, GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-
-       dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);
-       if (dma_addr == DMA_ERROR_CODE) {
-               kfree(page);
-               return -ENOMEM;
-       }
-       memset(page, 0, 256);
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 33;
-       vsp_cmd.sub_data.kern.token = dma_addr;
-       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       vsp_cmd.sub_data.kern.side = (u64)m->private;
-       vsp_cmd.sub_data.kern.length = 256;
-       mb();
-       rc = signal_vsp_instruction(&vsp_cmd);
-       iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);
-       if (rc) {
-               kfree(page);
-               return rc;
-       }
-       if (vsp_cmd.result_code != 0) {
-               kfree(page);
-               return -ENOMEM;
-       }
-       p = page;
-       while (p - page < 256) {
-               if (*p == '\0' || *p == '\n') {
-                       *p = '\n';
-                       break;
-               }
-               p++;
-
-       }
-       seq_write(m, page, p - page);
-       kfree(page);
-       return 0;
-}
-
-static int mf_cmdline_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);
-}
-
-#if 0
-static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
-{
-       struct vsp_cmd_data vsp_cmd;
-       int rc;
-       int len = *size;
-       dma_addr_t dma_addr;
-
-       dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);
-       memset(buffer, 0, len);
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 32;
-       vsp_cmd.sub_data.kern.token = dma_addr;
-       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       vsp_cmd.sub_data.kern.side = side;
-       vsp_cmd.sub_data.kern.offset = offset;
-       vsp_cmd.sub_data.kern.length = len;
-       mb();
-       rc = signal_vsp_instruction(&vsp_cmd);
-       if (rc == 0) {
-               if (vsp_cmd.result_code == 0)
-                       *size = vsp_cmd.sub_data.length_out;
-               else
-                       rc = -ENOMEM;
-       }
-
-       iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
-
-       return rc;
-}
-
-static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
-{
-       int sizeToGet = count;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-
-       if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
-               if (sizeToGet != 0) {
-                       *start = page + off;
-                       return sizeToGet;
-               }
-               *eof = 1;
-               return 0;
-       }
-       *eof = 1;
-       return 0;
-}
-#endif
-
-static int mf_side_proc_show(struct seq_file *m, void *v)
-{
-       char mf_current_side = ' ';
-       struct vsp_cmd_data vsp_cmd;
-
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 2;
-       vsp_cmd.sub_data.ipl_type = 0;
-       mb();
-
-       if (signal_vsp_instruction(&vsp_cmd) == 0) {
-               if (vsp_cmd.result_code == 0) {
-                       switch (vsp_cmd.sub_data.ipl_type) {
-                       case 0: mf_current_side = 'A';
-                               break;
-                       case 1: mf_current_side = 'B';
-                               break;
-                       case 2: mf_current_side = 'C';
-                               break;
-                       default:        mf_current_side = 'D';
-                               break;
-                       }
-               }
-       }
-
-       seq_printf(m, "%c\n", mf_current_side);
-       return 0;
-}
-
-static int mf_side_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mf_side_proc_show, NULL);
-}
-
-static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,
-                                 size_t count, loff_t *pos)
-{
-       char side;
-       u64 newSide;
-       struct vsp_cmd_data vsp_cmd;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-
-       if (count == 0)
-               return 0;
-
-       if (get_user(side, buffer))
-               return -EFAULT;
-
-       switch (side) {
-       case 'A':       newSide = 0;
-                       break;
-       case 'B':       newSide = 1;
-                       break;
-       case 'C':       newSide = 2;
-                       break;
-       case 'D':       newSide = 3;
-                       break;
-       default:
-               printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
-               return -EINVAL;
-       }
-
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.sub_data.ipl_type = newSide;
-       vsp_cmd.cmd = 10;
-
-       (void)signal_vsp_instruction(&vsp_cmd);
-
-       return count;
-}
-
-static const struct file_operations mf_side_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = mf_side_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = mf_side_proc_write,
-};
-
-static int mf_src_proc_show(struct seq_file *m, void *v)
-{
-       return 0;
-}
-
-static int mf_src_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mf_src_proc_show, NULL);
-}
-
-static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,
-                                size_t count, loff_t *pos)
-{
-       char stkbuf[10];
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-
-       if ((count < 4) && (count != 1)) {
-               printk(KERN_ERR "mf_proc: invalid src\n");
-               return -EINVAL;
-       }
-
-       if (count > (sizeof(stkbuf) - 1))
-               count = sizeof(stkbuf) - 1;
-       if (copy_from_user(stkbuf, buffer, count))
-               return -EFAULT;
-
-       if ((count == 1) && (*stkbuf == '\0'))
-               mf_clear_src();
-       else
-               mf_display_src(*(u32 *)stkbuf);
-
-       return count;
-}
-
-static const struct file_operations mf_src_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = mf_src_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = mf_src_proc_write,
-};
-
-static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,
-                                    size_t count, loff_t *pos)
-{
-       void *data = PDE(file->f_path.dentry->d_inode)->data;
-       struct vsp_cmd_data vsp_cmd;
-       dma_addr_t dma_addr;
-       char *page;
-       int ret = -EACCES;
-
-       if (!capable(CAP_SYS_ADMIN))
-               goto out;
-
-       dma_addr = 0;
-       page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
-       ret = -ENOMEM;
-       if (page == NULL)
-               goto out;
-
-       ret = -EFAULT;
-       if (copy_from_user(page, buffer, count))
-               goto out_free;
-
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 31;
-       vsp_cmd.sub_data.kern.token = dma_addr;
-       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       vsp_cmd.sub_data.kern.side = (u64)data;
-       vsp_cmd.sub_data.kern.length = count;
-       mb();
-       (void)signal_vsp_instruction(&vsp_cmd);
-       ret = count;
-
-out_free:
-       iseries_hv_free(count, page, dma_addr);
-out:
-       return ret;
-}
-
-static const struct file_operations mf_cmdline_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = mf_cmdline_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = mf_cmdline_proc_write,
-};
-
-static ssize_t proc_mf_change_vmlinux(struct file *file,
-                                     const char __user *buf,
-                                     size_t count, loff_t *ppos)
-{
-       struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
-       ssize_t rc;
-       dma_addr_t dma_addr;
-       char *page;
-       struct vsp_cmd_data vsp_cmd;
-
-       rc = -EACCES;
-       if (!capable(CAP_SYS_ADMIN))
-               goto out;
-
-       dma_addr = 0;
-       page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
-       rc = -ENOMEM;
-       if (page == NULL) {
-               printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
-               goto out;
-       }
-       rc = -EFAULT;
-       if (copy_from_user(page, buf, count))
-               goto out_free;
-
-       memset(&vsp_cmd, 0, sizeof(vsp_cmd));
-       vsp_cmd.cmd = 30;
-       vsp_cmd.sub_data.kern.token = dma_addr;
-       vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       vsp_cmd.sub_data.kern.side = (u64)dp->data;
-       vsp_cmd.sub_data.kern.offset = *ppos;
-       vsp_cmd.sub_data.kern.length = count;
-       mb();
-       rc = signal_vsp_instruction(&vsp_cmd);
-       if (rc)
-               goto out_free;
-       rc = -ENOMEM;
-       if (vsp_cmd.result_code != 0)
-               goto out_free;
-
-       *ppos += count;
-       rc = count;
-out_free:
-       iseries_hv_free(count, page, dma_addr);
-out:
-       return rc;
-}
-
-static const struct file_operations proc_vmlinux_operations = {
-       .write          = proc_mf_change_vmlinux,
-       .llseek         = default_llseek,
-};
-
-static int __init mf_proc_init(void)
-{
-       struct proc_dir_entry *mf_proc_root;
-       struct proc_dir_entry *ent;
-       struct proc_dir_entry *mf;
-       char name[2];
-       int i;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-
-       mf_proc_root = proc_mkdir("iSeries/mf", NULL);
-       if (!mf_proc_root)
-               return 1;
-
-       name[1] = '\0';
-       for (i = 0; i < 4; i++) {
-               name[0] = 'A' + i;
-               mf = proc_mkdir(name, mf_proc_root);
-               if (!mf)
-                       return 1;
-
-               ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,
-                                      &mf_cmdline_proc_fops, (void *)(long)i);
-               if (!ent)
-                       return 1;
-
-               if (i == 3)     /* no vmlinux entry for 'D' */
-                       continue;
-
-               ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,
-                                      &proc_vmlinux_operations,
-                                      (void *)(long)i);
-               if (!ent)
-                       return 1;
-       }
-
-       ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
-                         &mf_side_proc_fops);
-       if (!ent)
-               return 1;
-
-       ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
-                         &mf_src_proc_fops);
-       if (!ent)
-               return 1;
-
-       return 0;
-}
-
-__initcall(mf_proc_init);
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Get the RTC from the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
-{
-       mf_get_rtc(rtc_tm);
-       rtc_tm->tm_mon--;
-}
-
-/*
- * Set the RTC in the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-int iSeries_set_rtc_time(struct rtc_time *tm)
-{
-       mf_set_rtc(tm);
-       return 0;
-}
-
-unsigned long iSeries_get_boot_time(void)
-{
-       struct rtc_time tm;
-
-       mf_get_boot_rtc(&tm);
-       return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,
-                     tm.tm_hour, tm.tm_min, tm.tm_sec);
-}
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
deleted file mode 100644 (file)
index 2c6ff0f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file contains miscellaneous low-level functions.
- *    Copyright (C) 1995-2005 IBM Corp
- *
- * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
- * and Paul Mackerras.
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/processor.h>
-#include <asm/asm-offsets.h>
-#include <asm/ppc_asm.h>
-
-       .text
-
-/* Handle pending interrupts in interrupt context */
-_GLOBAL(iseries_handle_interrupts)
-       li      r0,0x5555
-       sc
-       blr
diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h
deleted file mode 100644 (file)
index f01708e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_NACA_H
-#define _PLATFORMS_ISERIES_NACA_H
-
-/*
- * c 2001 PPC 64 Team, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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 <asm/types.h>
-
-struct naca_struct {
-       /* Kernel only data - undefined for user space */
-       const void *xItVpdAreas;        /* VPD Data                  0x00 */
-       void *xRamDisk;                 /* iSeries ramdisk           0x08 */
-       u64   xRamDiskSize;             /* In pages                  0x10 */
-};
-
-extern struct naca_struct naca;
-
-#endif /* _PLATFORMS_ISERIES_NACA_H */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
deleted file mode 100644 (file)
index c754128..0000000
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- * Copyright (C) 2001 Allan Trautman, IBM Corporation
- * Copyright (C) 2005,2007  Stephen Rothwell, IBM Corp
- *
- * iSeries specific routines for PCI.
- *
- * Based on code from pci.c and iSeries_pci.c 32bit
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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
- */
-
-#undef DEBUG
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/of.h>
-#include <linux/ratelimit.h>
-
-#include <asm/types.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.h>
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/iommu.h>
-
-#include <asm/ppc-pci.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#define PCI_RETRY_MAX  3
-static int limit_pci_retries = 1;      /* Set Retry Error on. */
-
-/*
- * Table defines
- * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
- */
-#define IOMM_TABLE_MAX_ENTRIES 1024
-#define IOMM_TABLE_ENTRY_SIZE  0x0000000000400000UL
-#define BASE_IO_MEMORY         0xE000000000000000UL
-#define END_IO_MEMORY          0xEFFFFFFFFFFFFFFFUL
-
-static unsigned long max_io_memory = BASE_IO_MEMORY;
-static long current_iomm_table_entry;
-
-/*
- * Lookup Tables.
- */
-static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
-static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];
-
-static DEFINE_SPINLOCK(iomm_table_lock);
-
-/*
- * Generate a Direct Select Address for the Hypervisor
- */
-static inline u64 iseries_ds_addr(struct device_node *node)
-{
-       struct pci_dn *pdn = PCI_DN(node);
-       const u32 *sbp = of_get_property(node, "linux,subbus", NULL);
-
-       return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)
-                       + ((u64)0x10 << 32);
-}
-
-/*
- * Size of Bus VPD data
- */
-#define BUS_VPDSIZE      1024
-
-/*
- * Bus Vpd Tags
- */
-#define VPD_END_OF_AREA                0x79
-#define VPD_ID_STRING          0x82
-#define VPD_VENDOR_AREA                0x84
-
-/*
- * Mfg Area Tags
- */
-#define VPD_FRU_FRAME_ID       0x4649  /* "FI" */
-#define VPD_SLOT_MAP_FORMAT    0x4D46  /* "MF" */
-#define VPD_SLOT_MAP           0x534D  /* "SM" */
-
-/*
- * Structures of the areas
- */
-struct mfg_vpd_area {
-       u16     tag;
-       u8      length;
-       u8      data1;
-       u8      data2;
-};
-#define MFG_ENTRY_SIZE   3
-
-struct slot_map {
-       u8      agent;
-       u8      secondary_agent;
-       u8      phb;
-       char    card_location[3];
-       char    parms[8];
-       char    reserved[2];
-};
-#define SLOT_ENTRY_SIZE   16
-
-/*
- * Parse the Slot Area
- */
-static void __init iseries_parse_slot_area(struct slot_map *map, int len,
-               HvAgentId agent, u8 *phb, char card[4])
-{
-       /*
-        * Parse Slot label until we find the one requested
-        */
-       while (len > 0) {
-               if (map->agent == agent) {
-                       /*
-                        * If Phb wasn't found, grab the entry first one found.
-                        */
-                       if (*phb == 0xff)
-                               *phb = map->phb;
-                       /* Found it, extract the data. */
-                       if (map->phb == *phb) {
-                               memcpy(card, &map->card_location, 3);
-                               card[3]  = 0;
-                               break;
-                       }
-               }
-               /* Point to the next Slot */
-               map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
-               len -= SLOT_ENTRY_SIZE;
-       }
-}
-
-/*
- * Parse the Mfg Area
- */
-static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
-               HvAgentId agent, u8 *phb, u8 *frame, char card[4])
-{
-       u16 slot_map_fmt = 0;
-
-       /* Parse Mfg Data */
-       while (len > 0) {
-               int mfg_tag_len = area->length;
-               /* Frame ID         (FI 4649020310 ) */
-               if (area->tag == VPD_FRU_FRAME_ID)
-                       *frame = area->data1;
-               /* Slot Map Format  (MF 4D46020004 ) */
-               else if (area->tag == VPD_SLOT_MAP_FORMAT)
-                       slot_map_fmt = (area->data1 * 256)
-                               + area->data2;
-               /* Slot Map         (SM 534D90 */
-               else if (area->tag == VPD_SLOT_MAP) {
-                       struct slot_map *slot_map;
-
-                       if (slot_map_fmt == 0x1004)
-                               slot_map = (struct slot_map *)((char *)area
-                                               + MFG_ENTRY_SIZE + 1);
-                       else
-                               slot_map = (struct slot_map *)((char *)area
-                                               + MFG_ENTRY_SIZE);
-                       iseries_parse_slot_area(slot_map, mfg_tag_len,
-                                       agent, phb, card);
-               }
-               /*
-                * Point to the next Mfg Area
-                * Use defined size, sizeof give wrong answer
-                */
-               area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
-                               + MFG_ENTRY_SIZE);
-               len -= (mfg_tag_len + MFG_ENTRY_SIZE);
-       }
-}
-
-/*
- * Look for "BUS".. Data is not Null terminated.
- * PHBID of 0xFF indicates PHB was not found in VPD Data.
- */
-static u8 __init iseries_parse_phbid(u8 *area, int len)
-{
-       while (len > 0) {
-               if ((*area == 'B') && (*(area + 1) == 'U')
-                               && (*(area + 2) == 'S')) {
-                       area += 3;
-                       while (*area == ' ')
-                               area++;
-                       return *area & 0x0F;
-               }
-               area++;
-               len--;
-       }
-       return 0xff;
-}
-
-/*
- * Parse out the VPD Areas
- */
-static void __init iseries_parse_vpd(u8 *data, int data_len,
-               HvAgentId agent, u8 *frame, char card[4])
-{
-       u8 phb = 0xff;
-
-       while (data_len > 0) {
-               int len;
-               u8 tag = *data;
-
-               if (tag == VPD_END_OF_AREA)
-                       break;
-               len = *(data + 1) + (*(data + 2) * 256);
-               data += 3;
-               data_len -= 3;
-               if (tag == VPD_ID_STRING)
-                       phb = iseries_parse_phbid(data, len);
-               else if (tag == VPD_VENDOR_AREA)
-                       iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
-                                       agent, &phb, frame, card);
-               /* Point to next Area. */
-               data += len;
-               data_len -= len;
-       }
-}
-
-static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
-               u8 *frame, char card[4])
-{
-       int status = 0;
-       int bus_vpd_len = 0;
-       u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
-
-       if (bus_vpd == NULL) {
-               printk("PCI: Bus VPD Buffer allocation failure.\n");
-               return 0;
-       }
-       bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
-                                       BUS_VPDSIZE);
-       if (bus_vpd_len == 0) {
-               printk("PCI: Bus VPD Buffer zero length.\n");
-               goto out_free;
-       }
-       /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
-       /* Make sure this is what I think it is */
-       if (*bus_vpd != VPD_ID_STRING) {
-               printk("PCI: Bus VPD Buffer missing starting tag.\n");
-               goto out_free;
-       }
-       iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
-       status = 1;
-out_free:
-       kfree(bus_vpd);
-       return status;
-}
-
-/*
- * Prints the device information.
- * - Pass in pci_dev* pointer to the device.
- * - Pass in the device count
- *
- * Format:
- * PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet
- * controller
- */
-static void __init iseries_device_information(struct pci_dev *pdev,
-                                             u16 bus, HvSubBusNumber subbus)
-{
-       u8 frame = 0;
-       char card[4];
-       HvAgentId agent;
-
-       agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
-                       ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
-
-       if (iseries_get_location_code(bus, agent, &frame, card)) {
-               printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
-                      "Card %4s  0x%04X\n", pci_name(pdev), pdev->vendor,
-                      frame, card, (int)(pdev->class >> 8));
-       }
-}
-
-/*
- * iomm_table_allocate_entry
- *
- * Adds pci_dev entry in address translation table
- *
- * - Allocates the number of entries required in table base on BAR
- *   size.
- * - Allocates starting at BASE_IO_MEMORY and increases.
- * - The size is round up to be a multiple of entry size.
- * - CurrentIndex is incremented to keep track of the last entry.
- * - Builds the resource entry for allocated BARs.
- */
-static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
-{
-       struct resource *bar_res = &dev->resource[bar_num];
-       long bar_size = pci_resource_len(dev, bar_num);
-       struct device_node *dn = pci_device_to_OF_node(dev);
-
-       /*
-        * No space to allocate, quick exit, skip Allocation.
-        */
-       if (bar_size == 0)
-               return;
-       /*
-        * Set Resource values.
-        */
-       spin_lock(&iomm_table_lock);
-       bar_res->start = BASE_IO_MEMORY +
-               IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
-       bar_res->end = bar_res->start + bar_size - 1;
-       /*
-        * Allocate the number of table entries needed for BAR.
-        */
-       while (bar_size > 0 ) {
-               iomm_table[current_iomm_table_entry] = dn;
-               ds_addr_table[current_iomm_table_entry] =
-                       iseries_ds_addr(dn) | (bar_num << 24);
-               bar_size -= IOMM_TABLE_ENTRY_SIZE;
-               ++current_iomm_table_entry;
-       }
-       max_io_memory = BASE_IO_MEMORY +
-               IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
-       spin_unlock(&iomm_table_lock);
-}
-
-/*
- * allocate_device_bars
- *
- * - Allocates ALL pci_dev BAR's and updates the resources with the
- *   BAR value.  BARS with zero length will have the resources
- *   The HvCallPci_getBarParms is used to get the size of the BAR
- *   space.  It calls iomm_table_allocate_entry to allocate
- *   each entry.
- * - Loops through The Bar resources(0 - 5) including the ROM
- *   is resource(6).
- */
-static void __init allocate_device_bars(struct pci_dev *dev)
-{
-       int bar_num;
-
-       for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
-               iomm_table_allocate_entry(dev, bar_num);
-}
-
-/*
- * Log error information to system console.
- * Filter out the device not there errors.
- * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
- */
-static void pci_log_error(char *error, int bus, int subbus,
-               int agent, int hv_res)
-{
-       if (hv_res == 0x0302)
-               return;
-       printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
-              error, bus, subbus, agent, hv_res);
-}
-
-/*
- * Look down the chain to find the matching Device Device
- */
-static struct device_node *find_device_node(int bus, int devfn)
-{
-       struct device_node *node;
-
-       for (node = NULL; (node = of_find_all_nodes(node)); ) {
-               struct pci_dn *pdn = PCI_DN(node);
-
-               if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
-                       return node;
-       }
-       return NULL;
-}
-
-/*
- * iSeries_pcibios_fixup_resources
- *
- * Fixes up all resources for devices
- */
-void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
-{
-       const u32 *agent;
-       const u32 *sub_bus;
-       unsigned char bus = pdev->bus->number;
-       struct device_node *node;
-       int i;
-
-       node = pci_device_to_OF_node(pdev);
-       pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
-                pci_name(pdev), pdev, node);
-       if (!node) {
-               printk("PCI: %s disabled, device tree entry not found !\n",
-                      pci_name(pdev));
-               for (i = 0; i <= PCI_ROM_RESOURCE; i++)
-                       pdev->resource[i].flags = 0;
-               return;
-       }
-       sub_bus = of_get_property(node, "linux,subbus", NULL);
-       agent = of_get_property(node, "linux,agent-id", NULL);
-       if (agent && sub_bus) {
-               u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
-               int err;
-
-               err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
-               if (err)
-                       pci_log_error("Connect Bus Unit",
-                                     bus, *sub_bus, *agent, err);
-               else {
-                       err = HvCallPci_configStore8(bus, *sub_bus,
-                                       *agent, PCI_INTERRUPT_LINE, irq);
-                       if (err)
-                               pci_log_error("PciCfgStore Irq Failed!",
-                                               bus, *sub_bus, *agent, err);
-                       else
-                               pdev->irq = irq;
-               }
-       }
-
-       allocate_device_bars(pdev);
-       if (likely(sub_bus))
-               iseries_device_information(pdev, bus, *sub_bus);
-       else
-               printk(KERN_ERR "PCI: Device node %s has missing or invalid "
-                               "linux,subbus property\n", node->full_name);
-}
-
-/*
- * iSeries_pci_final_fixup(void)
- */
-void __init iSeries_pci_final_fixup(void)
-{
-       /* Fix up at the device node and pci_dev relationship */
-       mf_display_src(0xC9000100);
-       iSeries_activate_IRQs();
-       mf_display_src(0xC9000200);
-}
-
-/*
- * Config space read and write functions.
- * For now at least, we look for the device node for the bus and devfn
- * that we are asked to access.  It may be possible to translate the devfn
- * to a subbus and deviceid more directly.
- */
-static u64 hv_cfg_read_func[4]  = {
-       HvCallPciConfigLoad8, HvCallPciConfigLoad16,
-       HvCallPciConfigLoad32, HvCallPciConfigLoad32
-};
-
-static u64 hv_cfg_write_func[4] = {
-       HvCallPciConfigStore8, HvCallPciConfigStore16,
-       HvCallPciConfigStore32, HvCallPciConfigStore32
-};
-
-/*
- * Read PCI config space
- */
-static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-               int offset, int size, u32 *val)
-{
-       struct device_node *node = find_device_node(bus->number, devfn);
-       u64 fn;
-       struct HvCallPci_LoadReturn ret;
-
-       if (node == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (offset > 255) {
-               *val = ~0;
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-       }
-
-       fn = hv_cfg_read_func[(size - 1) & 3];
-       HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);
-
-       if (ret.rc != 0) {
-               *val = ~0;
-               return PCIBIOS_DEVICE_NOT_FOUND;        /* or something */
-       }
-
-       *val = ret.value;
-       return 0;
-}
-
-/*
- * Write PCI config space
- */
-
-static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-               int offset, int size, u32 val)
-{
-       struct device_node *node = find_device_node(bus->number, devfn);
-       u64 fn;
-       u64 ret;
-
-       if (node == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       if (offset > 255)
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       fn = hv_cfg_write_func[(size - 1) & 3];
-       ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);
-
-       if (ret != 0)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       return 0;
-}
-
-static struct pci_ops iSeries_pci_ops = {
-       .read = iSeries_pci_read_config,
-       .write = iSeries_pci_write_config
-};
-
-/*
- * Check Return Code
- * -> On Failure, print and log information.
- *    Increment Retry Count, if exceeds max, panic partition.
- *
- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
- * PCI: Device 23.90 ReadL Retry( 1)
- * PCI: Device 23.90 ReadL Retry Successful(1)
- */
-static int check_return_code(char *type, struct device_node *dn,
-               int *retry, u64 ret)
-{
-       if (ret != 0)  {
-               struct pci_dn *pdn = PCI_DN(dn);
-
-               (*retry)++;
-               printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
-                               type, pdn->busno, pdn->devfn,
-                               *retry, (int)ret);
-               /*
-                * Bump the retry and check for retry count exceeded.
-                * If, Exceeded, panic the system.
-                */
-               if (((*retry) > PCI_RETRY_MAX) &&
-                               (limit_pci_retries > 0)) {
-                       mf_display_src(0xB6000103);
-                       panic_timeout = 0;
-                       panic("PCI: Hardware I/O Error, SRC B6000103, "
-                                       "Automatic Reboot Disabled.\n");
-               }
-               return -1;      /* Retry Try */
-       }
-       return 0;
-}
-
-/*
- * Translate the I/O Address into a device node, bar, and bar offset.
- * Note: Make sure the passed variable end up on the stack to avoid
- * the exposure of being device global.
- */
-static inline struct device_node *xlate_iomm_address(
-               const volatile void __iomem *addr,
-               u64 *dsaptr, u64 *bar_offset, const char *func)
-{
-       unsigned long orig_addr;
-       unsigned long base_addr;
-       unsigned long ind;
-       struct device_node *dn;
-
-       orig_addr = (unsigned long __force)addr;
-       if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {
-               static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10);
-
-               if (__ratelimit(&ratelimit))
-                       printk(KERN_ERR
-                               "iSeries_%s: invalid access at IO address %p\n",
-                               func, addr);
-               return NULL;
-       }
-       base_addr = orig_addr - BASE_IO_MEMORY;
-       ind = base_addr / IOMM_TABLE_ENTRY_SIZE;
-       dn = iomm_table[ind];
-
-       if (dn != NULL) {
-               *dsaptr = ds_addr_table[ind];
-               *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
-       } else
-               panic("PCI: Invalid PCI IO address detected!\n");
-       return dn;
-}
-
-/*
- * Read MM I/O Instructions for the iSeries
- * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
- * else, data is returned in Big Endian format.
- */
-static u8 iseries_readb(const volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       struct HvCallPci_LoadReturn ret;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");
-
-       if (dn == NULL)
-               return 0xff;
-       do {
-               HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);
-       } while (check_return_code("RDB", dn, &retry, ret.rc) != 0);
-
-       return ret.value;
-}
-
-static u16 iseries_readw_be(const volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       struct HvCallPci_LoadReturn ret;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");
-
-       if (dn == NULL)
-               return 0xffff;
-       do {
-               HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
-                               bar_offset, 0);
-       } while (check_return_code("RDW", dn, &retry, ret.rc) != 0);
-
-       return ret.value;
-}
-
-static u32 iseries_readl_be(const volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       struct HvCallPci_LoadReturn ret;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");
-
-       if (dn == NULL)
-               return 0xffffffff;
-       do {
-               HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
-                               bar_offset, 0);
-       } while (check_return_code("RDL", dn, &retry, ret.rc) != 0);
-
-       return ret.value;
-}
-
-/*
- * Write MM I/O Instructions for the iSeries
- *
- */
-static void iseries_writeb(u8 data, volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       u64 rc;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");
-
-       if (dn == NULL)
-               return;
-       do {
-               rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);
-       } while (check_return_code("WWB", dn, &retry, rc) != 0);
-}
-
-static void iseries_writew_be(u16 data, volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       u64 rc;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");
-
-       if (dn == NULL)
-               return;
-       do {
-               rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);
-       } while (check_return_code("WWW", dn, &retry, rc) != 0);
-}
-
-static void iseries_writel_be(u32 data, volatile void __iomem *addr)
-{
-       u64 bar_offset;
-       u64 dsa;
-       int retry = 0;
-       u64 rc;
-       struct device_node *dn =
-               xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");
-
-       if (dn == NULL)
-               return;
-       do {
-               rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);
-       } while (check_return_code("WWL", dn, &retry, rc) != 0);
-}
-
-static u16 iseries_readw(const volatile void __iomem *addr)
-{
-       return le16_to_cpu(iseries_readw_be(addr));
-}
-
-static u32 iseries_readl(const volatile void __iomem *addr)
-{
-       return le32_to_cpu(iseries_readl_be(addr));
-}
-
-static void iseries_writew(u16 data, volatile void __iomem *addr)
-{
-       iseries_writew_be(cpu_to_le16(data), addr);
-}
-
-static void iseries_writel(u32 data, volatile void __iomem *addr)
-{
-       iseries_writel(cpu_to_le32(data), addr);
-}
-
-static void iseries_readsb(const volatile void __iomem *addr, void *buf,
-                          unsigned long count)
-{
-       u8 *dst = buf;
-       while(count-- > 0)
-               *(dst++) = iseries_readb(addr);
-}
-
-static void iseries_readsw(const volatile void __iomem *addr, void *buf,
-                          unsigned long count)
-{
-       u16 *dst = buf;
-       while(count-- > 0)
-               *(dst++) = iseries_readw_be(addr);
-}
-
-static void iseries_readsl(const volatile void __iomem *addr, void *buf,
-                          unsigned long count)
-{
-       u32 *dst = buf;
-       while(count-- > 0)
-               *(dst++) = iseries_readl_be(addr);
-}
-
-static void iseries_writesb(volatile void __iomem *addr, const void *buf,
-                           unsigned long count)
-{
-       const u8 *src = buf;
-       while(count-- > 0)
-               iseries_writeb(*(src++), addr);
-}
-
-static void iseries_writesw(volatile void __iomem *addr, const void *buf,
-                           unsigned long count)
-{
-       const u16 *src = buf;
-       while(count-- > 0)
-               iseries_writew_be(*(src++), addr);
-}
-
-static void iseries_writesl(volatile void __iomem *addr, const void *buf,
-                           unsigned long count)
-{
-       const u32 *src = buf;
-       while(count-- > 0)
-               iseries_writel_be(*(src++), addr);
-}
-
-static void iseries_memset_io(volatile void __iomem *addr, int c,
-                             unsigned long n)
-{
-       volatile char __iomem *d = addr;
-
-       while (n-- > 0)
-               iseries_writeb(c, d++);
-}
-
-static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
-                                 unsigned long n)
-{
-       char *d = dest;
-       const volatile char __iomem *s = src;
-
-       while (n-- > 0)
-               *d++ = iseries_readb(s++);
-}
-
-static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
-                               unsigned long n)
-{
-       const char *s = src;
-       volatile char __iomem *d = dest;
-
-       while (n-- > 0)
-               iseries_writeb(*s++, d++);
-}
-
-/* We only set MMIO ops. The default PIO ops will be default
- * to the MMIO ops + pci_io_base which is 0 on iSeries as
- * expected so both should work.
- *
- * Note that we don't implement the readq/writeq versions as
- * I don't know of an HV call for doing so. Thus, the default
- * operation will be used instead, which will fault a the value
- * return by iSeries for MMIO addresses always hits a non mapped
- * area. This is as good as the BUG() we used to have there.
- */
-static struct ppc_pci_io __initdata iseries_pci_io = {
-       .readb = iseries_readb,
-       .readw = iseries_readw,
-       .readl = iseries_readl,
-       .readw_be = iseries_readw_be,
-       .readl_be = iseries_readl_be,
-       .writeb = iseries_writeb,
-       .writew = iseries_writew,
-       .writel = iseries_writel,
-       .writew_be = iseries_writew_be,
-       .writel_be = iseries_writel_be,
-       .readsb = iseries_readsb,
-       .readsw = iseries_readsw,
-       .readsl = iseries_readsl,
-       .writesb = iseries_writesb,
-       .writesw = iseries_writesw,
-       .writesl = iseries_writesl,
-       .memset_io = iseries_memset_io,
-       .memcpy_fromio = iseries_memcpy_fromio,
-       .memcpy_toio = iseries_memcpy_toio,
-};
-
-/*
- * iSeries_pcibios_init
- *
- * Description:
- *   This function checks for all possible system PCI host bridges that connect
- *   PCI buses.  The system hypervisor is queried as to the guest partition
- *   ownership status.  A pci_controller is built for any bus which is partially
- *   owned or fully owned by this guest partition.
- */
-void __init iSeries_pcibios_init(void)
-{
-       struct pci_controller *phb;
-       struct device_node *root = of_find_node_by_path("/");
-       struct device_node *node = NULL;
-
-       /* Install IO hooks */
-       ppc_pci_io = iseries_pci_io;
-
-       pci_probe_only = 1;
-
-       /* iSeries has no IO space in the common sense, it needs to set
-        * the IO base to 0
-        */
-       pci_io_base = 0;
-
-       if (root == NULL) {
-               printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
-                               "of device tree\n");
-               return;
-       }
-       while ((node = of_get_next_child(root, node)) != NULL) {
-               HvBusNumber bus;
-               const u32 *busp;
-
-               if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
-                       continue;
-
-               busp = of_get_property(node, "bus-range", NULL);
-               if (busp == NULL)
-                       continue;
-               bus = *busp;
-               printk("bus %d appears to exist\n", bus);
-               phb = pcibios_alloc_controller(node);
-               if (phb == NULL)
-                       continue;
-               /* All legacy iSeries PHBs are in domain zero */
-               phb->global_number = 0;
-
-               phb->first_busno = bus;
-               phb->last_busno = bus;
-               phb->ops = &iSeries_pci_ops;
-               phb->io_base_virt = (void __iomem *)_IO_BASE;
-               phb->io_resource.flags = IORESOURCE_IO;
-               phb->io_resource.start = BASE_IO_MEMORY;
-               phb->io_resource.end = END_IO_MEMORY;
-               phb->io_resource.name = "iSeries PCI IO";
-               phb->mem_resources[0].flags = IORESOURCE_MEM;
-               phb->mem_resources[0].start = BASE_IO_MEMORY;
-               phb->mem_resources[0].end = END_IO_MEMORY;
-               phb->mem_resources[0].name = "Series PCI MEM";
-       }
-
-       of_node_put(root);
-
-       pci_devs_phb_init();
-}
-
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h
deleted file mode 100644 (file)
index d9cf974..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_PCI_H
-#define _PLATFORMS_ISERIES_PCI_H
-
-/*
- * Created by Allan Trautman on Tue Feb 20, 2001.
- *
- * Define some useful macros for the iSeries pci routines.
- * Copyright (C) 2001  Allan H Trautman, IBM 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; 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
- *
- * Change Activity:
- *   Created Feb 20, 2001
- *   Added device reset, March 22, 2001
- *   Ported to ppc64, May 25, 2001
- * End Change Activity
- */
-
-/*
- * Decodes Linux DevFn to iSeries DevFn, bridge device, or function.
- * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h
- */
-
-#define ISERIES_PCI_AGENTID(idsel, func)       \
-       (((idsel & 0x0F) << 4) | (func & 0x07))
-#define ISERIES_ENCODE_DEVICE(agentid)         \
-       ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07))
-
-#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus)         ((subbus >> 5) & 0x7)
-#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)       ((subbus >> 2) & 0x7)
-
-struct pci_dev;
-
-#ifdef CONFIG_PCI
-extern void    iSeries_pcibios_init(void);
-extern void    iSeries_pci_final_fixup(void);
-extern void    iSeries_pcibios_fixup_resources(struct pci_dev *dev);
-#else
-static inline void     iSeries_pcibios_init(void) { }
-static inline void     iSeries_pci_final_fixup(void) { }
-static inline void     iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}
-#endif
-
-#endif /* _PLATFORMS_ISERIES_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c
deleted file mode 100644 (file)
index 0676368..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2001  Kyle A. Lucke IBM Corporation
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM 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; 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/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/param.h>               /* for HZ */
-#include <asm/paca.h>
-#include <asm/processor.h>
-#include <asm/time.h>
-#include <asm/lppaca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call_xm.h>
-
-#include "processor_vpd.h"
-#include "main_store.h"
-
-static int __init iseries_proc_create(void)
-{
-       struct proc_dir_entry *e;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-
-       e = proc_mkdir("iSeries", 0);
-       if (!e)
-               return 1;
-
-       return 0;
-}
-core_initcall(iseries_proc_create);
-
-static unsigned long startTitan = 0;
-static unsigned long startTb = 0;
-
-static int proc_titantod_show(struct seq_file *m, void *v)
-{
-       unsigned long tb0, titan_tod;
-
-       tb0 = get_tb();
-       titan_tod = HvCallXm_loadTod();
-
-       seq_printf(m, "Titan\n" );
-       seq_printf(m, "  time base =          %016lx\n", tb0);
-       seq_printf(m, "  titan tod =          %016lx\n", titan_tod);
-       seq_printf(m, "  xProcFreq =          %016x\n",
-                  xIoHriProcessorVpd[0].xProcFreq);
-       seq_printf(m, "  xTimeBaseFreq =      %016x\n",
-                  xIoHriProcessorVpd[0].xTimeBaseFreq);
-       seq_printf(m, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);
-       seq_printf(m, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec);
-
-       if (!startTitan) {
-               startTitan = titan_tod;
-               startTb = tb0;
-       } else {
-               unsigned long titan_usec = (titan_tod - startTitan) >> 12;
-               unsigned long tb_ticks = (tb0 - startTb);
-               unsigned long titan_jiffies = titan_usec / (1000000/HZ);
-               unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
-               unsigned long titan_jiff_rem_usec =
-                       titan_usec - titan_jiff_usec;
-               unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
-               unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
-               unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
-               unsigned long tb_jiff_rem_usec =
-                       tb_jiff_rem_ticks / tb_ticks_per_usec;
-               unsigned long new_tb_ticks_per_jiffy =
-                       (tb_ticks * (1000000/HZ))/titan_usec;
-
-               seq_printf(m, "  titan elapsed = %lu uSec\n", titan_usec);
-               seq_printf(m, "  tb elapsed    = %lu ticks\n", tb_ticks);
-               seq_printf(m, "  titan jiffies = %lu.%04lu\n", titan_jiffies,
-                          titan_jiff_rem_usec);
-               seq_printf(m, "  tb jiffies    = %lu.%04lu\n", tb_jiffies,
-                          tb_jiff_rem_usec);
-               seq_printf(m, "  new tb_ticks_per_jiffy = %lu\n",
-                          new_tb_ticks_per_jiffy);
-       }
-
-       return 0;
-}
-
-static int proc_titantod_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_titantod_show, NULL);
-}
-
-static const struct file_operations proc_titantod_operations = {
-       .open           = proc_titantod_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init iseries_proc_init(void)
-{
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-
-       proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL,
-                   &proc_titantod_operations);
-       return 0;
-}
-__initcall(iseries_proc_init);
diff --git a/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h
deleted file mode 100644 (file)
index 7ac5d0d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ISERIES_PROCESSOR_VPD_H
-#define _ISERIES_PROCESSOR_VPD_H
-
-#include <asm/types.h>
-
-/*
- * This struct maps Processor Vpd that is DMAd to SLIC by CSP
- */
-struct IoHriProcessorVpd {
-       u8      xFormat;                // VPD format indicator         x00-x00
-       u8      xProcStatus:8;          // Processor State              x01-x01
-       u8      xSecondaryThreadCount;  // Secondary thread cnt         x02-x02
-       u8      xSrcType:1;             // Src Type                     x03-x03
-       u8      xSrcSoft:1;             // Src stay soft                ...
-       u8      xSrcParable:1;          // Src parable                  ...
-       u8      xRsvd1:5;               // Reserved                     ...
-       u16     xHvPhysicalProcIndex;   // Hypervisor physical proc index04-x05
-       u16     xRsvd2;                 // Reserved                     x06-x07
-       u32     xHwNodeId;              // Hardware node id             x08-x0B
-       u32     xHwProcId;              // Hardware processor id        x0C-x0F
-
-       u32     xTypeNum;               // Card Type/CCIN number        x10-x13
-       u32     xModelNum;              // Model/Feature number         x14-x17
-       u64     xSerialNum;             // Serial number                x18-x1F
-       char    xPartNum[12];           // Book Part or FPU number      x20-x2B
-       char    xMfgID[4];              // Manufacturing ID             x2C-x2F
-
-       u32     xProcFreq;              // Processor Frequency          x30-x33
-       u32     xTimeBaseFreq;          // Time Base Frequency          x34-x37
-
-       u32     xChipEcLevel;           // Chip EC Levels               x38-x3B
-       u32     xProcIdReg;             // PIR SPR value                x3C-x3F
-       u32     xPVR;                   // PVR value                    x40-x43
-       u8      xRsvd3[12];             // Reserved                     x44-x4F
-
-       u32     xInstCacheSize;         // Instruction cache size in KB x50-x53
-       u32     xInstBlockSize;         // Instruction cache block size x54-x57
-       u32     xDataCacheOperandSize;  // Data cache operand size      x58-x5B
-       u32     xInstCacheOperandSize;  // Inst cache operand size      x5C-x5F
-
-       u32     xDataL1CacheSizeKB;     // L1 data cache size in KB     x60-x63
-       u32     xDataL1CacheLineSize;   // L1 data cache block size     x64-x67
-       u64     xRsvd4;                 // Reserved                     x68-x6F
-
-       u32     xDataL2CacheSizeKB;     // L2 data cache size in KB     x70-x73
-       u32     xDataL2CacheLineSize;   // L2 data cache block size     x74-x77
-       u64     xRsvd5;                 // Reserved                     x78-x7F
-
-       u32     xDataL3CacheSizeKB;     // L3 data cache size in KB     x80-x83
-       u32     xDataL3CacheLineSize;   // L3 data cache block size     x84-x87
-       u64     xRsvd6;                 // Reserved                     x88-x8F
-
-       u64     xFruLabel;              // Card Location Label          x90-x97
-       u8      xSlotsOnCard;           // Slots on card (0=no slots)   x98-x98
-       u8      xPartLocFlag;           // Location flag (0-pluggable 1-imbedded) x99-x99
-       u16     xSlotMapIndex;          // Index in slot map table      x9A-x9B
-       u8      xSmartCardPortNo;       // Smart card port number       x9C-x9C
-       u8      xRsvd7;                 // Reserved                     x9D-x9D
-       u16     xFrameIdAndRackUnit;    // Frame ID and rack unit adr   x9E-x9F
-
-       u8      xRsvd8[24];             // Reserved                     xA0-xB7
-
-       char    xProcSrc[72];           // CSP format SRC               xB8-xFF
-};
-
-extern struct IoHriProcessorVpd        xIoHriProcessorVpd[];
-
-#endif /* _ISERIES_PROCESSOR_VPD_H */
diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h
deleted file mode 100644 (file)
index 6ad7d84..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ISERIES_RELEASE_DATA_H
-#define _ISERIES_RELEASE_DATA_H
-
-/*
- * This control block contains the critical information about the
- * release so that it can be changed in the future (ie, the virtual
- * address of the OS's NACA).
- */
-#include <asm/types.h>
-#include "naca.h"
-
-/*
- * When we IPL a secondary partition, we will check if if the
- * secondary xMinPlicVrmIndex > the primary xVrmIndex.
- * If it is then this tells PLIC that this secondary is not
- * supported running on this "old" of a level of PLIC.
- *
- * Likewise, we will compare the primary xMinSlicVrmIndex to
- * the secondary xVrmIndex.
- * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we
- * know that this PLIC does not support running an OS "that old".
- */
-
-#define        HVREL_TAGSINACTIVE      0x8000
-#define HVREL_32BIT            0x4000
-#define HVREL_NOSHAREDPROCS    0x2000
-#define HVREL_NOHMT            0x1000
-
-struct HvReleaseData {
-       u32     xDesc;          /* Descriptor "HvRD" ebcdic     x00-x03 */
-       u16     xSize;          /* Size of this control block   x04-x05 */
-       u16     xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */
-       struct  naca_struct     *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */
-       u32     xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */
-       u32     xRsvd1;         /* Reserved                     x14-x17 */
-       u16     xFlags;
-       u16     xVrmIndex;      /* VRM Index of OS image        x1A-x1B */
-       u16     xMinSupportedPlicVrmIndex; /* Min PLIC level  (soft) x1C-x1D */
-       u16     xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */
-       char    xVrmName[12];   /* Displayable name             x20-x2B */
-       char    xRsvd3[20];     /* Reserved                     x2C-x3F */
-};
-
-extern const struct HvReleaseData      hvReleaseData;
-
-#endif /* _ISERIES_RELEASE_DATA_H */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
deleted file mode 100644 (file)
index a5fbf4c..0000000
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
- *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM iSeries LPAR.  Adapted from original code by Grant Erickson and
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.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.
- */
-
-#undef DEBUG
-
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/export.h>
-#include <linux/seq_file.h>
-#include <linux/kdev_t.h>
-#include <linux/kexec.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-#include <linux/kernel.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
-#include <asm/cputable.h>
-#include <asm/sections.h>
-#include <asm/iommu.h>
-#include <asm/firmware.h>
-#include <asm/system.h>
-#include <asm/time.h>
-#include <asm/paca.h>
-#include <asm/cache.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/udbg.h>
-#include <asm/irq.h>
-
-#include "naca.h"
-#include "setup.h"
-#include "irq.h"
-#include "vpd_areas.h"
-#include "processor_vpd.h"
-#include "it_lp_naca.h"
-#include "main_store.h"
-#include "call_sm.h"
-#include "call_hpt.h"
-#include "pci.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/* Function Prototypes */
-static unsigned long build_iSeries_Memory_Map(void);
-static void iseries_shared_idle(void);
-static void iseries_dedicated_idle(void);
-
-
-struct MemoryBlock {
-       unsigned long absStart;
-       unsigned long absEnd;
-       unsigned long logicalStart;
-       unsigned long logicalEnd;
-};
-
-/*
- * Process the main store vpd to determine where the holes in memory are
- * and return the number of physical blocks and fill in the array of
- * block data.
- */
-static unsigned long iSeries_process_Condor_mainstore_vpd(
-               struct MemoryBlock *mb_array, unsigned long max_entries)
-{
-       unsigned long holeFirstChunk, holeSizeChunks;
-       unsigned long numMemoryBlocks = 1;
-       struct IoHriMainStoreSegment4 *msVpd =
-               (struct IoHriMainStoreSegment4 *)xMsVpd;
-       unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
-       unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr;
-       unsigned long holeSize = holeEnd - holeStart;
-
-       printk("Mainstore_VPD: Condor\n");
-       /*
-        * Determine if absolute memory has any
-        * holes so that we can interpret the
-        * access map we get back from the hypervisor
-        * correctly.
-        */
-       mb_array[0].logicalStart = 0;
-       mb_array[0].logicalEnd = 0x100000000UL;
-       mb_array[0].absStart = 0;
-       mb_array[0].absEnd = 0x100000000UL;
-
-       if (holeSize) {
-               numMemoryBlocks = 2;
-               holeStart = holeStart & 0x000fffffffffffffUL;
-               holeStart = addr_to_chunk(holeStart);
-               holeFirstChunk = holeStart;
-               holeSize = addr_to_chunk(holeSize);
-               holeSizeChunks = holeSize;
-               printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",
-                               holeFirstChunk, holeSizeChunks );
-               mb_array[0].logicalEnd = holeFirstChunk;
-               mb_array[0].absEnd = holeFirstChunk;
-               mb_array[1].logicalStart = holeFirstChunk;
-               mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;
-               mb_array[1].absStart = holeFirstChunk + holeSizeChunks;
-               mb_array[1].absEnd = 0x100000000UL;
-       }
-       return numMemoryBlocks;
-}
-
-#define MaxSegmentAreas                        32
-#define MaxSegmentAdrRangeBlocks       128
-#define MaxAreaRangeBlocks             4
-
-static unsigned long iSeries_process_Regatta_mainstore_vpd(
-               struct MemoryBlock *mb_array, unsigned long max_entries)
-{
-       struct IoHriMainStoreSegment5 *msVpdP =
-               (struct IoHriMainStoreSegment5 *)xMsVpd;
-       unsigned long numSegmentBlocks = 0;
-       u32 existsBits = msVpdP->msAreaExists;
-       unsigned long area_num;
-
-       printk("Mainstore_VPD: Regatta\n");
-
-       for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
-               unsigned long numAreaBlocks;
-               struct IoHriMainStoreArea4 *currentArea;
-
-               if (existsBits & 0x80000000) {
-                       unsigned long block_num;
-
-                       currentArea = &msVpdP->msAreaArray[area_num];
-                       numAreaBlocks = currentArea->numAdrRangeBlocks;
-                       printk("ms_vpd: processing area %2ld  blocks=%ld",
-                                       area_num, numAreaBlocks);
-                       for (block_num = 0; block_num < numAreaBlocks;
-                                       ++block_num ) {
-                               /* Process an address range block */
-                               struct MemoryBlock tempBlock;
-                               unsigned long i;
-
-                               tempBlock.absStart =
-                                       (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
-                               tempBlock.absEnd =
-                                       (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
-                               tempBlock.logicalStart = 0;
-                               tempBlock.logicalEnd   = 0;
-                               printk("\n          block %ld absStart=%016lx absEnd=%016lx",
-                                               block_num, tempBlock.absStart,
-                                               tempBlock.absEnd);
-
-                               for (i = 0; i < numSegmentBlocks; ++i) {
-                                       if (mb_array[i].absStart ==
-                                                       tempBlock.absStart)
-                                               break;
-                               }
-                               if (i == numSegmentBlocks) {
-                                       if (numSegmentBlocks == max_entries)
-                                               panic("iSeries_process_mainstore_vpd: too many memory blocks");
-                                       mb_array[numSegmentBlocks] = tempBlock;
-                                       ++numSegmentBlocks;
-                               } else
-                                       printk(" (duplicate)");
-                       }
-                       printk("\n");
-               }
-               existsBits <<= 1;
-       }
-       /* Now sort the blocks found into ascending sequence */
-       if (numSegmentBlocks > 1) {
-               unsigned long m, n;
-
-               for (m = 0; m < numSegmentBlocks - 1; ++m) {
-                       for (n = numSegmentBlocks - 1; m < n; --n) {
-                               if (mb_array[n].absStart <
-                                               mb_array[n-1].absStart) {
-                                       struct MemoryBlock tempBlock;
-
-                                       tempBlock = mb_array[n];
-                                       mb_array[n] = mb_array[n-1];
-                                       mb_array[n-1] = tempBlock;
-                               }
-                       }
-               }
-       }
-       /*
-        * Assign "logical" addresses to each block.  These
-        * addresses correspond to the hypervisor "bitmap" space.
-        * Convert all addresses into units of 256K chunks.
-        */
-       {
-       unsigned long i, nextBitmapAddress;
-
-       printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);
-       nextBitmapAddress = 0;
-       for (i = 0; i < numSegmentBlocks; ++i) {
-               unsigned long length = mb_array[i].absEnd -
-                       mb_array[i].absStart;
-
-               mb_array[i].logicalStart = nextBitmapAddress;
-               mb_array[i].logicalEnd = nextBitmapAddress + length;
-               nextBitmapAddress += length;
-               printk("          Bitmap range: %016lx - %016lx\n"
-                               "        Absolute range: %016lx - %016lx\n",
-                               mb_array[i].logicalStart,
-                               mb_array[i].logicalEnd,
-                               mb_array[i].absStart, mb_array[i].absEnd);
-               mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
-                               0x000fffffffffffffUL);
-               mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &
-                               0x000fffffffffffffUL);
-               mb_array[i].logicalStart =
-                       addr_to_chunk(mb_array[i].logicalStart);
-               mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);
-       }
-       }
-
-       return numSegmentBlocks;
-}
-
-static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
-               unsigned long max_entries)
-{
-       unsigned long i;
-       unsigned long mem_blocks = 0;
-
-       if (mmu_has_feature(MMU_FTR_SLB))
-               mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
-                               max_entries);
-       else
-               mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array,
-                               max_entries);
-
-       printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks);
-       for (i = 0; i < mem_blocks; ++i) {
-               printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"
-                      "                             abs chunks %016lx - %016lx\n",
-                       i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
-                       mb_array[i].absStart, mb_array[i].absEnd);
-       }
-       return mem_blocks;
-}
-
-static void __init iSeries_get_cmdline(void)
-{
-       char *p, *q;
-
-       /* copy the command line parameter from the primary VSP  */
-       HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256,
-                       HvLpDma_Direction_RemoteToLocal);
-
-       p = cmd_line;
-       q = cmd_line + 255;
-       while(p < q) {
-               if (!*p || *p == '\n')
-                       break;
-               ++p;
-       }
-       *p = 0;
-}
-
-static void __init iSeries_init_early(void)
-{
-       DBG(" -> iSeries_init_early()\n");
-
-       /* Snapshot the timebase, for use in later recalibration */
-       iSeries_time_init_early();
-
-       /*
-        * Initialize the DMA/TCE management
-        */
-       iommu_init_early_iSeries();
-
-       /* Initialize machine-dependency vectors */
-#ifdef CONFIG_SMP
-       smp_init_iSeries();
-#endif
-
-       /* Associate Lp Event Queue 0 with processor 0 */
-       HvCallEvent_setLpEventQueueInterruptProc(0, 0);
-
-       mf_init();
-
-       DBG(" <- iSeries_init_early()\n");
-}
-
-struct mschunks_map mschunks_map = {
-       /* XXX We don't use these, but Piranha might need them. */
-       .chunk_size  = MSCHUNKS_CHUNK_SIZE,
-       .chunk_shift = MSCHUNKS_CHUNK_SHIFT,
-       .chunk_mask  = MSCHUNKS_OFFSET_MASK,
-};
-EXPORT_SYMBOL(mschunks_map);
-
-static void mschunks_alloc(unsigned long num_chunks)
-{
-       klimit = _ALIGN(klimit, sizeof(u32));
-       mschunks_map.mapping = (u32 *)klimit;
-       klimit += num_chunks * sizeof(u32);
-       mschunks_map.num_chunks = num_chunks;
-}
-
-/*
- * The iSeries may have very large memories ( > 128 GB ) and a partition
- * may get memory in "chunks" that may be anywhere in the 2**52 real
- * address space.  The chunks are 256K in size.  To map this to the
- * memory model Linux expects, the AS/400 specific code builds a
- * translation table to translate what Linux thinks are "physical"
- * addresses to the actual real addresses.  This allows us to make
- * it appear to Linux that we have contiguous memory starting at
- * physical address zero while in fact this could be far from the truth.
- * To avoid confusion, I'll let the words physical and/or real address
- * apply to the Linux addresses while I'll use "absolute address" to
- * refer to the actual hardware real address.
- *
- * build_iSeries_Memory_Map gets information from the Hypervisor and
- * looks at the Main Store VPD to determine the absolute addresses
- * of the memory that has been assigned to our partition and builds
- * a table used to translate Linux's physical addresses to these
- * absolute addresses.  Absolute addresses are needed when
- * communicating with the hypervisor (e.g. to build HPT entries)
- *
- * Returns the physical memory size
- */
-
-static unsigned long __init build_iSeries_Memory_Map(void)
-{
-       u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
-       u32 nextPhysChunk;
-       u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
-       u32 totalChunks,moreChunks;
-       u32 currChunk, thisChunk, absChunk;
-       u32 currDword;
-       u32 chunkBit;
-       u64 map;
-       struct MemoryBlock mb[32];
-       unsigned long numMemoryBlocks, curBlock;
-
-       /* Chunk size on iSeries is 256K bytes */
-       totalChunks = (u32)HvLpConfig_getMsChunks();
-       mschunks_alloc(totalChunks);
-
-       /*
-        * Get absolute address of our load area
-        * and map it to physical address 0
-        * This guarantees that the loadarea ends up at physical 0
-        * otherwise, it might not be returned by PLIC as the first
-        * chunks
-        */
-
-       loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
-       loadAreaSize =  itLpNaca.xLoadAreaChunks;
-
-       /*
-        * Only add the pages already mapped here.
-        * Otherwise we might add the hpt pages
-        * The rest of the pages of the load area
-        * aren't in the HPT yet and can still
-        * be assigned an arbitrary physical address
-        */
-       if ((loadAreaSize * 64) > HvPagesToMap)
-               loadAreaSize = HvPagesToMap / 64;
-
-       loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
-
-       /*
-        * TODO Do we need to do something if the HPT is in the 64MB load area?
-        * This would be required if the itLpNaca.xLoadAreaChunks includes
-        * the HPT size
-        */
-
-       printk("Mapping load area - physical addr = 0000000000000000\n"
-               "                    absolute addr = %016lx\n",
-               chunk_to_addr(loadAreaFirstChunk));
-       printk("Load area size %dK\n", loadAreaSize * 256);
-
-       for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
-               mschunks_map.mapping[nextPhysChunk] =
-                       loadAreaFirstChunk + nextPhysChunk;
-
-       /*
-        * Get absolute address of our HPT and remember it so
-        * we won't map it to any physical address
-        */
-       hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
-       hptSizePages = (u32)HvCallHpt_getHptPages();
-       hptSizeChunks = hptSizePages >>
-               (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);
-       hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
-
-       printk("HPT absolute addr = %016lx, size = %dK\n",
-                       chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);
-
-       /*
-        * Determine if absolute memory has any
-        * holes so that we can interpret the
-        * access map we get back from the hypervisor
-        * correctly.
-        */
-       numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32);
-
-       /*
-        * Process the main store access map from the hypervisor
-        * to build up our physical -> absolute translation table
-        */
-       curBlock = 0;
-       currChunk = 0;
-       currDword = 0;
-       moreChunks = totalChunks;
-
-       while (moreChunks) {
-               map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex,
-                               currDword);
-               thisChunk = currChunk;
-               while (map) {
-                       chunkBit = map >> 63;
-                       map <<= 1;
-                       if (chunkBit) {
-                               --moreChunks;
-                               while (thisChunk >= mb[curBlock].logicalEnd) {
-                                       ++curBlock;
-                                       if (curBlock >= numMemoryBlocks)
-                                               panic("out of memory blocks");
-                               }
-                               if (thisChunk < mb[curBlock].logicalStart)
-                                       panic("memory block error");
-
-                               absChunk = mb[curBlock].absStart +
-                                       (thisChunk - mb[curBlock].logicalStart);
-                               if (((absChunk < hptFirstChunk) ||
-                                    (absChunk > hptLastChunk)) &&
-                                   ((absChunk < loadAreaFirstChunk) ||
-                                    (absChunk > loadAreaLastChunk))) {
-                                       mschunks_map.mapping[nextPhysChunk] =
-                                               absChunk;
-                                       ++nextPhysChunk;
-                               }
-                       }
-                       ++thisChunk;
-               }
-               ++currDword;
-               currChunk += 64;
-       }
-
-       /*
-        * main store size (in chunks) is
-        *   totalChunks - hptSizeChunks
-        * which should be equal to
-        *   nextPhysChunk
-        */
-       return chunk_to_addr(nextPhysChunk);
-}
-
-/*
- * Document me.
- */
-static void __init iSeries_setup_arch(void)
-{
-       if (get_lppaca()->shared_proc) {
-               ppc_md.idle_loop = iseries_shared_idle;
-               printk(KERN_DEBUG "Using shared processor idle loop\n");
-       } else {
-               ppc_md.idle_loop = iseries_dedicated_idle;
-               printk(KERN_DEBUG "Using dedicated idle loop\n");
-       }
-
-       /* Setup the Lp Event Queue */
-       setup_hvlpevent_queue();
-
-       printk("Max  logical processors = %d\n",
-                       itVpdAreas.xSlicMaxLogicalProcs);
-       printk("Max physical processors = %d\n",
-                       itVpdAreas.xSlicMaxPhysicalProcs);
-
-       iSeries_pcibios_init();
-}
-
-static void iSeries_show_cpuinfo(struct seq_file *m)
-{
-       seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
-}
-
-static void __init iSeries_progress(char * st, unsigned short code)
-{
-       printk("Progress: [%04x] - %s\n", (unsigned)code, st);
-       mf_display_progress(code);
-}
-
-static void __init iSeries_fixup_klimit(void)
-{
-       /*
-        * Change klimit to take into account any ram disk
-        * that may be included
-        */
-       if (naca.xRamDisk)
-               klimit = KERNELBASE + (u64)naca.xRamDisk +
-                       (naca.xRamDiskSize * HW_PAGE_SIZE);
-}
-
-static int __init iSeries_src_init(void)
-{
-        /* clear the progress line */
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               ppc_md.progress(" ", 0xffff);
-        return 0;
-}
-
-late_initcall(iSeries_src_init);
-
-static inline void process_iSeries_events(void)
-{
-       asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
-       unsigned long tb;
-
-       HvCall_setEnabledInterrupts(HvCall_MaskIPI |
-                                   HvCall_MaskLpEvent |
-                                   HvCall_MaskLpProd |
-                                   HvCall_MaskTimeout);
-
-       tb = get_tb();
-       /* Compute future tb value when yield should expire */
-       HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
-       /*
-        * The decrementer stops during the yield.  Force a fake decrementer
-        * here and let the timer_interrupt code sort out the actual time.
-        */
-       get_lppaca()->int_dword.fields.decr_int = 1;
-       ppc64_runlatch_on();
-       process_iSeries_events();
-}
-
-static void iseries_shared_idle(void)
-{
-       while (1) {
-               tick_nohz_idle_enter();
-               rcu_idle_enter();
-               while (!need_resched() && !hvlpevent_is_pending()) {
-                       local_irq_disable();
-                       ppc64_runlatch_off();
-
-                       /* Recheck with irqs off */
-                       if (!need_resched() && !hvlpevent_is_pending())
-                               yield_shared_processor();
-
-                       HMT_medium();
-                       local_irq_enable();
-               }
-
-               ppc64_runlatch_on();
-               rcu_idle_exit();
-               tick_nohz_idle_exit();
-
-               if (hvlpevent_is_pending())
-                       process_iSeries_events();
-
-               schedule_preempt_disabled();
-       }
-}
-
-static void iseries_dedicated_idle(void)
-{
-       set_thread_flag(TIF_POLLING_NRFLAG);
-
-       while (1) {
-               tick_nohz_idle_enter();
-               rcu_idle_enter();
-               if (!need_resched()) {
-                       while (!need_resched()) {
-                               ppc64_runlatch_off();
-                               HMT_low();
-
-                               if (hvlpevent_is_pending()) {
-                                       HMT_medium();
-                                       ppc64_runlatch_on();
-                                       process_iSeries_events();
-                               }
-                       }
-
-                       HMT_medium();
-               }
-
-               ppc64_runlatch_on();
-               rcu_idle_exit();
-               tick_nohz_idle_exit();
-               schedule_preempt_disabled();
-       }
-}
-
-static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
-                                    unsigned long flags, void *caller)
-{
-       return (void __iomem *)address;
-}
-
-static void iseries_iounmap(volatile void __iomem *token)
-{
-}
-
-static int __init iseries_probe(void)
-{
-       unsigned long root = of_get_flat_dt_root();
-       if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
-               return 0;
-
-       hpte_init_iSeries();
-       /* iSeries does not support 16M pages */
-       cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;
-
-       return 1;
-}
-
-#ifdef CONFIG_KEXEC
-static int iseries_kexec_prepare(struct kimage *image)
-{
-       return -ENOSYS;
-}
-#endif
-
-define_machine(iseries) {
-       .name                   = "iSeries",
-       .setup_arch             = iSeries_setup_arch,
-       .show_cpuinfo           = iSeries_show_cpuinfo,
-       .init_IRQ               = iSeries_init_IRQ,
-       .get_irq                = iSeries_get_irq,
-       .init_early             = iSeries_init_early,
-       .pcibios_fixup          = iSeries_pci_final_fixup,
-       .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
-       .restart                = mf_reboot,
-       .power_off              = mf_power_off,
-       .halt                   = mf_power_off,
-       .get_boot_time          = iSeries_get_boot_time,
-       .set_rtc_time           = iSeries_set_rtc_time,
-       .get_rtc_time           = iSeries_get_rtc_time,
-       .calibrate_decr         = generic_calibrate_decr,
-       .progress               = iSeries_progress,
-       .probe                  = iseries_probe,
-       .ioremap                = iseries_ioremap,
-       .iounmap                = iseries_iounmap,
-#ifdef CONFIG_KEXEC
-       .machine_kexec_prepare  = iseries_kexec_prepare,
-#endif
-       /* XXX Implement enable_pmcs for iSeries */
-};
-
-void * __init iSeries_early_setup(void)
-{
-       unsigned long phys_mem_size;
-
-       /* Identify CPU type. This is done again by the common code later
-        * on but calling this function multiple times is fine.
-        */
-       identify_cpu(0, mfspr(SPRN_PVR));
-       initialise_paca(&boot_paca, 0);
-
-       powerpc_firmware_features |= FW_FEATURE_ISERIES;
-       powerpc_firmware_features |= FW_FEATURE_LPAR;
-
-#ifdef CONFIG_SMP
-       /* On iSeries we know we can never have more than 64 cpus */
-       nr_cpu_ids = max(nr_cpu_ids, 64);
-#endif
-
-       iSeries_fixup_klimit();
-
-       /*
-        * Initialize the table which translate Linux physical addresses to
-        * AS/400 absolute addresses
-        */
-       phys_mem_size = build_iSeries_Memory_Map();
-
-       iSeries_get_cmdline();
-
-       return (void *) __pa(build_flat_dt(phys_mem_size));
-}
-
-static void hvputc(char c)
-{
-       if (c == '\n')
-               hvputc('\r');
-
-       HvCall_writeLogBuffer(&c, 1);
-}
-
-void __init udbg_init_iseries(void)
-{
-       udbg_putc = hvputc;
-}
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
deleted file mode 100644 (file)
index 729754b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dan@netx4.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        __ISERIES_SETUP_H__
-#define        __ISERIES_SETUP_H__
-
-extern void *iSeries_early_setup(void);
-extern unsigned long iSeries_get_boot_time(void);
-extern int iSeries_set_rtc_time(struct rtc_time *tm);
-extern void iSeries_get_rtc_time(struct rtc_time *tm);
-
-extern void *build_flat_dt(unsigned long phys_mem_size);
-
-#endif /* __ISERIES_SETUP_H__ */
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
deleted file mode 100644 (file)
index 02df49f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SMP support for iSeries machines.
- *
- * Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
- *
- * Plus various changes from other IBM teams...
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/cpu.h>
-
-#include <asm/ptrace.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/paca.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/time.h>
-#include <asm/machdep.h>
-#include <asm/cputable.h>
-#include <asm/system.h>
-
-static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
-{
-       HvCall_sendIPI(&(paca[cpu]));
-}
-
-static int smp_iSeries_probe(void)
-{
-       return cpumask_weight(cpu_possible_mask);
-}
-
-static int smp_iSeries_kick_cpu(int nr)
-{
-       BUG_ON((nr < 0) || (nr >= NR_CPUS));
-
-       /* Verify that our partition has a processor nr */
-       if (lppaca_of(nr).dyn_proc_status >= 2)
-               return -ENOENT;
-
-       /* The processor is currently spinning, waiting
-        * for the cpu_start field to become non-zero
-        * After we set cpu_start, the processor will
-        * continue on to secondary_start in iSeries_head.S
-        */
-       paca[nr].cpu_start = 1;
-
-       return 0;
-}
-
-static void __devinit smp_iSeries_setup_cpu(int nr)
-{
-}
-
-static struct smp_ops_t iSeries_smp_ops = {
-       .message_pass = NULL,   /* Use smp_muxed_ipi_message_pass */
-       .cause_ipi    = smp_iSeries_cause_ipi,
-       .probe        = smp_iSeries_probe,
-       .kick_cpu     = smp_iSeries_kick_cpu,
-       .setup_cpu    = smp_iSeries_setup_cpu,
-};
-
-/* This is called very early. */
-void __init smp_init_iSeries(void)
-{
-       smp_ops = &iSeries_smp_ops;
-}
diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h
deleted file mode 100644 (file)
index 598b7c1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#ifndef _ISERIES_SPCOMM_AREA_H
-#define _ISERIES_SPCOMM_AREA_H
-
-
-struct SpCommArea {
-       u32     xDesc;                  // Descriptor (only in new formats)     000-003
-       u8      xFormat;                // Format (only in new formats)         004-004
-       u8      xRsvd1[11];             // Reserved                             005-00F
-       u64     xRawTbAtIplStart;       // Raw HW TB value when IPL is started  010-017
-       u64     xRawTodAtIplStart;      // Raw HW TOD value when IPL is started 018-01F
-       u64     xBcdTimeAtIplStart;     // BCD time when IPL is started         020-027
-       u64     xBcdTimeAtOsStart;      // BCD time when OS passed control      028-02F
-       u8      xRsvd2[80];             // Reserved                             030-07F
-};
-
-#endif /* _ISERIES_SPCOMM_AREA_H */
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
deleted file mode 100644 (file)
index 04be62d..0000000
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Legacy iSeries specific vio initialisation
- * that needs to be built in (not a module).
- *
- * Â© Copyright 2007 IBM Corporation
- *     Author: Stephen Rothwell
- *     Some parts collected from various other files
- *
- * This program is free software;  you can redistribute it and/or
- * modify it under the terms of the 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/of.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-
-#include <asm/firmware.h>
-#include <asm/vio.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/iommu.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-
-#define FIRST_VTY      0
-#define NUM_VTYS       1
-#define FIRST_VSCSI    (FIRST_VTY + NUM_VTYS)
-#define NUM_VSCSIS     1
-#define FIRST_VLAN     (FIRST_VSCSI + NUM_VSCSIS)
-#define NUM_VLANS      HVMAXARCHITECTEDVIRTUALLANS
-#define FIRST_VIODASD  (FIRST_VLAN + NUM_VLANS)
-#define NUM_VIODASDS   HVMAXARCHITECTEDVIRTUALDISKS
-#define FIRST_VIOCD    (FIRST_VIODASD + NUM_VIODASDS)
-#define NUM_VIOCDS     HVMAXARCHITECTEDVIRTUALCDROMS
-#define FIRST_VIOTAPE  (FIRST_VIOCD + NUM_VIOCDS)
-#define NUM_VIOTAPES   HVMAXARCHITECTEDVIRTUALTAPES
-
-struct vio_waitevent {
-       struct completion       com;
-       int                     rc;
-       u16                     sub_result;
-};
-
-struct vio_resource {
-       char    rsrcname[10];
-       char    type[4];
-       char    model[3];
-};
-
-static struct property *new_property(const char *name, int length,
-               const void *value)
-{
-       struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
-                       GFP_KERNEL);
-
-       if (!np)
-               return NULL;
-       np->name = (char *)(np + 1);
-       np->value = np->name + strlen(name) + 1;
-       strcpy(np->name, name);
-       memcpy(np->value, value, length);
-       np->length = length;
-       return np;
-}
-
-static void free_property(struct property *np)
-{
-       kfree(np);
-}
-
-static struct device_node *new_node(const char *path,
-               struct device_node *parent)
-{
-       struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
-
-       if (!np)
-               return NULL;
-       np->full_name = kstrdup(path, GFP_KERNEL);
-       if (!np->full_name) {
-               kfree(np);
-               return NULL;
-       }
-       of_node_set_flag(np, OF_DYNAMIC);
-       kref_init(&np->kref);
-       np->parent = of_node_get(parent);
-       return np;
-}
-
-static void free_node(struct device_node *np)
-{
-       struct property *next;
-       struct property *prop;
-
-       next = np->properties;
-       while (next) {
-               prop = next;
-               next = prop->next;
-               free_property(prop);
-       }
-       of_node_put(np->parent);
-       kfree(np->full_name);
-       kfree(np);
-}
-
-static int add_string_property(struct device_node *np, const char *name,
-               const char *value)
-{
-       struct property *nprop = new_property(name, strlen(value) + 1, value);
-
-       if (!nprop)
-               return 0;
-       prom_add_property(np, nprop);
-       return 1;
-}
-
-static int add_raw_property(struct device_node *np, const char *name,
-               int length, const void *value)
-{
-       struct property *nprop = new_property(name, length, value);
-
-       if (!nprop)
-               return 0;
-       prom_add_property(np, nprop);
-       return 1;
-}
-
-static struct device_node *do_device_node(struct device_node *parent,
-               const char *name, u32 reg, u32 unit, const char *type,
-               const char *compat, struct vio_resource *res)
-{
-       struct device_node *np;
-       char path[32];
-
-       snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg);
-       np = new_node(path, parent);
-       if (!np)
-               return NULL;
-       if (!add_string_property(np, "name", name) ||
-               !add_string_property(np, "device_type", type) ||
-               !add_string_property(np, "compatible", compat) ||
-               !add_raw_property(np, "reg", sizeof(reg), &reg) ||
-               !add_raw_property(np, "linux,unit_address",
-                       sizeof(unit), &unit)) {
-               goto node_free;
-       }
-       if (res) {
-               if (!add_raw_property(np, "linux,vio_rsrcname",
-                               sizeof(res->rsrcname), res->rsrcname) ||
-                       !add_raw_property(np, "linux,vio_type",
-                               sizeof(res->type), res->type) ||
-                       !add_raw_property(np, "linux,vio_model",
-                               sizeof(res->model), res->model))
-                       goto node_free;
-       }
-       np->name = of_get_property(np, "name", NULL);
-       np->type = of_get_property(np, "device_type", NULL);
-       of_attach_node(np);
-#ifdef CONFIG_PROC_DEVICETREE
-       if (parent->pde) {
-               struct proc_dir_entry *ent;
-
-               ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde);
-               if (ent)
-                       proc_device_tree_add_node(np, ent);
-       }
-#endif
-       return np;
-
- node_free:
-       free_node(np);
-       return NULL;
-}
-
-/*
- * This is here so that we can dynamically add viodasd
- * devices without exposing all the above infrastructure.
- */
-struct vio_dev *vio_create_viodasd(u32 unit)
-{
-       struct device_node *vio_root;
-       struct device_node *np;
-       struct vio_dev *vdev = NULL;
-
-       vio_root = of_find_node_by_path("/vdevice");
-       if (!vio_root)
-               return NULL;
-       np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
-                       "block", "IBM,iSeries-viodasd", NULL);
-       of_node_put(vio_root);
-       if (np) {
-               vdev = vio_register_device_node(np);
-               if (!vdev)
-                       free_node(np);
-       }
-       return vdev;
-}
-EXPORT_SYMBOL_GPL(vio_create_viodasd);
-
-static void __init handle_block_event(struct HvLpEvent *event)
-{
-       struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
-       struct vio_waitevent *pwe;
-
-       if (event == NULL)
-               /* Notification that a partition went away! */
-               return;
-       /* First, we should NEVER get an int here...only acks */
-       if (hvlpevent_is_int(event)) {
-               printk(KERN_WARNING "handle_viod_request: "
-                      "Yikes! got an int in viodasd event handler!\n");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-               return;
-       }
-
-       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-       case vioblockopen:
-               /*
-                * Handle a response to an open request.  We get all the
-                * disk information in the response, so update it.  The
-                * correlation token contains a pointer to a waitevent
-                * structure that has a completion in it.  update the
-                * return code in the waitevent structure and post the
-                * completion to wake up the guy who sent the request
-                */
-               pwe = (struct vio_waitevent *)event->xCorrelationToken;
-               pwe->rc = event->xRc;
-               pwe->sub_result = bevent->sub_result;
-               complete(&pwe->com);
-               break;
-       case vioblockclose:
-               break;
-       default:
-               printk(KERN_WARNING "handle_viod_request: unexpected subtype!");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-static void __init probe_disk(struct device_node *vio_root, u32 unit)
-{
-       HvLpEvent_Rc hvrc;
-       struct vio_waitevent we;
-       u16 flags = 0;
-
-retry:
-       init_completion(&we.com);
-
-       /* Send the open event to OS/400 */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)&we, VIOVERSION << 16,
-                       ((u64)unit << 48) | ((u64)flags<< 32),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n",
-                       (int)hvrc);
-               return;
-       }
-
-       wait_for_completion(&we.com);
-
-       if (we.rc != 0) {
-               if (flags != 0)
-                       return;
-               /* try again with read only flag set */
-               flags = vioblockflags_ro;
-               goto retry;
-       }
-
-       /* Send the close event to OS/400.  We DON'T expect a response */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockclose,
-                       HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       0, VIOVERSION << 16,
-                       ((u64)unit << 48) | ((u64)flags << 32),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               printk(KERN_WARNING "probe_disk: "
-                      "bad rc sending event to OS/400 %d\n", (int)hvrc);
-               return;
-       }
-
-       do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
-                       "block", "IBM,iSeries-viodasd", NULL);
-}
-
-static void __init get_viodasd_info(struct device_node *vio_root)
-{
-       int rc;
-       u32 unit;
-
-       rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2);
-       if (rc) {
-               printk(KERN_WARNING "get_viodasd_info: "
-                      "error opening path to host partition %d\n",
-                      viopath_hostLp);
-               return;
-       }
-
-       /* Initialize our request handler */
-       vio_setHandler(viomajorsubtype_blockio, handle_block_event);
-
-       for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++)
-               probe_disk(vio_root, unit);
-
-       vio_clearHandler(viomajorsubtype_blockio);
-       viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2);
-}
-
-static void __init handle_cd_event(struct HvLpEvent *event)
-{
-       struct viocdlpevent *bevent;
-       struct vio_waitevent *pwe;
-
-       if (!event)
-               /* Notification that a partition went away! */
-               return;
-
-       /* First, we should NEVER get an int here...only acks */
-       if (hvlpevent_is_int(event)) {
-               printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-               return;
-       }
-
-       bevent = (struct viocdlpevent *)event;
-
-       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-       case viocdgetinfo:
-               pwe = (struct vio_waitevent *)event->xCorrelationToken;
-               pwe->rc = event->xRc;
-               pwe->sub_result = bevent->sub_result;
-               complete(&pwe->com);
-               break;
-
-       default:
-               printk(KERN_WARNING "handle_cd_event: "
-                       "message with unexpected subtype %0x04X!\n",
-                       event->xSubtype & VIOMINOR_SUBTYPE_MASK);
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-static void __init get_viocd_info(struct device_node *vio_root)
-{
-       HvLpEvent_Rc hvrc;
-       u32 unit;
-       struct vio_waitevent we;
-       struct vio_resource *unitinfo;
-       dma_addr_t unitinfo_dmaaddr;
-       int ret;
-
-       ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
-       if (ret) {
-               printk(KERN_WARNING
-                       "get_viocd_info: error opening path to host partition %d\n",
-                       viopath_hostLp);
-               return;
-       }
-
-       /* Initialize our request handler */
-       vio_setHandler(viomajorsubtype_cdio, handle_cd_event);
-
-       unitinfo = iseries_hv_alloc(
-                       sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
-                       &unitinfo_dmaaddr, GFP_ATOMIC);
-       if (!unitinfo) {
-               printk(KERN_WARNING
-                       "get_viocd_info: error allocating unitinfo\n");
-               goto clear_handler;
-       }
-
-       memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);
-
-       init_completion(&we.com);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_cdio | viocdgetinfo,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
-                       sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               printk(KERN_WARNING
-                       "get_viocd_info: cdrom error sending event. rc %d\n",
-                       (int)hvrc);
-               goto hv_free;
-       }
-
-       wait_for_completion(&we.com);
-
-       if (we.rc) {
-               printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
-                       we.rc, we.sub_result);
-               goto hv_free;
-       }
-
-       for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
-                       unitinfo[unit].rsrcname[0]; unit++) {
-               if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit,
-                               "block", "IBM,iSeries-viocd", &unitinfo[unit]))
-                       break;
-       }
-
- hv_free:
-       iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
-                       unitinfo, unitinfo_dmaaddr);
- clear_handler:
-       vio_clearHandler(viomajorsubtype_cdio);
-       viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
-}
-
-/* Handle interrupt events for tape */
-static void __init handle_tape_event(struct HvLpEvent *event)
-{
-       struct vio_waitevent *we;
-       struct viotapelpevent *tevent = (struct viotapelpevent *)event;
-
-       if (event == NULL)
-               /* Notification that a partition went away! */
-               return;
-
-       we = (struct vio_waitevent *)event->xCorrelationToken;
-       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-       case viotapegetinfo:
-               we->rc = tevent->sub_type_result;
-               complete(&we->com);
-               break;
-       default:
-               printk(KERN_WARNING "handle_tape_event: weird ack\n");
-       }
-}
-
-static void __init get_viotape_info(struct device_node *vio_root)
-{
-       HvLpEvent_Rc hvrc;
-       u32 unit;
-       struct vio_resource *unitinfo;
-       dma_addr_t unitinfo_dmaaddr;
-       size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
-       struct vio_waitevent we;
-       int ret;
-
-       init_completion(&we.com);
-
-       ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
-       if (ret) {
-               printk(KERN_WARNING "get_viotape_info: "
-                       "error on viopath_open to hostlp %d\n", ret);
-               return;
-       }
-
-       vio_setHandler(viomajorsubtype_tape, handle_tape_event);
-
-       unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
-       if (!unitinfo)
-               goto clear_handler;
-
-       memset(unitinfo, 0, len);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotapegetinfo,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)&we, VIOVERSION << 16,
-                       unitinfo_dmaaddr, len, 0, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
-                               (int)hvrc);
-               goto hv_free;
-       }
-
-       wait_for_completion(&we.com);
-
-       for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
-                       unitinfo[unit].rsrcname[0]; unit++) {
-               if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit,
-                               unit, "byte", "IBM,iSeries-viotape",
-                               &unitinfo[unit]))
-                       break;
-       }
-
- hv_free:
-       iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
- clear_handler:
-       vio_clearHandler(viomajorsubtype_tape);
-       viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
-}
-
-static int __init iseries_vio_init(void)
-{
-       struct device_node *vio_root;
-       int ret = -ENODEV;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               goto out;
-
-       iommu_vio_init();
-
-       vio_root = of_find_node_by_path("/vdevice");
-       if (!vio_root)
-               goto out;
-
-       if (viopath_hostLp == HvLpIndexInvalid) {
-               vio_set_hostlp();
-               /* If we don't have a host, bail out */
-               if (viopath_hostLp == HvLpIndexInvalid)
-                       goto put_node;
-       }
-
-       get_viodasd_info(vio_root);
-       get_viocd_info(vio_root);
-       get_viotape_info(vio_root);
-
-       ret = 0;
-
- put_node:
-       of_node_put(vio_root);
- out:
-       return ret;
-}
-arch_initcall(iseries_vio_init);
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
deleted file mode 100644 (file)
index 40dad08..0000000
+++ /dev/null
@@ -1,677 +0,0 @@
-/* -*- linux-c -*-
- *
- *  iSeries Virtual I/O Message Path code
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *
- * (C) Copyright 2000-2005 IBM Corporation
- *
- * This code is used by the iSeries virtual disk, cd,
- * tape, and console to communicate with OS/400 in another
- * partition.
- *
- * This program is free software;  you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) anyu 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/export.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/wait.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/vio.h>
-
-/* Status of the path to each other partition in the system.
- * This is overkill, since we will only ever establish connections
- * to our hosting partition and the primary partition on the system.
- * But this allows for other support in the future.
- */
-static struct viopathStatus {
-       int isOpen;             /* Did we open the path?            */
-       int isActive;           /* Do we have a mon msg outstanding */
-       int users[VIO_MAX_SUBTYPES];
-       HvLpInstanceId mSourceInst;
-       HvLpInstanceId mTargetInst;
-       int numberAllocated;
-} viopathStatus[HVMAXARCHITECTEDLPS];
-
-static DEFINE_SPINLOCK(statuslock);
-
-/*
- * For each kind of event we allocate a buffer that is
- * guaranteed not to cross a page boundary
- */
-static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
-       __attribute__((__aligned__(4096)));
-static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
-static int event_buffer_initialised;
-
-static void handleMonitorEvent(struct HvLpEvent *event);
-
-/*
- * We use this structure to handle asynchronous responses.  The caller
- * blocks on the semaphore and the handler posts the semaphore.  However,
- * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...
- */
-struct alloc_parms {
-       struct completion done;
-       int number;
-       atomic_t wait_atomic;
-       int used_wait_atomic;
-};
-
-/* Put a sequence number in each mon msg.  The value is not
- * important.  Start at something other than 0 just for
- * readability.  wrapping this is ok.
- */
-static u8 viomonseq = 22;
-
-/* Our hosting logical partition.  We get this at startup
- * time, and different modules access this variable directly.
- */
-HvLpIndex viopath_hostLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_hostLp);
-HvLpIndex viopath_ourLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_ourLp);
-
-/* For each kind of incoming event we set a pointer to a
- * routine to call.
- */
-static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];
-
-#define VIOPATH_KERN_WARN      KERN_WARNING "viopath: "
-#define VIOPATH_KERN_INFO      KERN_INFO "viopath: "
-
-static int proc_viopath_show(struct seq_file *m, void *v)
-{
-       char *buf;
-       u16 vlanMap;
-       dma_addr_t handle;
-       HvLpEvent_Rc hvrc;
-       DECLARE_COMPLETION_ONSTACK(done);
-       struct device_node *node;
-       const char *sysid;
-
-       buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL);
-       if (!buf)
-               return 0;
-
-       handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_config | vioconfigget,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)&done, VIOVERSION << 16,
-                       ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);
-
-       if (hvrc != HvLpEvent_Rc_Good)
-               printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);
-
-       wait_for_completion(&done);
-
-       vlanMap = HvLpConfig_getVirtualLanIndexMap();
-
-       buf[HW_PAGE_SIZE-1] = '\0';
-       seq_printf(m, "%s", buf);
-
-       iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
-       kfree(buf);
-
-       seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
-
-       node = of_find_node_by_path("/");
-       sysid = NULL;
-       if (node != NULL)
-               sysid = of_get_property(node, "system-id", NULL);
-
-       if (sysid == NULL)
-               seq_printf(m, "SRLNBR=<UNKNOWN>\n");
-       else
-               /* Skip "IBM," on front of serial number, see dt.c */
-               seq_printf(m, "SRLNBR=%s\n", sysid + 4);
-
-       of_node_put(node);
-
-       return 0;
-}
-
-static int proc_viopath_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_viopath_show, NULL);
-}
-
-static const struct file_operations proc_viopath_operations = {
-       .open           = proc_viopath_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init vio_proc_init(void)
-{
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-
-       proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);
-        return 0;
-}
-__initcall(vio_proc_init);
-
-/* See if a given LP is active.  Allow for invalid lps to be passed in
- * and just return invalid
- */
-int viopath_isactive(HvLpIndex lp)
-{
-       if (lp == HvLpIndexInvalid)
-               return 0;
-       if (lp < HVMAXARCHITECTEDLPS)
-               return viopathStatus[lp].isActive;
-       else
-               return 0;
-}
-EXPORT_SYMBOL(viopath_isactive);
-
-/*
- * We cache the source and target instance ids for each
- * partition.
- */
-HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
-{
-       return viopathStatus[lp].mSourceInst;
-}
-EXPORT_SYMBOL(viopath_sourceinst);
-
-HvLpInstanceId viopath_targetinst(HvLpIndex lp)
-{
-       return viopathStatus[lp].mTargetInst;
-}
-EXPORT_SYMBOL(viopath_targetinst);
-
-/*
- * Send a monitor message.  This is a message with the acknowledge
- * bit on that the other side will NOT explicitly acknowledge.  When
- * the other side goes down, the hypervisor will acknowledge any
- * outstanding messages....so we will know when the other side dies.
- */
-static void sendMonMsg(HvLpIndex remoteLp)
-{
-       HvLpEvent_Rc hvrc;
-
-       viopathStatus[remoteLp].mSourceInst =
-               HvCallEvent_getSourceLpInstanceId(remoteLp,
-                               HvLpEvent_Type_VirtualIo);
-       viopathStatus[remoteLp].mTargetInst =
-               HvCallEvent_getTargetLpInstanceId(remoteLp,
-                               HvLpEvent_Type_VirtualIo);
-
-       /*
-        * Deliberately ignore the return code here.  if we call this
-        * more than once, we don't care.
-        */
-       vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent);
-
-       hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck,
-                       HvLpEvent_AckType_DeferredAck,
-                       viopathStatus[remoteLp].mSourceInst,
-                       viopathStatus[remoteLp].mTargetInst,
-                       viomonseq++, 0, 0, 0, 0, 0);
-
-       if (hvrc == HvLpEvent_Rc_Good)
-               viopathStatus[remoteLp].isActive = 1;
-       else {
-               printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",
-                               remoteLp);
-               viopathStatus[remoteLp].isActive = 0;
-       }
-}
-
-static void handleMonitorEvent(struct HvLpEvent *event)
-{
-       HvLpIndex remoteLp;
-       int i;
-
-       /*
-        * This handler is _also_ called as part of the loop
-        * at the end of this routine, so it must be able to
-        * ignore NULL events...
-        */
-       if (!event)
-               return;
-
-       /*
-        * First see if this is just a normal monitor message from the
-        * other partition
-        */
-       if (hvlpevent_is_int(event)) {
-               remoteLp = event->xSourceLp;
-               if (!viopathStatus[remoteLp].isActive)
-                       sendMonMsg(remoteLp);
-               return;
-       }
-
-       /*
-        * This path is for an acknowledgement; the other partition
-        * died
-        */
-       remoteLp = event->xTargetLp;
-       if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
-           (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {
-               printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");
-               return;
-       }
-
-       printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);
-
-       viopathStatus[remoteLp].isActive = 0;
-
-       /*
-        * For each active handler, pass them a NULL
-        * message to indicate that the other partition
-        * died
-        */
-       for (i = 0; i < VIO_MAX_SUBTYPES; i++) {
-               if (vio_handler[i] != NULL)
-                       (*vio_handler[i])(NULL);
-       }
-}
-
-int vio_setHandler(int subtype, vio_event_handler_t *beh)
-{
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-               return -EINVAL;
-       if (vio_handler[subtype] != NULL)
-               return -EBUSY;
-       vio_handler[subtype] = beh;
-       return 0;
-}
-EXPORT_SYMBOL(vio_setHandler);
-
-int vio_clearHandler(int subtype)
-{
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-               return -EINVAL;
-       if (vio_handler[subtype] == NULL)
-               return -EAGAIN;
-       vio_handler[subtype] = NULL;
-       return 0;
-}
-EXPORT_SYMBOL(vio_clearHandler);
-
-static void handleConfig(struct HvLpEvent *event)
-{
-       if (!event)
-               return;
-       if (hvlpevent_is_int(event)) {
-               printk(VIOPATH_KERN_WARN
-                      "unexpected config request from partition %d",
-                      event->xSourceLp);
-
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-               return;
-       }
-
-       complete((struct completion *)event->xCorrelationToken);
-}
-
-/*
- * Initialization of the hosting partition
- */
-void vio_set_hostlp(void)
-{
-       /*
-        * If this has already been set then we DON'T want to either change
-        * it or re-register the proc file system
-        */
-       if (viopath_hostLp != HvLpIndexInvalid)
-               return;
-
-       /*
-        * Figure out our hosting partition.  This isn't allowed to change
-        * while we're active
-        */
-       viopath_ourLp = HvLpConfig_getLpIndex();
-       viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);
-
-       if (viopath_hostLp != HvLpIndexInvalid)
-               vio_setHandler(viomajorsubtype_config, handleConfig);
-}
-EXPORT_SYMBOL(vio_set_hostlp);
-
-static void vio_handleEvent(struct HvLpEvent *event)
-{
-       HvLpIndex remoteLp;
-       int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
-               >> VIOMAJOR_SUBTYPE_SHIFT;
-
-       if (hvlpevent_is_int(event)) {
-               remoteLp = event->xSourceLp;
-               /*
-                * The isActive is checked because if the hosting partition
-                * went down and came back up it would not be active but it
-                * would have different source and target instances, in which
-                * case we'd want to reset them.  This case really protects
-                * against an unauthorized active partition sending interrupts
-                * or acks to this linux partition.
-                */
-               if (viopathStatus[remoteLp].isActive
-                   && (event->xSourceInstanceId !=
-                       viopathStatus[remoteLp].mTargetInst)) {
-                       printk(VIOPATH_KERN_WARN
-                              "message from invalid partition. "
-                              "int msg rcvd, source inst (%d) doesn't match (%d)\n",
-                              viopathStatus[remoteLp].mTargetInst,
-                              event->xSourceInstanceId);
-                       return;
-               }
-
-               if (viopathStatus[remoteLp].isActive
-                   && (event->xTargetInstanceId !=
-                       viopathStatus[remoteLp].mSourceInst)) {
-                       printk(VIOPATH_KERN_WARN
-                              "message from invalid partition. "
-                              "int msg rcvd, target inst (%d) doesn't match (%d)\n",
-                              viopathStatus[remoteLp].mSourceInst,
-                              event->xTargetInstanceId);
-                       return;
-               }
-       } else {
-               remoteLp = event->xTargetLp;
-               if (event->xSourceInstanceId !=
-                   viopathStatus[remoteLp].mSourceInst) {
-                       printk(VIOPATH_KERN_WARN
-                              "message from invalid partition. "
-                              "ack msg rcvd, source inst (%d) doesn't match (%d)\n",
-                              viopathStatus[remoteLp].mSourceInst,
-                              event->xSourceInstanceId);
-                       return;
-               }
-
-               if (event->xTargetInstanceId !=
-                   viopathStatus[remoteLp].mTargetInst) {
-                       printk(VIOPATH_KERN_WARN
-                              "message from invalid partition. "
-                              "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n",
-                              viopathStatus[remoteLp].mTargetInst,
-                              event->xTargetInstanceId);
-                       return;
-               }
-       }
-
-       if (vio_handler[subtype] == NULL) {
-               printk(VIOPATH_KERN_WARN
-                      "unexpected virtual io event subtype %d from partition %d\n",
-                      event->xSubtype, remoteLp);
-               /* No handler.  Ack if necessary */
-               if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-               return;
-       }
-
-       /* This innocuous little line is where all the real work happens */
-       (*vio_handler[subtype])(event);
-}
-
-static void viopath_donealloc(void *parm, int number)
-{
-       struct alloc_parms *parmsp = parm;
-
-       parmsp->number = number;
-       if (parmsp->used_wait_atomic)
-               atomic_set(&parmsp->wait_atomic, 0);
-       else
-               complete(&parmsp->done);
-}
-
-static int allocateEvents(HvLpIndex remoteLp, int numEvents)
-{
-       struct alloc_parms parms;
-
-       if (system_state != SYSTEM_RUNNING) {
-               parms.used_wait_atomic = 1;
-               atomic_set(&parms.wait_atomic, 1);
-       } else {
-               parms.used_wait_atomic = 0;
-               init_completion(&parms.done);
-       }
-       mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250,  /* It would be nice to put a real number here! */
-                           numEvents, &viopath_donealloc, &parms);
-       if (system_state != SYSTEM_RUNNING) {
-               while (atomic_read(&parms.wait_atomic))
-                       mb();
-       } else
-               wait_for_completion(&parms.done);
-       return parms.number;
-}
-
-int viopath_open(HvLpIndex remoteLp, int subtype, int numReq)
-{
-       int i;
-       unsigned long flags;
-       int tempNumAllocated;
-
-       if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
-               return -EINVAL;
-
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-               return -EINVAL;
-
-       spin_lock_irqsave(&statuslock, flags);
-
-       if (!event_buffer_initialised) {
-               for (i = 0; i < VIO_MAX_SUBTYPES; i++)
-                       atomic_set(&event_buffer_available[i], 1);
-               event_buffer_initialised = 1;
-       }
-
-       viopathStatus[remoteLp].users[subtype]++;
-
-       if (!viopathStatus[remoteLp].isOpen) {
-               viopathStatus[remoteLp].isOpen = 1;
-               HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
-
-               /*
-                * Don't hold the spinlock during an operation that
-                * can sleep.
-                */
-               spin_unlock_irqrestore(&statuslock, flags);
-               tempNumAllocated = allocateEvents(remoteLp, 1);
-               spin_lock_irqsave(&statuslock, flags);
-
-               viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
-
-               if (viopathStatus[remoteLp].numberAllocated == 0) {
-                       HvCallEvent_closeLpEventPath(remoteLp,
-                                       HvLpEvent_Type_VirtualIo);
-
-                       spin_unlock_irqrestore(&statuslock, flags);
-                       return -ENOMEM;
-               }
-
-               viopathStatus[remoteLp].mSourceInst =
-                       HvCallEvent_getSourceLpInstanceId(remoteLp,
-                                       HvLpEvent_Type_VirtualIo);
-               viopathStatus[remoteLp].mTargetInst =
-                       HvCallEvent_getTargetLpInstanceId(remoteLp,
-                                       HvLpEvent_Type_VirtualIo);
-               HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,
-                                         &vio_handleEvent);
-               sendMonMsg(remoteLp);
-               printk(VIOPATH_KERN_INFO "opening connection to partition %d, "
-                               "setting sinst %d, tinst %d\n",
-                               remoteLp, viopathStatus[remoteLp].mSourceInst,
-                               viopathStatus[remoteLp].mTargetInst);
-       }
-
-       spin_unlock_irqrestore(&statuslock, flags);
-       tempNumAllocated = allocateEvents(remoteLp, numReq);
-       spin_lock_irqsave(&statuslock, flags);
-       viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
-       spin_unlock_irqrestore(&statuslock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(viopath_open);
-
-int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
-{
-       unsigned long flags;
-       int i;
-       int numOpen;
-       struct alloc_parms parms;
-
-       if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
-               return -EINVAL;
-
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-               return -EINVAL;
-
-       spin_lock_irqsave(&statuslock, flags);
-       /*
-        * If the viopath_close somehow gets called before a
-        * viopath_open it could decrement to -1 which is a non
-        * recoverable state so we'll prevent this from
-        * happening.
-        */
-       if (viopathStatus[remoteLp].users[subtype] > 0)
-               viopathStatus[remoteLp].users[subtype]--;
-
-       spin_unlock_irqrestore(&statuslock, flags);
-
-       parms.used_wait_atomic = 0;
-       init_completion(&parms.done);
-       mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,
-                             numReq, &viopath_donealloc, &parms);
-       wait_for_completion(&parms.done);
-
-       spin_lock_irqsave(&statuslock, flags);
-       for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)
-               numOpen += viopathStatus[remoteLp].users[i];
-
-       if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
-               printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
-                               remoteLp);
-
-               HvCallEvent_closeLpEventPath(remoteLp,
-                                            HvLpEvent_Type_VirtualIo);
-               viopathStatus[remoteLp].isOpen = 0;
-               viopathStatus[remoteLp].isActive = 0;
-
-               for (i = 0; i < VIO_MAX_SUBTYPES; i++)
-                       atomic_set(&event_buffer_available[i], 0);
-               event_buffer_initialised = 0;
-       }
-       spin_unlock_irqrestore(&statuslock, flags);
-       return 0;
-}
-EXPORT_SYMBOL(viopath_close);
-
-void *vio_get_event_buffer(int subtype)
-{
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
-               return NULL;
-
-       if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0)
-               return &event_buffer[subtype * 256];
-       else
-               return NULL;
-}
-EXPORT_SYMBOL(vio_get_event_buffer);
-
-void vio_free_event_buffer(int subtype, void *buffer)
-{
-       subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
-       if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {
-               printk(VIOPATH_KERN_WARN
-                      "unexpected subtype %d freeing event buffer\n", subtype);
-               return;
-       }
-
-       if (atomic_read(&event_buffer_available[subtype]) != 0) {
-               printk(VIOPATH_KERN_WARN
-                      "freeing unallocated event buffer, subtype %d\n",
-                      subtype);
-               return;
-       }
-
-       if (buffer != &event_buffer[subtype * 256]) {
-               printk(VIOPATH_KERN_WARN
-                      "freeing invalid event buffer, subtype %d\n", subtype);
-       }
-
-       atomic_set(&event_buffer_available[subtype], 1);
-}
-EXPORT_SYMBOL(vio_free_event_buffer);
-
-static const struct vio_error_entry vio_no_error =
-    { 0, 0, "Non-VIO Error" };
-static const struct vio_error_entry vio_unknown_error =
-    { 0, EIO, "Unknown Error" };
-
-static const struct vio_error_entry vio_default_errors[] = {
-       {0x0001, EIO, "No Connection"},
-       {0x0002, EIO, "No Receiver"},
-       {0x0003, EIO, "No Buffer Available"},
-       {0x0004, EBADRQC, "Invalid Message Type"},
-       {0x0000, 0, NULL},
-};
-
-const struct vio_error_entry *vio_lookup_rc(
-               const struct vio_error_entry *local_table, u16 rc)
-{
-       const struct vio_error_entry *cur;
-
-       if (!rc)
-               return &vio_no_error;
-       if (local_table)
-               for (cur = local_table; cur->rc; ++cur)
-                       if (cur->rc == rc)
-                               return cur;
-       for (cur = vio_default_errors; cur->rc; ++cur)
-               if (cur->rc == rc)
-                       return cur;
-       return &vio_unknown_error;
-}
-EXPORT_SYMBOL(vio_lookup_rc);
diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h
deleted file mode 100644 (file)
index feb001f..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2001  Mike Corrigan IBM 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-#ifndef _ISERIES_VPD_AREAS_H
-#define _ISERIES_VPD_AREAS_H
-
-/*
- * This file defines the address and length of all of the VPD area passed to
- * the OS from PLIC (most of which start from the SP).
- */
-
-#include <asm/types.h>
-
-/* VPD Entry index is carved in stone - cannot be changed (easily). */
-#define ItVpdCecVpd                            0
-#define ItVpdDynamicSpace                      1
-#define ItVpdExtVpd                            2
-#define ItVpdExtVpdOnPanel                     3
-#define ItVpdFirstPaca                         4
-#define ItVpdIoVpd                             5
-#define ItVpdIplParms                          6
-#define ItVpdMsVpd                             7
-#define ItVpdPanelVpd                          8
-#define ItVpdLpNaca                            9
-#define ItVpdBackplaneAndMaybeClockCardVpd     10
-#define ItVpdRecoveryLogBuffer                 11
-#define ItVpdSpCommArea                                12
-#define ItVpdSpLogBuffer                       13
-#define ItVpdSpLogBufferSave                   14
-#define ItVpdSpCardVpd                         15
-#define ItVpdFirstProcVpd                      16
-#define ItVpdApModelVpd                                17
-#define ItVpdClockCardVpd                      18
-#define ItVpdBusExtCardVpd                     19
-#define ItVpdProcCapacityVpd                   20
-#define ItVpdInteractiveCapacityVpd            21
-#define ItVpdFirstSlotLabel                    22
-#define ItVpdFirstLpQueue                      23
-#define ItVpdFirstL3CacheVpd                   24
-#define ItVpdFirstProcFruVpd                   25
-
-#define ItVpdMaxEntries                                26
-
-#define ItDmaMaxEntries                                10
-
-#define ItVpdAreasMaxSlotLabels                        192
-
-
-struct ItVpdAreas {
-       u32     xSlicDesc;              // Descriptor                   000-003
-       u16     xSlicSize;              // Size of this control block   004-005
-       u16     xPlicAdjustVpdLens:1;   // Flag to indicate new interface006-007
-       u16     xRsvd1:15;              // Reserved bits                ...
-       u16     xSlicVpdEntries;        // Number of VPD entries        008-009
-       u16     xSlicDmaEntries;        // Number of DMA entries        00A-00B
-       u16     xSlicMaxLogicalProcs;   // Maximum logical processors   00C-00D
-       u16     xSlicMaxPhysicalProcs;  // Maximum physical processors  00E-00F
-       u16     xSlicDmaToksOffset;     // Offset into this of array    010-011
-       u16     xSlicVpdAdrsOffset;     // Offset into this of array    012-013
-       u16     xSlicDmaLensOffset;     // Offset into this of array    014-015
-       u16     xSlicVpdLensOffset;     // Offset into this of array    016-017
-       u16     xSlicMaxSlotLabels;     // Maximum number of slot labels018-019
-       u16     xSlicMaxLpQueues;       // Maximum number of LP Queues  01A-01B
-       u8      xRsvd2[4];              // Reserved                     01C-01F
-       u64     xRsvd3[12];             // Reserved                     020-07F
-       u32     xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths   080-0A7
-       u32     xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens    0A8-0CF
-       u32     xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths   0D0-12F
-       const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF
-};
-
-extern const struct ItVpdAreas itVpdAreas;
-
-#endif /* _ISERIES_VPD_AREAS_H */
index 0bcbfe7..3b7545a 100644 (file)
@@ -262,7 +262,7 @@ static void __init maple_init_IRQ(void)
                flags |= MPIC_BIG_ENDIAN;
 
        /* XXX Maple specific bits */
-       flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
+       flags |= MPIC_U3_HT_IRQS;
        /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
        flags |= MPIC_BIG_ENDIAN;
 
index 98b7a7c..e777ad4 100644 (file)
@@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void)
        openpic_addr = of_read_number(opprop, naddr);
        printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
 
-       mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS;
+       mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET;
 
        nmiprop = of_get_property(mpic_node, "nmi-source", NULL);
        if (nmiprop)
index 54d2271..da18b26 100644 (file)
@@ -279,7 +279,7 @@ static u32 core99_check(u8* datas)
 
 static int sm_erase_bank(int bank)
 {
-       int stat, i;
+       int stat;
        unsigned long timeout;
 
        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
@@ -301,11 +301,10 @@ static int sm_erase_bank(int bank)
        out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
        out_8(base, SM_FLASH_CMD_RESET);
 
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
-                       return -ENXIO;
-               }
+       if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+               printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+               return -ENXIO;
+       }
        return 0;
 }
 
@@ -336,17 +335,16 @@ static int sm_write_bank(int bank, u8* datas)
        }
        out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
        out_8(base, SM_FLASH_CMD_RESET);
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
-                       return -ENXIO;
-               }
+       if (memcmp(base, datas, NVRAM_SIZE)) {
+               printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
+               return -ENXIO;
+       }
        return 0;
 }
 
 static int amd_erase_bank(int bank)
 {
-       int i, stat = 0;
+       int stat = 0;
        unsigned long timeout;
 
        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
@@ -382,12 +380,11 @@ static int amd_erase_bank(int bank)
        /* Reset */
        out_8(base, 0xf0);
        udelay(1);
-       
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: AMD flash erase failed !\n");
-                       return -ENXIO;
-               }
+
+       if (memchr_inv(base, 0xff, NVRAM_SIZE)) {
+               printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+               return -ENXIO;
+       }
        return 0;
 }
 
@@ -429,11 +426,10 @@ static int amd_write_bank(int bank, u8* datas)
        out_8(base, 0xf0);
        udelay(1);
 
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: AMD flash write failed !\n");
-                       return -ENXIO;
-               }
+       if (memcmp(base, datas, NVRAM_SIZE)) {
+               printk(KERN_ERR "nvram: AMD flash write failed !\n");
+               return -ENXIO;
+       }
        return 0;
 }
 
index 92afc38..66ad93d 100644 (file)
@@ -457,7 +457,6 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
 
        pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
 
-       flags |= MPIC_WANTS_RESET;
        if (of_get_property(np, "big-endian", NULL))
                flags |= MPIC_BIG_ENDIAN;
 
index f92b9ef..214478d 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/iommu.h>
 #include <asm/tce.h>
 #include <asm/abs_addr.h>
+#include <asm/firmware.h>
 
 #include "powernv.h"
 #include "pci.h"
index 467bd4a..db1ad1c 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/xics.h>
 #include <asm/rtas.h>
 #include <asm/opal.h>
-#include <asm/xics.h>
 
 #include "powernv.h"
 
index f255625..aadbe4f 100644 (file)
@@ -73,7 +73,7 @@ config IO_EVENT_IRQ
 
 config LPARCFG
        bool "LPAR Configuration Data"
-       depends on PPC_PSERIES || PPC_ISERIES
+       depends on PPC_PSERIES
        help
        Provide system capacity information via human readable
        <key word>=<value> pairs through a /proc/ppc64/lparcfg interface.
index 236db46..c222189 100644 (file)
@@ -6,7 +6,8 @@ obj-y                   := lpar.o hvCall.o nvram.o reconfig.o \
                           firmware.o power.o dlpar.o mobility.o
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_SCANLOG)  += scanlog.o
-obj-$(CONFIG_EEH)      += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o
+obj-$(CONFIG_EEH)      += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \
+                          eeh_event.o eeh_sysfs.o eeh_pseries.o
 obj-$(CONFIG_KEXEC)    += kexec.o
 obj-$(CONFIG_PCI)      += pci.o pci_dlpar.o
 obj-$(CONFIG_PSERIES_MSI)      += msi.o
@@ -18,7 +19,6 @@ 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_CMM)              += cmm.o
 obj-$(CONFIG_DTL)              += dtl.o
 obj-$(CONFIG_IO_EVENT_IRQ)     += io_event_irq.o
index c0b40af..8011088 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * eeh.c
  * Copyright IBM Corporation 2001, 2005, 2006
  * Copyright Dave Engebretsen & Todd Inglett 2001
  * Copyright Linas Vepstas 2005, 2006
+ * Copyright 2001-2012 IBM 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
@@ -22,7 +22,7 @@
  */
 
 #include <linux/delay.h>
-#include <linux/sched.h>       /* for init_mm */
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/pci.h>
 /* Time to wait for a PCI slot to report status, in milliseconds */
 #define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
-/* RTAS tokens */
-static int ibm_set_eeh_option;
-static int ibm_set_slot_reset;
-static int ibm_read_slot_reset_state;
-static int ibm_read_slot_reset_state2;
-static int ibm_slot_error_detail;
-static int ibm_get_config_addr_info;
-static int ibm_get_config_addr_info2;
-static int ibm_configure_bridge;
-static int ibm_configure_pe;
+/* Platform dependent EEH operations */
+struct eeh_ops *eeh_ops = NULL;
 
 int eeh_subsystem_enabled;
 EXPORT_SYMBOL(eeh_subsystem_enabled);
@@ -103,14 +95,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
 /* Lock to avoid races due to multiple reports of an error */
 static DEFINE_RAW_SPINLOCK(confirm_error_lock);
 
-/* Buffer for reporting slot-error-detail rtas calls. Its here
- * in BSS, and not dynamically alloced, so that it ends up in
- * RMO where RTAS can access it.
- */
-static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
-static DEFINE_SPINLOCK(slot_errbuf_lock);
-static int eeh_error_buf_size;
-
 /* Buffer for reporting pci register dumps. Its here in BSS, and
  * not dynamically alloced, so that it ends up in RMO where RTAS
  * can access it.
@@ -118,74 +102,50 @@ static int eeh_error_buf_size;
 #define EEH_PCI_REGS_LOG_LEN 4096
 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
 
-/* System monitoring statistics */
-static unsigned long no_device;
-static unsigned long no_dn;
-static unsigned long no_cfg_addr;
-static unsigned long ignored_check;
-static unsigned long total_mmio_ffs;
-static unsigned long false_positives;
-static unsigned long slot_resets;
-
-#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
-
-/* --------------------------------------------------------------- */
-/* Below lies the EEH event infrastructure */
+/*
+ * The struct is used to maintain the EEH global statistic
+ * information. Besides, the EEH global statistics will be
+ * exported to user space through procfs
+ */
+struct eeh_stats {
+       u64 no_device;          /* PCI device not found         */
+       u64 no_dn;              /* OF node not found            */
+       u64 no_cfg_addr;        /* Config address not found     */
+       u64 ignored_check;      /* EEH check skipped            */
+       u64 total_mmio_ffs;     /* Total EEH checks             */
+       u64 false_positives;    /* Unnecessary EEH checks       */
+       u64 slot_resets;        /* PE reset                     */
+};
 
-static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
-                                   char *driver_log, size_t loglen)
-{
-       int config_addr;
-       unsigned long flags;
-       int rc;
+static struct eeh_stats eeh_stats;
 
-       /* Log the error with the rtas logger */
-       spin_lock_irqsave(&slot_errbuf_lock, flags);
-       memset(slot_errbuf, 0, eeh_error_buf_size);
-
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       rc = rtas_call(ibm_slot_error_detail,
-                      8, 1, NULL, config_addr,
-                      BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid),
-                      virt_to_phys(driver_log), loglen,
-                      virt_to_phys(slot_errbuf),
-                      eeh_error_buf_size,
-                      severity);
-
-       if (rc == 0)
-               log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
-       spin_unlock_irqrestore(&slot_errbuf_lock, flags);
-}
+#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
 
 /**
- * gather_pci_data - copy assorted PCI config space registers to buff
- * @pdn: device to report data for
+ * eeh_gather_pci_data - Copy assorted PCI config space registers to buff
+ * @edev: device to report data for
  * @buf: point to buffer in which to log
  * @len: amount of room in buffer
  *
  * This routine captures assorted PCI configuration space data,
  * and puts them into a buffer for RTAS error logging.
  */
-static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
 {
-       struct pci_dev *dev = pdn->pcidev;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
+       struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
        u32 cfg;
        int cap, i;
        int n = 0;
 
-       n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
-       printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+       n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
+       printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
 
-       rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+       eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
        n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
        printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
 
-       rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+       eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
        n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
        printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
 
@@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
 
        /* Gather bridge-specific registers */
        if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
-               rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg);
+               eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
                n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
                printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
 
-               rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg);
+               eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
                n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
                printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
        }
@@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
        /* Dump out the PCI-X command and status regs */
        cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
        if (cap) {
-               rtas_read_config(pdn, cap, 4, &cfg);
+               eeh_ops->read_config(dn, cap, 4, &cfg);
                n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
                printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
 
-               rtas_read_config(pdn, cap+4, 4, &cfg);
+               eeh_ops->read_config(dn, cap+4, 4, &cfg);
                n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
                printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
        }
@@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
                       "EEH: PCI-E capabilities and status follow:\n");
 
                for (i=0; i<=8; i++) {
-                       rtas_read_config(pdn, cap+4*i, 4, &cfg);
+                       eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
                        n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
                        printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
                }
@@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
                               "EEH: PCI-E AER capability register set follows:\n");
 
                        for (i=0; i<14; i++) {
-                               rtas_read_config(pdn, cap+4*i, 4, &cfg);
+                               eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
                                n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
                                printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
                        }
@@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
 
        /* Gather status on devices under the bridge */
        if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
-               struct device_node *dn;
+               struct device_node *child;
 
-               for_each_child_of_node(pdn->node, dn) {
-                       pdn = PCI_DN(dn);
-                       if (pdn)
-                               n += gather_pci_data(pdn, buf+n, len-n);
+               for_each_child_of_node(dn, child) {
+                       if (of_node_to_eeh_dev(child))
+                               n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n);
                }
        }
 
        return n;
 }
 
-void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
-{
-       size_t loglen = 0;
-       pci_regs_buf[0] = 0;
-
-       rtas_pci_enable(pdn, EEH_THAW_MMIO);
-       rtas_configure_bridge(pdn);
-       eeh_restore_bars(pdn);
-       loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
-
-       rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
-}
-
 /**
- * read_slot_reset_state - Read the reset state of a device node's slot
- * @dn: device node to read
- * @rets: array to return results in
- */
-static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
-{
-       int token, outputs;
-       int config_addr;
-
-       if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
-               token = ibm_read_slot_reset_state2;
-               outputs = 4;
-       } else {
-               token = ibm_read_slot_reset_state;
-               rets[2] = 0; /* fake PE Unavailable info */
-               outputs = 3;
-       }
-
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       return rtas_call(token, 3, outputs, rets, config_addr,
-                        BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
-}
-
-/**
- * eeh_wait_for_slot_status - returns error status of slot
- * @pdn pci device node
- * @max_wait_msecs maximum number to millisecs to wait
- *
- * Return negative value if a permanent error, else return
- * Partition Endpoint (PE) status value.
+ * eeh_slot_error_detail - Generate combined log including driver log and error log
+ * @edev: device to report error log for
+ * @severity: temporary or permanent error log
  *
- * If @max_wait_msecs is positive, then this routine will
- * sleep until a valid status can be obtained, or until
- * the max allowed wait time is exceeded, in which case
- * a -2 is returned.
+ * This routine should be called to generate the combined log, which
+ * is comprised of driver log and error log. The driver log is figured
+ * out from the config space of the corresponding PCI device, while
+ * the error log is fetched through platform dependent function call.
  */
-int
-eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
+void eeh_slot_error_detail(struct eeh_dev *edev, int severity)
 {
-       int rc;
-       int rets[3];
-       int mwait;
-
-       while (1) {
-               rc = read_slot_reset_state(pdn, rets);
-               if (rc) return rc;
-               if (rets[1] == 0) return -1;  /* EEH is not supported */
-
-               if (rets[0] != 5) return rets[0]; /* return actual status */
-
-               if (rets[2] == 0) return -1; /* permanently unavailable */
+       size_t loglen = 0;
+       pci_regs_buf[0] = 0;
 
-               if (max_wait_msecs <= 0) break;
+       eeh_pci_enable(edev, EEH_OPT_THAW_MMIO);
+       eeh_ops->configure_bridge(eeh_dev_to_of_node(edev));
+       eeh_restore_bars(edev);
+       loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
 
-               mwait = rets[2];
-               if (mwait <= 0) {
-                       printk (KERN_WARNING
-                               "EEH: Firmware returned bad wait value=%d\n", mwait);
-                       mwait = 1000;
-               } else if (mwait > 300*1000) {
-                       printk (KERN_WARNING
-                               "EEH: Firmware is taking too long, time=%d\n", mwait);
-                       mwait = 300*1000;
-               }
-               max_wait_msecs -= mwait;
-               msleep (mwait);
-       }
-
-       printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
-       return -2;
+       eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen);
 }
 
 /**
- * eeh_token_to_phys - convert EEH address token to phys address
- * @token i/o token, should be address in the form 0xA....
+ * eeh_token_to_phys - Convert EEH address token to phys address
+ * @token: I/O token, should be address in the form 0xA....
+ *
+ * This routine should be called to convert virtual I/O address
+ * to physical one.
  */
 static inline unsigned long eeh_token_to_phys(unsigned long token)
 {
@@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
        return pa | (token & (PAGE_SIZE-1));
 }
 
-/** 
- * Return the "partitionable endpoint" (pe) under which this device lies
+/**
+ * eeh_find_device_pe - Retrieve the PE for the given device
+ * @dn: device node
+ *
+ * Return the PE under which this device lies
  */
-struct device_node * find_device_pe(struct device_node *dn)
+struct device_node *eeh_find_device_pe(struct device_node *dn)
 {
-       while ((dn->parent) && PCI_DN(dn->parent) &&
-             (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+       while (dn->parent && of_node_to_eeh_dev(dn->parent) &&
+              (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
                dn = dn->parent;
        }
        return dn;
 }
 
-/** Mark all devices that are children of this device as failed.
- *  Mark the device driver too, so that it can see the failure
- *  immediately; this is critical, since some drivers poll
- *  status registers in interrupts ... If a driver is polling,
- *  and the slot is frozen, then the driver can deadlock in
- *  an interrupt context, which is bad.
+/**
+ * __eeh_mark_slot - Mark all child devices as failed
+ * @parent: parent device
+ * @mode_flag: failure flag
+ *
+ * Mark all devices that are children of this device as failed.
+ * Mark the device driver too, so that it can see the failure
+ * immediately; this is critical, since some drivers poll
+ * status registers in interrupts ... If a driver is polling,
+ * and the slot is frozen, then the driver can deadlock in
+ * an interrupt context, which is bad.
  */
-
 static void __eeh_mark_slot(struct device_node *parent, int mode_flag)
 {
        struct device_node *dn;
 
        for_each_child_of_node(parent, dn) {
-               if (PCI_DN(dn)) {
+               if (of_node_to_eeh_dev(dn)) {
                        /* Mark the pci device driver too */
-                       struct pci_dev *dev = PCI_DN(dn)->pcidev;
+                       struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev;
 
-                       PCI_DN(dn)->eeh_mode |= mode_flag;
+                       of_node_to_eeh_dev(dn)->mode |= mode_flag;
 
                        if (dev && dev->driver)
                                dev->error_state = pci_channel_io_frozen;
@@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag)
        }
 }
 
-void eeh_mark_slot (struct device_node *dn, int mode_flag)
+/**
+ * eeh_mark_slot - Mark the indicated device and its children as failed
+ * @dn: parent device
+ * @mode_flag: failure flag
+ *
+ * Mark the indicated device and its child devices as failed.
+ * The device drivers are marked as failed as well.
+ */
+void eeh_mark_slot(struct device_node *dn, int mode_flag)
 {
        struct pci_dev *dev;
-       dn = find_device_pe (dn);
+       dn = eeh_find_device_pe(dn);
 
        /* Back up one, since config addrs might be shared */
-       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+       if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
                dn = dn->parent;
 
-       PCI_DN(dn)->eeh_mode |= mode_flag;
+       of_node_to_eeh_dev(dn)->mode |= mode_flag;
 
        /* Mark the pci device too */
-       dev = PCI_DN(dn)->pcidev;
+       dev = of_node_to_eeh_dev(dn)->pdev;
        if (dev)
                dev->error_state = pci_channel_io_frozen;
 
        __eeh_mark_slot(dn, mode_flag);
 }
 
+/**
+ * __eeh_clear_slot - Clear failure flag for the child devices
+ * @parent: parent device
+ * @mode_flag: flag to be cleared
+ *
+ * Clear failure flag for the child devices.
+ */
 static void __eeh_clear_slot(struct device_node *parent, int mode_flag)
 {
        struct device_node *dn;
 
        for_each_child_of_node(parent, dn) {
-               if (PCI_DN(dn)) {
-                       PCI_DN(dn)->eeh_mode &= ~mode_flag;
-                       PCI_DN(dn)->eeh_check_count = 0;
+               if (of_node_to_eeh_dev(dn)) {
+                       of_node_to_eeh_dev(dn)->mode &= ~mode_flag;
+                       of_node_to_eeh_dev(dn)->check_count = 0;
                        __eeh_clear_slot(dn, mode_flag);
                }
        }
 }
 
-void eeh_clear_slot (struct device_node *dn, int mode_flag)
+/**
+ * eeh_clear_slot - Clear failure flag for the indicated device and its children
+ * @dn: parent device
+ * @mode_flag: flag to be cleared
+ *
+ * Clear failure flag for the indicated device and its children.
+ */
+void eeh_clear_slot(struct device_node *dn, int mode_flag)
 {
        unsigned long flags;
        raw_spin_lock_irqsave(&confirm_error_lock, flags);
        
-       dn = find_device_pe (dn);
+       dn = eeh_find_device_pe(dn);
        
        /* Back up one, since config addrs might be shared */
-       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+       if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
                dn = dn->parent;
 
-       PCI_DN(dn)->eeh_mode &= ~mode_flag;
-       PCI_DN(dn)->eeh_check_count = 0;
+       of_node_to_eeh_dev(dn)->mode &= ~mode_flag;
+       of_node_to_eeh_dev(dn)->check_count = 0;
        __eeh_clear_slot(dn, mode_flag);
        raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
 }
 
-void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
-{
-       struct device_node *dn;
-
-       for_each_child_of_node(parent, dn) {
-               if (PCI_DN(dn)) {
-
-                       struct pci_dev *dev = PCI_DN(dn)->pcidev;
-
-                       if (dev && dev->driver)
-                               *freset |= dev->needs_freset;
-
-                       __eeh_set_pe_freset(dn, freset);
-               }
-       }
-}
-
-void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
-{
-       struct pci_dev *dev;
-       dn = find_device_pe(dn);
-
-       /* Back up one, since config addrs might be shared */
-       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
-               dn = dn->parent;
-
-       dev = PCI_DN(dn)->pcidev;
-       if (dev)
-               *freset |= dev->needs_freset;
-
-       __eeh_set_pe_freset(dn, freset);
-}
-
 /**
- * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze
- * @dn device node
- * @dev pci device, if known
+ * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze
+ * @dn: device node
+ * @dev: pci device, if known
  *
  * Check for an EEH failure for the given device node.  Call this
  * routine if the result of a read was all 0xff's and you want to
@@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
 int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
 {
        int ret;
-       int rets[3];
        unsigned long flags;
-       struct pci_dn *pdn;
+       struct eeh_dev *edev;
        int rc = 0;
        const char *location;
 
-       total_mmio_ffs++;
+       eeh_stats.total_mmio_ffs++;
 
        if (!eeh_subsystem_enabled)
                return 0;
 
        if (!dn) {
-               no_dn++;
+               eeh_stats.no_dn++;
                return 0;
        }
-       dn = find_device_pe(dn);
-       pdn = PCI_DN(dn);
+       dn = eeh_find_device_pe(dn);
+       edev = of_node_to_eeh_dev(dn);
 
        /* Access to IO BARs might get this far and still not want checking. */
-       if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
-           pdn->eeh_mode & EEH_MODE_NOCHECK) {
-               ignored_check++;
+       if (!(edev->mode & EEH_MODE_SUPPORTED) ||
+           edev->mode & EEH_MODE_NOCHECK) {
+               eeh_stats.ignored_check++;
                pr_debug("EEH: Ignored check (%x) for %s %s\n",
-                        pdn->eeh_mode, eeh_pci_name(dev), dn->full_name);
+                       edev->mode, eeh_pci_name(dev), dn->full_name);
                return 0;
        }
 
-       if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) {
-               no_cfg_addr++;
+       if (!edev->config_addr && !edev->pe_config_addr) {
+               eeh_stats.no_cfg_addr++;
                return 0;
        }
 
@@ -544,15 +434,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
         */
        raw_spin_lock_irqsave(&confirm_error_lock, flags);
        rc = 1;
-       if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
-               pdn->eeh_check_count ++;
-               if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) {
+       if (edev->mode & EEH_MODE_ISOLATED) {
+               edev->check_count++;
+               if (edev->check_count % EEH_MAX_FAILS == 0) {
                        location = of_get_property(dn, "ibm,loc-code", NULL);
-                       printk (KERN_ERR "EEH: %d reads ignored for recovering device at "
+                       printk(KERN_ERR "EEH: %d reads ignored for recovering device at "
                                "location=%s driver=%s pci addr=%s\n",
-                               pdn->eeh_check_count, location,
+                               edev->check_count, location,
                                eeh_driver_name(dev), eeh_pci_name(dev));
-                       printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n",
+                       printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n",
                                eeh_driver_name(dev));
                        dump_stack();
                }
@@ -566,58 +456,39 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
         * function zero of a multi-function device.
         * In any case they must share a common PHB.
         */
-       ret = read_slot_reset_state(pdn, rets);
-
-       /* If the call to firmware failed, punt */
-       if (ret != 0) {
-               printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n",
-                      ret, dn->full_name);
-               false_positives++;
-               pdn->eeh_false_positives ++;
-               rc = 0;
-               goto dn_unlock;
-       }
+       ret = eeh_ops->get_state(dn, NULL);
 
        /* Note that config-io to empty slots may fail;
-        * they are empty when they don't have children. */
-       if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) {
-               false_positives++;
-               pdn->eeh_false_positives ++;
-               rc = 0;
-               goto dn_unlock;
-       }
-
-       /* If EEH is not supported on this device, punt. */
-       if (rets[1] != 1) {
-               printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
-                      ret, dn->full_name);
-               false_positives++;
-               pdn->eeh_false_positives ++;
-               rc = 0;
-               goto dn_unlock;
-       }
-
-       /* If not the kind of error we know about, punt. */
-       if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
-               false_positives++;
-               pdn->eeh_false_positives ++;
+        * they are empty when they don't have children.
+        * We will punt with the following conditions: Failure to get
+        * PE's state, EEH not support and Permanently unavailable
+        * state, PE is in good state.
+        */
+       if ((ret < 0) ||
+           (ret == EEH_STATE_NOT_SUPPORT) ||
+           (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
+           (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
+               eeh_stats.false_positives++;
+               edev->false_positives ++;
                rc = 0;
                goto dn_unlock;
        }
 
-       slot_resets++;
+       eeh_stats.slot_resets++;
  
        /* Avoid repeated reports of this failure, including problems
         * with other functions on this device, and functions under
-        * bridges. */
-       eeh_mark_slot (dn, EEH_MODE_ISOLATED);
+        * bridges.
+        */
+       eeh_mark_slot(dn, EEH_MODE_ISOLATED);
        raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
 
-       eeh_send_failure_event (dn, dev);
+       eeh_send_failure_event(edev);
 
        /* Most EEH events are due to device driver bugs.  Having
         * a stack trace will help the device-driver authors figure
-        * out what happened.  So print that out. */
+        * out what happened.  So print that out.
+        */
        dump_stack();
        return 1;
 
@@ -629,9 +500,9 @@ dn_unlock:
 EXPORT_SYMBOL_GPL(eeh_dn_check_failure);
 
 /**
- * eeh_check_failure - check if all 1's data is due to EEH slot freeze
- * @token i/o token, should be address in the form 0xA....
- * @val value, should be all 1's (XXX why do we need this arg??)
+ * eeh_check_failure - Check if all 1's data is due to EEH slot freeze
+ * @token: I/O token, should be address in the form 0xA....
+ * @val: value, should be all 1's (XXX why do we need this arg??)
  *
  * Check for an EEH failure at the given token address.  Call this
  * routine if the result of a read was all 0xff's and you want to
@@ -648,14 +519,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon
 
        /* Finding the phys addr + pci device; this is pretty quick. */
        addr = eeh_token_to_phys((unsigned long __force) token);
-       dev = pci_get_device_by_addr(addr);
+       dev = pci_addr_cache_get_device(addr);
        if (!dev) {
-               no_device++;
+               eeh_stats.no_device++;
                return val;
        }
 
        dn = pci_device_to_OF_node(dev);
-       eeh_dn_check_failure (dn, dev);
+       eeh_dn_check_failure(dn, dev);
 
        pci_dev_put(dev);
        return val;
@@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon
 
 EXPORT_SYMBOL(eeh_check_failure);
 
-/* ------------------------------------------------------------- */
-/* The code below deals with error recovery */
 
 /**
- * rtas_pci_enable - enable MMIO or DMA transfers for this slot
- * @pdn pci device node
+ * eeh_pci_enable - Enable MMIO or DMA transfers for this slot
+ * @edev: pci device node
+ *
+ * This routine should be called to reenable frozen MMIO or DMA
+ * so that it would work correctly again. It's useful while doing
+ * recovery or log collection on the indicated device.
  */
-
-int
-rtas_pci_enable(struct pci_dn *pdn, int function)
+int eeh_pci_enable(struct eeh_dev *edev, int function)
 {
-       int config_addr;
        int rc;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
 
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-                      config_addr,
-                      BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid),
-                           function);
-
+       rc = eeh_ops->set_option(dn, function);
        if (rc)
                printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
-                       function, rc, pdn->node->full_name);
+                       function, rc, dn->full_name);
 
-       rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC);
-       if ((rc == 4) && (function == EEH_THAW_MMIO))
+       rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
+       if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) &&
+          (function == EEH_OPT_THAW_MMIO))
                return 0;
 
        return rc;
 }
 
-/**
- * rtas_pci_slot_reset - raises/lowers the pci #RST line
- * @pdn pci device node
- * @state: 1/0 to raise/lower the #RST
- *
- * Clear the EEH-frozen condition on a slot.  This routine
- * asserts the PCI #RST line if the 'state' argument is '1',
- * and drops the #RST line if 'state is '0'.  This routine is
- * safe to call in an interrupt context.
- *
- */
-
-static void
-rtas_pci_slot_reset(struct pci_dn *pdn, int state)
-{
-       int config_addr;
-       int rc;
-
-       BUG_ON (pdn==NULL); 
-
-       if (!pdn->phb) {
-               printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n",
-                       pdn->node->full_name);
-               return;
-       }
-
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
-                      config_addr,
-                      BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid),
-                      state);
-
-       /* Fundamental-reset not supported on this PE, try hot-reset */
-       if (rc == -8 && state == 3) {
-               rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
-                              config_addr,
-                              BUID_HI(pdn->phb->buid),
-                              BUID_LO(pdn->phb->buid), 1);
-               if (rc)
-                       printk(KERN_WARNING
-                               "EEH: Unable to reset the failed slot,"
-                               " #RST=%d dn=%s\n",
-                               rc, pdn->node->full_name);
-       }
-}
-
 /**
  * pcibios_set_pcie_slot_reset - Set PCI-E reset state
- * @dev:       pci device struct
- * @state:     reset state to enter
+ * @dev: pci device struct
+ * @state: reset state to enter
  *
  * Return value:
  *     0 if success
- **/
+ */
 int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
 {
        struct device_node *dn = pci_device_to_OF_node(dev);
-       struct pci_dn *pdn = PCI_DN(dn);
 
        switch (state) {
        case pcie_deassert_reset:
-               rtas_pci_slot_reset(pdn, 0);
+               eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);
                break;
        case pcie_hot_reset:
-               rtas_pci_slot_reset(pdn, 1);
+               eeh_ops->reset(dn, EEH_RESET_HOT);
                break;
        case pcie_warm_reset:
-               rtas_pci_slot_reset(pdn, 3);
+               eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);
                break;
        default:
                return -EINVAL;
@@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
 }
 
 /**
- * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
- * @pdn: pci device node to be reset.
+ * __eeh_set_pe_freset - Check the required reset for child devices
+ * @parent: parent device
+ * @freset: return value
+ *
+ * Each device might have its preferred reset type: fundamental or
+ * hot reset. The routine is used to collect the information from
+ * the child devices so that they could be reset accordingly.
+ */
+void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
+{
+       struct device_node *dn;
+
+       for_each_child_of_node(parent, dn) {
+               if (of_node_to_eeh_dev(dn)) {
+                       struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev;
+
+                       if (dev && dev->driver)
+                               *freset |= dev->needs_freset;
+
+                       __eeh_set_pe_freset(dn, freset);
+               }
+       }
+}
+
+/**
+ * eeh_set_pe_freset - Check the required reset for the indicated device and its children
+ * @dn: parent device
+ * @freset: return value
+ *
+ * Each device might have its preferred reset type: fundamental or
+ * hot reset. The routine is used to collected the information for
+ * the indicated device and its children so that the bunch of the
+ * devices could be reset properly.
  */
+void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
+{
+       struct pci_dev *dev;
+       dn = eeh_find_device_pe(dn);
+
+       /* Back up one, since config addrs might be shared */
+       if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
+               dn = dn->parent;
+
+       dev = of_node_to_eeh_dev(dn)->pdev;
+       if (dev)
+               *freset |= dev->needs_freset;
 
-static void __rtas_set_slot_reset(struct pci_dn *pdn)
+       __eeh_set_pe_freset(dn, freset);
+}
+
+/**
+ * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second
+ * @edev: pci device node to be reset.
+ *
+ * Assert the PCI #RST line for 1/4 second.
+ */
+static void eeh_reset_pe_once(struct eeh_dev *edev)
 {
        unsigned int freset = 0;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
 
        /* Determine type of EEH reset required for
         * Partitionable Endpoint, a hot-reset (1)
@@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn)
         * A fundamental reset required by any device under
         * Partitionable Endpoint trumps hot-reset.
         */
-       eeh_set_pe_freset(pdn->node, &freset);
+       eeh_set_pe_freset(dn, &freset);
 
        if (freset)
-               rtas_pci_slot_reset(pdn, 3);
+               eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);
        else
-               rtas_pci_slot_reset(pdn, 1);
+               eeh_ops->reset(dn, EEH_RESET_HOT);
 
        /* The PCI bus requires that the reset be held high for at least
-        * a 100 milliseconds. We wait a bit longer 'just in case'.  */
-
+        * a 100 milliseconds. We wait a bit longer 'just in case'.
+        */
 #define PCI_BUS_RST_HOLD_TIME_MSEC 250
-       msleep (PCI_BUS_RST_HOLD_TIME_MSEC);
+       msleep(PCI_BUS_RST_HOLD_TIME_MSEC);
        
        /* We might get hit with another EEH freeze as soon as the 
         * pci slot reset line is dropped. Make sure we don't miss
-        * these, and clear the flag now. */
-       eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED);
+        * these, and clear the flag now.
+        */
+       eeh_clear_slot(dn, EEH_MODE_ISOLATED);
 
-       rtas_pci_slot_reset (pdn, 0);
+       eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);
 
        /* After a PCI slot has been reset, the PCI Express spec requires
         * a 1.5 second idle time for the bus to stabilize, before starting
-        * up traffic. */
+        * up traffic.
+        */
 #define PCI_BUS_SETTLE_TIME_MSEC 1800
-       msleep (PCI_BUS_SETTLE_TIME_MSEC);
+       msleep(PCI_BUS_SETTLE_TIME_MSEC);
 }
 
-int rtas_set_slot_reset(struct pci_dn *pdn)
+/**
+ * eeh_reset_pe - Reset the indicated PE
+ * @edev: PCI device associated EEH device
+ *
+ * This routine should be called to reset indicated device, including
+ * PE. A PE might include multiple PCI devices and sometimes PCI bridges
+ * might be involved as well.
+ */
+int eeh_reset_pe(struct eeh_dev *edev)
 {
        int i, rc;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
 
        /* Take three shots at resetting the bus */
        for (i=0; i<3; i++) {
-               __rtas_set_slot_reset(pdn);
+               eeh_reset_pe_once(edev);
 
-               rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
-               if (rc == 0)
+               rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
+               if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
                        return 0;
 
                if (rc < 0) {
                        printk(KERN_ERR "EEH: unrecoverable slot failure %s\n",
-                              pdn->node->full_name);
+                              dn->full_name);
                        return -1;
                }
                printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n",
-                      i+1, pdn->node->full_name, rc);
+                      i+1, dn->full_name, rc);
        }
 
        return -1;
 }
 
-/* ------------------------------------------------------- */
 /** Save and restore of PCI BARs
  *
  * Although firmware will set up BARs during boot, it doesn't
@@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn)
  */
 
 /**
- * __restore_bars - Restore the Base Address Registers
- * @pdn: pci device node
+ * eeh_restore_one_device_bars - Restore the Base Address Registers for one device
+ * @edev: PCI device associated EEH device
  *
  * Loads the PCI configuration space base address registers,
  * the expansion ROM base address, the latency timer, and etc.
  * from the saved values in the device node.
  */
-static inline void __restore_bars (struct pci_dn *pdn)
+static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
 {
        int i;
        u32 cmd;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
+
+       if (!edev->phb)
+               return;
 
-       if (NULL==pdn->phb) return;
        for (i=4; i<10; i++) {
-               rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);
+               eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
        }
 
        /* 12 == Expansion ROM Address */
-       rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);
+       eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
 
 #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
-#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])
+#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
 
-       rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1,
+       eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
                    SAVED_BYTE(PCI_CACHE_LINE_SIZE));
 
-       rtas_write_config (pdn, PCI_LATENCY_TIMER, 1,
+       eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
                    SAVED_BYTE(PCI_LATENCY_TIMER));
 
        /* max latency, min grant, interrupt pin and line */
-       rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);
+       eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
 
        /* Restore PERR & SERR bits, some devices require it,
-          don't touch the other command bits */
-       rtas_read_config(pdn, PCI_COMMAND, 4, &cmd);
-       if (pdn->config_space[1] & PCI_COMMAND_PARITY)
+        * don't touch the other command bits
+        */
+       eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
+       if (edev->config_space[1] & PCI_COMMAND_PARITY)
                cmd |= PCI_COMMAND_PARITY;
        else
                cmd &= ~PCI_COMMAND_PARITY;
-       if (pdn->config_space[1] & PCI_COMMAND_SERR)
+       if (edev->config_space[1] & PCI_COMMAND_SERR)
                cmd |= PCI_COMMAND_SERR;
        else
                cmd &= ~PCI_COMMAND_SERR;
-       rtas_write_config(pdn, PCI_COMMAND, 4, cmd);
+       eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
 }
 
 /**
- * eeh_restore_bars - restore the PCI config space info
+ * eeh_restore_bars - Restore the PCI config space info
+ * @edev: EEH device
  *
  * This routine performs a recursive walk to the children
  * of this device as well.
  */
-void eeh_restore_bars(struct pci_dn *pdn)
+void eeh_restore_bars(struct eeh_dev *edev)
 {
        struct device_node *dn;
-       if (!pdn) 
+       if (!edev)
                return;
        
-       if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code))
-               __restore_bars (pdn);
+       if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code))
+               eeh_restore_one_device_bars(edev);
 
-       for_each_child_of_node(pdn->node, dn)
-               eeh_restore_bars (PCI_DN(dn));
+       for_each_child_of_node(eeh_dev_to_of_node(edev), dn)
+               eeh_restore_bars(of_node_to_eeh_dev(dn));
 }
 
 /**
- * eeh_save_bars - save device bars
+ * eeh_save_bars - Save device bars
+ * @edev: PCI device associated EEH device
  *
  * Save the values of the device bars. Unlike the restore
  * routine, this routine is *not* recursive. This is because
  * PCI devices are added individually; but, for the restore,
  * an entire slot is reset at a time.
  */
-static void eeh_save_bars(struct pci_dn *pdn)
+static void eeh_save_bars(struct eeh_dev *edev)
 {
        int i;
+       struct device_node *dn;
 
-       if (!pdn )
+       if (!edev)
                return;
+       dn = eeh_dev_to_of_node(edev);
        
        for (i = 0; i < 16; i++)
-               rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);
-}
-
-void
-rtas_configure_bridge(struct pci_dn *pdn)
-{
-       int config_addr;
-       int rc;
-       int token;
-
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       /* Use new configure-pe function, if supported */
-       if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
-               token = ibm_configure_pe;
-       else
-               token = ibm_configure_bridge;
-
-       rc = rtas_call(token, 3, 1, NULL,
-                      config_addr,
-                      BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid));
-       if (rc) {
-               printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
-                       rc, pdn->node->full_name);
-       }
+               eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
 }
 
-/* ------------------------------------------------------------- */
-/* The code below deals with enabling EEH for devices during  the
- * early boot sequence.  EEH must be enabled before any PCI probing
- * can be done.
+/**
+ * eeh_early_enable - Early enable EEH on the indicated device
+ * @dn: device node
+ * @data: BUID
+ *
+ * Enable EEH functionality on the specified PCI device. The function
+ * is expected to be called before real PCI probing is done. However,
+ * the PHBs have been initialized at this point.
  */
-
-#define EEH_ENABLE 1
-
-struct eeh_early_enable_info {
-       unsigned int buid_hi;
-       unsigned int buid_lo;
-};
-
-static int get_pe_addr (int config_addr,
-                        struct eeh_early_enable_info *info)
+static void *eeh_early_enable(struct device_node *dn, void *data)
 {
-       unsigned int rets[3];
-       int ret;
-
-       /* Use latest config-addr token on power6 */
-       if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
-               /* Make sure we have a PE in hand */
-               ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
-                       config_addr, info->buid_hi, info->buid_lo, 1);
-               if (ret || (rets[0]==0))
-                       return 0;
-
-               ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
-                       config_addr, info->buid_hi, info->buid_lo, 0);
-               if (ret)
-                       return 0;
-               return rets[0];
-       }
-
-       /* Use older config-addr token on power5 */
-       if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
-               ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
-                       config_addr, info->buid_hi, info->buid_lo, 0);
-               if (ret)
-                       return 0;
-               return rets[0];
-       }
-       return 0;
-}
-
-/* Enable eeh for the given device node. */
-static void *early_enable_eeh(struct device_node *dn, void *data)
-{
-       unsigned int rets[3];
-       struct eeh_early_enable_info *info = data;
        int ret;
        const u32 *class_code = of_get_property(dn, "class-code", NULL);
        const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
        const u32 *device_id = of_get_property(dn, "device-id", NULL);
        const u32 *regs;
        int enable;
-       struct pci_dn *pdn = PCI_DN(dn);
+       struct eeh_dev *edev = of_node_to_eeh_dev(dn);
 
-       pdn->class_code = 0;
-       pdn->eeh_mode = 0;
-       pdn->eeh_check_count = 0;
-       pdn->eeh_freeze_count = 0;
-       pdn->eeh_false_positives = 0;
+       edev->class_code = 0;
+       edev->mode = 0;
+       edev->check_count = 0;
+       edev->freeze_count = 0;
+       edev->false_positives = 0;
 
        if (!of_device_is_available(dn))
                return NULL;
@@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
 
        /* There is nothing to check on PCI to ISA bridges */
        if (dn->type && !strcmp(dn->type, "isa")) {
-               pdn->eeh_mode |= EEH_MODE_NOCHECK;
+               edev->mode |= EEH_MODE_NOCHECK;
                return NULL;
        }
-       pdn->class_code = *class_code;
+       edev->class_code = *class_code;
 
        /* Ok... see if this device supports EEH.  Some do, some don't,
-        * and the only way to find out is to check each and every one. */
+        * and the only way to find out is to check each and every one.
+        */
        regs = of_get_property(dn, "reg", NULL);
        if (regs) {
                /* First register entry is addr (00BBSS00)  */
                /* Try to enable eeh */
-               ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
-                               regs[0], info->buid_hi, info->buid_lo,
-                               EEH_ENABLE);
+               ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE);
 
                enable = 0;
                if (ret == 0) {
-                       pdn->eeh_config_addr = regs[0];
+                       edev->config_addr = regs[0];
 
                        /* If the newer, better, ibm,get-config-addr-info is supported, 
-                        * then use that instead. */
-                       pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);
+                        * then use that instead.
+                        */
+                       edev->pe_config_addr = eeh_ops->get_pe_addr(dn);
 
                        /* Some older systems (Power4) allow the
                         * ibm,set-eeh-option call to succeed even on nodes
                         * where EEH is not supported. Verify support
-                        * explicitly. */
-                       ret = read_slot_reset_state(pdn, rets);
-                       if ((ret == 0) && (rets[1] == 1))
+                        * explicitly.
+                        */
+                       ret = eeh_ops->get_state(dn, NULL);
+                       if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
                                enable = 1;
                }
 
                if (enable) {
                        eeh_subsystem_enabled = 1;
-                       pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+                       edev->mode |= EEH_MODE_SUPPORTED;
 
                        pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
-                                dn->full_name, pdn->eeh_config_addr,
-                                pdn->eeh_pe_config_addr);
+                                dn->full_name, edev->config_addr,
+                                edev->pe_config_addr);
                } else {
 
                        /* This device doesn't support EEH, but it may have an
-                        * EEH parent, in which case we mark it as supported. */
-                       if (dn->parent && PCI_DN(dn->parent)
-                           && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+                        * EEH parent, in which case we mark it as supported.
+                        */
+                       if (dn->parent && of_node_to_eeh_dev(dn->parent) &&
+                           (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
                                /* Parent supports EEH. */
-                               pdn->eeh_mode |= EEH_MODE_SUPPORTED;
-                               pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;
+                               edev->mode |= EEH_MODE_SUPPORTED;
+                               edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr;
                                return NULL;
                        }
                }
@@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
                       dn->full_name);
        }
 
-       eeh_save_bars(pdn);
+       eeh_save_bars(edev);
        return NULL;
 }
 
-/*
+/**
+ * eeh_ops_register - Register platform dependent EEH operations
+ * @ops: platform dependent EEH operations
+ *
+ * Register the platform dependent EEH operation callback
+ * functions. The platform should call this function before
+ * any other EEH operations.
+ */
+int __init eeh_ops_register(struct eeh_ops *ops)
+{
+       if (!ops->name) {
+               pr_warning("%s: Invalid EEH ops name for %p\n",
+                       __func__, ops);
+               return -EINVAL;
+       }
+
+       if (eeh_ops && eeh_ops != ops) {
+               pr_warning("%s: EEH ops of platform %s already existing (%s)\n",
+                       __func__, eeh_ops->name, ops->name);
+               return -EEXIST;
+       }
+
+       eeh_ops = ops;
+
+       return 0;
+}
+
+/**
+ * eeh_ops_unregister - Unreigster platform dependent EEH operations
+ * @name: name of EEH platform operations
+ *
+ * Unregister the platform dependent EEH operation callback
+ * functions.
+ */
+int __exit eeh_ops_unregister(const char *name)
+{
+       if (!name || !strlen(name)) {
+               pr_warning("%s: Invalid EEH ops name\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       if (eeh_ops && !strcmp(eeh_ops->name, name)) {
+               eeh_ops = NULL;
+               return 0;
+       }
+
+       return -EEXIST;
+}
+
+/**
+ * eeh_init - EEH initialization
+ *
  * Initialize EEH by trying to enable it for all of the adapters in the system.
  * As a side effect we can determine here if eeh is supported at all.
  * Note that we leave EEH on so failed config cycles won't cause a machine
@@ -1117,50 +985,35 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
 void __init eeh_init(void)
 {
        struct device_node *phb, *np;
-       struct eeh_early_enable_info info;
+       int ret;
+
+       /* call platform initialization function */
+       if (!eeh_ops) {
+               pr_warning("%s: Platform EEH operation not found\n",
+                       __func__);
+               return;
+       } else if ((ret = eeh_ops->init())) {
+               pr_warning("%s: Failed to call platform init function (%d)\n",
+                       __func__, ret);
+               return;
+       }
 
        raw_spin_lock_init(&confirm_error_lock);
-       spin_lock_init(&slot_errbuf_lock);
 
        np = of_find_node_by_path("/rtas");
        if (np == NULL)
                return;
 
-       ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
-       ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
-       ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2");
-       ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-       ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
-       ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
-       ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
-       ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
-       ibm_configure_pe = rtas_token("ibm,configure-pe");
-
-       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
-               return;
-
-       eeh_error_buf_size = rtas_token("rtas-error-log-max");
-       if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
-               eeh_error_buf_size = 1024;
-       }
-       if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
-               printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "
-                     "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
-               eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
-       }
-
        /* Enable EEH for all adapters.  Note that eeh requires buid's */
        for (phb = of_find_node_by_name(NULL, "pci"); phb;
             phb = of_find_node_by_name(phb, "pci")) {
                unsigned long buid;
 
                buid = get_phb_buid(phb);
-               if (buid == 0 || PCI_DN(phb) == NULL)
+               if (buid == 0 || !of_node_to_eeh_dev(phb))
                        continue;
 
-               info.buid_lo = BUID_LO(buid);
-               info.buid_hi = BUID_HI(buid);
-               traverse_pci_devices(phb, early_enable_eeh, &info);
+               traverse_pci_devices(phb, eeh_early_enable, NULL);
        }
 
        if (eeh_subsystem_enabled)
@@ -1170,7 +1023,7 @@ void __init eeh_init(void)
 }
 
 /**
- * eeh_add_device_early - enable EEH for the indicated device_node
+ * eeh_add_device_early - Enable EEH for the indicated device_node
  * @dn: device node for which to set up EEH
  *
  * This routine must be used to perform EEH initialization for PCI
@@ -1184,21 +1037,26 @@ void __init eeh_init(void)
 static void eeh_add_device_early(struct device_node *dn)
 {
        struct pci_controller *phb;
-       struct eeh_early_enable_info info;
 
-       if (!dn || !PCI_DN(dn))
+       if (!dn || !of_node_to_eeh_dev(dn))
                return;
-       phb = PCI_DN(dn)->phb;
+       phb = of_node_to_eeh_dev(dn)->phb;
 
        /* USB Bus children of PCI devices will not have BUID's */
        if (NULL == phb || 0 == phb->buid)
                return;
 
-       info.buid_hi = BUID_HI(phb->buid);
-       info.buid_lo = BUID_LO(phb->buid);
-       early_enable_eeh(dn, &info);
+       eeh_early_enable(dn, NULL);
 }
 
+/**
+ * eeh_add_device_tree_early - Enable EEH for the indicated device
+ * @dn: device node
+ *
+ * This routine must be used to perform EEH initialization for the
+ * indicated PCI device that was added after system boot (e.g.
+ * hotplug, dlpar).
+ */
 void eeh_add_device_tree_early(struct device_node *dn)
 {
        struct device_node *sib;
@@ -1210,7 +1068,7 @@ void eeh_add_device_tree_early(struct device_node *dn)
 EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
 
 /**
- * eeh_add_device_late - perform EEH initialization for the indicated pci device
+ * eeh_add_device_late - Perform EEH initialization for the indicated pci device
  * @dev: pci device for which to set up EEH
  *
  * This routine must be used to complete EEH initialization for PCI
@@ -1219,7 +1077,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
 static void eeh_add_device_late(struct pci_dev *dev)
 {
        struct device_node *dn;
-       struct pci_dn *pdn;
+       struct eeh_dev *edev;
 
        if (!dev || !eeh_subsystem_enabled)
                return;
@@ -1227,20 +1085,29 @@ static void eeh_add_device_late(struct pci_dev *dev)
        pr_debug("EEH: Adding device %s\n", pci_name(dev));
 
        dn = pci_device_to_OF_node(dev);
-       pdn = PCI_DN(dn);
-       if (pdn->pcidev == dev) {
+       edev = pci_dev_to_eeh_dev(dev);
+       if (edev->pdev == dev) {
                pr_debug("EEH: Already referenced !\n");
                return;
        }
-       WARN_ON(pdn->pcidev);
+       WARN_ON(edev->pdev);
 
-       pci_dev_get (dev);
-       pdn->pcidev = dev;
+       pci_dev_get(dev);
+       edev->pdev = dev;
+       dev->dev.archdata.edev = edev;
 
        pci_addr_cache_insert_device(dev);
        eeh_sysfs_add_device(dev);
 }
 
+/**
+ * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus
+ * @bus: PCI bus
+ *
+ * This routine must be used to perform EEH initialization for PCI
+ * devices which are attached to the indicated PCI bus. The PCI bus
+ * is added after system boot through hotplug or dlpar.
+ */
 void eeh_add_device_tree_late(struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -1257,7 +1124,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus)
 EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
 
 /**
- * eeh_remove_device - undo EEH setup for the indicated pci device
+ * eeh_remove_device - Undo EEH setup for the indicated pci device
  * @dev: pci device to be removed
  *
  * This routine should be called when a device is removed from
@@ -1268,25 +1135,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
  */
 static void eeh_remove_device(struct pci_dev *dev)
 {
-       struct device_node *dn;
+       struct eeh_dev *edev;
+
        if (!dev || !eeh_subsystem_enabled)
                return;
+       edev = pci_dev_to_eeh_dev(dev);
 
        /* Unregister the device with the EEH/PCI address search system */
        pr_debug("EEH: Removing device %s\n", pci_name(dev));
 
-       dn = pci_device_to_OF_node(dev);
-       if (PCI_DN(dn)->pcidev == NULL) {
+       if (!edev || !edev->pdev) {
                pr_debug("EEH: Not referenced !\n");
                return;
        }
-       PCI_DN(dn)->pcidev = NULL;
-       pci_dev_put (dev);
+       edev->pdev = NULL;
+       dev->dev.archdata.edev = NULL;
+       pci_dev_put(dev);
 
        pci_addr_cache_remove_device(dev);
        eeh_sysfs_remove_device(dev);
 }
 
+/**
+ * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device
+ * @dev: PCI device
+ *
+ * This routine must be called when a device is removed from the
+ * running system through hotplug or dlpar. The corresponding
+ * PCI address cache will be removed.
+ */
 void eeh_remove_bus_device(struct pci_dev *dev)
 {
        struct pci_bus *bus = dev->subordinate;
@@ -1305,21 +1182,24 @@ static int proc_eeh_show(struct seq_file *m, void *v)
 {
        if (0 == eeh_subsystem_enabled) {
                seq_printf(m, "EEH Subsystem is globally disabled\n");
-               seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs);
+               seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
        } else {
                seq_printf(m, "EEH Subsystem is enabled\n");
                seq_printf(m,
-                               "no device=%ld\n"
-                               "no device node=%ld\n"
-                               "no config address=%ld\n"
-                               "check not wanted=%ld\n"
-                               "eeh_total_mmio_ffs=%ld\n"
-                               "eeh_false_positives=%ld\n"
-                               "eeh_slot_resets=%ld\n",
-                               no_device, no_dn, no_cfg_addr, 
-                               ignored_check, total_mmio_ffs, 
-                               false_positives,
-                               slot_resets);
+                               "no device=%llu\n"
+                               "no device node=%llu\n"
+                               "no config address=%llu\n"
+                               "check not wanted=%llu\n"
+                               "eeh_total_mmio_ffs=%llu\n"
+                               "eeh_false_positives=%llu\n"
+                               "eeh_slot_resets=%llu\n",
+                               eeh_stats.no_device,
+                               eeh_stats.no_dn,
+                               eeh_stats.no_cfg_addr,
+                               eeh_stats.ignored_check,
+                               eeh_stats.total_mmio_ffs,
+                               eeh_stats.false_positives,
+                               eeh_stats.slot_resets);
        }
 
        return 0;
index fc5ae76..e5ae1c6 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * eeh_cache.c
  * PCI address cache; allows the lookup of PCI devices based on I/O address
  *
  * Copyright IBM Corporation 2004
@@ -47,8 +46,7 @@
  * than any hash algo I could think of for this problem, even
  * with the penalty of slow pointer chases for d-cache misses).
  */
-struct pci_io_addr_range
-{
+struct pci_io_addr_range {
        struct rb_node rb_node;
        unsigned long addr_lo;
        unsigned long addr_hi;
@@ -56,13 +54,12 @@ struct pci_io_addr_range
        unsigned int flags;
 };
 
-static struct pci_io_addr_cache
-{
+static struct pci_io_addr_cache {
        struct rb_root rb_root;
        spinlock_t piar_lock;
 } pci_io_addr_cache_root;
 
-static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)
+static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr)
 {
        struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node;
 
@@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)
 }
 
 /**
- * pci_get_device_by_addr - Get device, given only address
+ * pci_addr_cache_get_device - Get device, given only address
  * @addr: mmio (PIO) phys address or i/o port number
  *
  * Given an mmio phys address, or a port number, find a pci device
@@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)
  * from zero (that is, they do *not* have pci_io_addr added in).
  * It is safe to call this function within an interrupt.
  */
-struct pci_dev *pci_get_device_by_addr(unsigned long addr)
+struct pci_dev *pci_addr_cache_get_device(unsigned long addr)
 {
        struct pci_dev *dev;
        unsigned long flags;
 
        spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
-       dev = __pci_get_device_by_addr(addr);
+       dev = __pci_addr_cache_get_device(addr);
        spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
        return dev;
 }
@@ -166,7 +163,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
 
 #ifdef DEBUG
        printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n",
-                         alo, ahi, pci_name (dev));
+                         alo, ahi, pci_name(dev));
 #endif
 
        rb_link_node(&piar->rb_node, parent, p);
@@ -178,7 +175,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
 static void __pci_addr_cache_insert_device(struct pci_dev *dev)
 {
        struct device_node *dn;
-       struct pci_dn *pdn;
+       struct eeh_dev *edev;
        int i;
 
        dn = pci_device_to_OF_node(dev);
@@ -187,13 +184,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev)
                return;
        }
 
+       edev = of_node_to_eeh_dev(dn);
+       if (!edev) {
+               pr_warning("PCI: no EEH dev found for dn=%s\n",
+                       dn->full_name);
+               return;
+       }
+
        /* Skip any devices for which EEH is not enabled. */
-       pdn = PCI_DN(dn);
-       if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
-           pdn->eeh_mode & EEH_MODE_NOCHECK) {
+       if (!(edev->mode & EEH_MODE_SUPPORTED) ||
+           edev->mode & EEH_MODE_NOCHECK) {
 #ifdef DEBUG
-               printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n",
-                      pci_name(dev), pdn->node->full_name);
+               pr_info("PCI: skip building address cache for=%s - %s\n",
+                       pci_name(dev), dn->full_name);
 #endif
                return;
        }
@@ -284,6 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev)
 void __init pci_addr_cache_build(void)
 {
        struct device_node *dn;
+       struct eeh_dev *edev;
        struct pci_dev *dev = NULL;
 
        spin_lock_init(&pci_io_addr_cache_root.piar_lock);
@@ -294,8 +298,14 @@ void __init pci_addr_cache_build(void)
                dn = pci_device_to_OF_node(dev);
                if (!dn)
                        continue;
+
+               edev = of_node_to_eeh_dev(dn);
+               if (!edev)
+                       continue;
+
                pci_dev_get(dev);  /* matching put is in eeh_remove_device() */
-               PCI_DN(dn)->pcidev = dev;
+               dev->dev.archdata.edev = edev;
+               edev->pdev = dev;
 
                eeh_sysfs_add_device(dev);
        }
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c
new file mode 100644 (file)
index 0000000..f3aed7d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * The file intends to implement dynamic creation of EEH device, which will
+ * be bound with OF node and PCI device simutaneously. The EEH devices would
+ * be foundamental information for EEH core components to work proerly. Besides,
+ * We have to support multiple situations where dynamic creation of EEH device
+ * is required:
+ *
+ * 1) Before PCI emunation starts, we need create EEH devices according to the
+ *    PCI sensitive OF nodes.
+ * 2) When PCI emunation is done, we need do the binding between PCI device and
+ *    the associated EEH device.
+ * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device
+ *    will be created while PCI sensitive OF node is detected from DR.
+ * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If
+ *    PHB is newly inserted, we also need create EEH devices accordingly.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/export.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+/**
+ * eeh_dev_init - Create EEH device according to OF node
+ * @dn: device node
+ * @data: PHB
+ *
+ * It will create EEH device according to the given OF node. The function
+ * might be called by PCI emunation, DR, PHB hotplug.
+ */
+void * __devinit eeh_dev_init(struct device_node *dn, void *data)
+{
+       struct pci_controller *phb = data;
+       struct eeh_dev *edev;
+
+       /* Allocate EEH device */
+       edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL);
+       if (!edev) {
+               pr_warning("%s: out of memory\n", __func__);
+               return NULL;
+       }
+
+       /* Associate EEH device with OF node */
+       dn->edev  = edev;
+       edev->dn  = dn;
+       edev->phb = phb;
+
+       return NULL;
+}
+
+/**
+ * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB
+ * @phb: PHB
+ *
+ * Scan the PHB OF node and its child association, then create the
+ * EEH devices accordingly
+ */
+void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb)
+{
+       struct device_node *dn = phb->dn;
+
+       /* EEH device for PHB */
+       eeh_dev_init(dn, phb);
+
+       /* EEH devices for children OF nodes */
+       traverse_pci_devices(dn, eeh_dev_init, phb);
+}
+
+/**
+ * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs
+ *
+ * Scan all the existing PHBs and create EEH devices for their OF
+ * nodes and their children OF nodes
+ */
+void __init eeh_dev_phb_init(void)
+{
+       struct pci_controller *phb, *tmp;
+
+       list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
+               eeh_dev_phb_init_dynamic(phb);
+}
index 1b6cb10..baf92cd 100644 (file)
 #include <asm/prom.h>
 #include <asm/rtas.h>
 
-
-static inline const char * pcid_name (struct pci_dev *pdev)
+/**
+ * eeh_pcid_name - Retrieve name of PCI device driver
+ * @pdev: PCI device
+ *
+ * This routine is used to retrieve the name of PCI device driver
+ * if that's valid.
+ */
+static inline const char *eeh_pcid_name(struct pci_dev *pdev)
 {
        if (pdev && pdev->dev.driver)
                return pdev->dev.driver->name;
@@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent)
 #endif
 
 /**
- * eeh_disable_irq - disable interrupt for the recovering device
+ * eeh_disable_irq - Disable interrupt for the recovering device
+ * @dev: PCI device
+ *
+ * This routine must be called when reporting temporary or permanent
+ * error to the particular PCI device to disable interrupt of that
+ * device. If the device has enabled MSI or MSI-X interrupt, we needn't
+ * do real work because EEH should freeze DMA transfers for those PCI
+ * devices encountering EEH errors, which includes MSI or MSI-X.
  */
 static void eeh_disable_irq(struct pci_dev *dev)
 {
-       struct device_node *dn = pci_device_to_OF_node(dev);
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
 
        /* Don't disable MSI and MSI-X interrupts. They are
         * effectively disabled by the DMA Stopped state
         * when an EEH error occurs.
-       */
+        */
        if (dev->msi_enabled || dev->msix_enabled)
                return;
 
        if (!irq_has_action(dev->irq))
                return;
 
-       PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED;
+       edev->mode |= EEH_MODE_IRQ_DISABLED;
        disable_irq_nosync(dev->irq);
 }
 
 /**
- * eeh_enable_irq - enable interrupt for the recovering device
+ * eeh_enable_irq - Enable interrupt for the recovering device
+ * @dev: PCI device
+ *
+ * This routine must be called to enable interrupt while failed
+ * device could be resumed.
  */
 static void eeh_enable_irq(struct pci_dev *dev)
 {
-       struct device_node *dn = pci_device_to_OF_node(dev);
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
 
-       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
-               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+       if ((edev->mode) & EEH_MODE_IRQ_DISABLED) {
+               edev->mode &= ~EEH_MODE_IRQ_DISABLED;
                enable_irq(dev->irq);
        }
 }
 
-/* ------------------------------------------------------- */
 /**
- * eeh_report_error - report pci error to each device driver
+ * eeh_report_error - Report pci error to each device driver
+ * @dev: PCI device
+ * @userdata: return value
  * 
  * Report an EEH error to each device driver, collect up and 
  * merge the device driver responses. Cumulative response 
  * passed back in "userdata".
  */
-
 static int eeh_report_error(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
@@ -122,7 +139,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)
            !driver->err_handler->error_detected)
                return 0;
 
-       rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
+       rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen);
 
        /* A driver that needs a reset trumps all others */
        if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
@@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)
 }
 
 /**
- * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled
+ * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled
+ * @dev: PCI device
+ * @userdata: return value
  *
  * Tells each device driver that IO ports, MMIO and config space I/O
  * are now enabled. Collects up and merges the device driver responses.
  * Cumulative response passed back in "userdata".
  */
-
 static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
@@ -149,7 +167,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
            !driver->err_handler->mmio_enabled)
                return 0;
 
-       rc = driver->err_handler->mmio_enabled (dev);
+       rc = driver->err_handler->mmio_enabled(dev);
 
        /* A driver that needs a reset trumps all others */
        if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
@@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
 }
 
 /**
- * eeh_report_reset - tell device that slot has been reset
+ * eeh_report_reset - Tell device that slot has been reset
+ * @dev: PCI device
+ * @userdata: return value
+ *
+ * This routine must be called while EEH tries to reset particular
+ * PCI device so that the associated PCI device driver could take
+ * some actions, usually to save data the driver needs so that the
+ * driver can work again while the device is recovered.
  */
-
 static int eeh_report_reset(struct pci_dev *dev, void *userdata)
 {
        enum pci_ers_result rc, *res = userdata;
@@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata)
 }
 
 /**
- * eeh_report_resume - tell device to resume normal operations
+ * eeh_report_resume - Tell device to resume normal operations
+ * @dev: PCI device
+ * @userdata: return value
+ *
+ * This routine must be called to notify the device driver that it
+ * could resume so that the device driver can do some initialization
+ * to make the recovered device work again.
  */
-
 static int eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
        struct pci_driver *driver = dev->driver;
@@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata)
 }
 
 /**
- * eeh_report_failure - tell device driver that device is dead.
+ * eeh_report_failure - Tell device driver that device is dead.
+ * @dev: PCI device
+ * @userdata: return value
  *
  * This informs the device driver that the device is permanently
  * dead, and that no further recovery attempts will be made on it.
  */
-
 static int eeh_report_failure(struct pci_dev *dev, void *userdata)
 {
        struct pci_driver *driver = dev->driver;
@@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata)
        return 0;
 }
 
-/* ------------------------------------------------------- */
 /**
- * handle_eeh_events -- reset a PCI device after hard lockup.
- *
- * pSeries systems will isolate a PCI slot if the PCI-Host
- * bridge detects address or data parity errors, DMA's
- * occurring to wild addresses (which usually happen due to
- * bugs in device drivers or in PCI adapter firmware).
- * Slot isolations also occur if #SERR, #PERR or other misc
- * PCI-related errors are detected.
+ * eeh_reset_device - Perform actual reset of a pci slot
+ * @edev: PE associated EEH device
+ * @bus: PCI bus corresponding to the isolcated slot
  *
- * Recovery process consists of unplugging the device driver
- * (which generated hotplug events to userspace), then issuing
- * a PCI #RST to the device, then reconfiguring the PCI config
- * space for all bridges & devices under this slot, and then
- * finally restarting the device drivers (which cause a second
- * set of hotplug events to go out to userspace).
+ * This routine must be called to do reset on the indicated PE.
+ * During the reset, udev might be invoked because those affected
+ * PCI devices will be removed and then added.
  */
-
-/**
- * eeh_reset_device() -- perform actual reset of a pci slot
- * @bus: pointer to the pci bus structure corresponding
- *            to the isolated slot. A non-null value will
- *            cause all devices under the bus to be removed
- *            and then re-added.
- * @pe_dn: pointer to a "Partionable Endpoint" device node.
- *            This is the top-level structure on which pci
- *            bus resets can be performed.
- */
-
-static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
+static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus)
 {
        struct device_node *dn;
        int cnt, rc;
 
        /* pcibios will clear the counter; save the value */
-       cnt = pe_dn->eeh_freeze_count;
+       cnt = edev->freeze_count;
 
        if (bus)
                pcibios_remove_pci_devices(bus);
 
        /* Reset the pci controller. (Asserts RST#; resets config space).
         * Reconfigure bridges and devices. Don't try to bring the system
-        * up if the reset failed for some reason. */
-       rc = rtas_set_slot_reset(pe_dn);
+        * up if the reset failed for some reason.
+        */
+       rc = eeh_reset_pe(edev);
        if (rc)
                return rc;
 
-       /* Walk over all functions on this device.  */
-       dn = pe_dn->node;
-       if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+       /* Walk over all functions on this device. */
+       dn = eeh_dev_to_of_node(edev);
+       if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))
                dn = dn->parent->child;
 
        while (dn) {
-               struct pci_dn *ppe = PCI_DN(dn);
+               struct eeh_dev *pedev = of_node_to_eeh_dev(dn);
+
                /* On Power4, always true because eeh_pe_config_addr=0 */
-               if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
-                       rtas_configure_bridge(ppe);
-                       eeh_restore_bars(ppe);
+               if (edev->pe_config_addr == pedev->pe_config_addr) {
+                       eeh_ops->configure_bridge(dn);
+                       eeh_restore_bars(pedev);
                }
                dn = dn->sibling;
        }
@@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
         * potentially weird things happen.
         */
        if (bus) {
-               ssleep (5);
+               ssleep(5);
                pcibios_add_pci_devices(bus);
        }
-       pe_dn->eeh_freeze_count = cnt;
+       edev->freeze_count = cnt;
 
        return 0;
 }
@@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
  */
 #define MAX_WAIT_FOR_RECOVERY 150
 
-struct pci_dn * handle_eeh_events (struct eeh_event *event)
+/**
+ * eeh_handle_event - Reset a PCI device after hard lockup.
+ * @event: EEH event
+ *
+ * While PHB detects address or data parity errors on particular PCI
+ * slot, the associated PE will be frozen. Besides, DMA's occurring
+ * to wild addresses (which usually happen due to bugs in device
+ * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
+ * #PERR or other misc PCI-related errors also can trigger EEH errors.
+ *
+ * Recovery process consists of unplugging the device driver (which
+ * generated hotplug events to userspace), then issuing a PCI #RST to
+ * the device, then reconfiguring the PCI config space for all bridges
+ * & devices under this slot, and then finally restarting the device
+ * drivers (which cause a second set of hotplug events to go out to
+ * userspace).
+ */
+struct eeh_dev *handle_eeh_events(struct eeh_event *event)
 {
        struct device_node *frozen_dn;
-       struct pci_dn *frozen_pdn;
+       struct eeh_dev *frozen_edev;
        struct pci_bus *frozen_bus;
        int rc = 0;
        enum pci_ers_result result = PCI_ERS_RESULT_NONE;
        const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;
 
-       frozen_dn = find_device_pe(event->dn);
+       frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev));
        if (!frozen_dn) {
-
-               location = of_get_property(event->dn, "ibm,loc-code", NULL);
+               location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL);
                location = location ? location : "unknown";
                printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
                                "for location=%s pci addr=%s\n",
-                       location, eeh_pci_name(event->dev));
+                       location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev)));
                return NULL;
        }
 
@@ -350,9 +377,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
         * which was always an EADS pci bridge.  In the new style,
         * there might not be any EADS bridges, and even when there are,
         * the firmware marks them as "EEH incapable". So another
-        * two-step is needed to find the pci bus.. */
+        * two-step is needed to find the pci bus..
+        */
        if (!frozen_bus)
-               frozen_bus = pcibios_find_pci_bus (frozen_dn->parent);
+               frozen_bus = pcibios_find_pci_bus(frozen_dn->parent);
 
        if (!frozen_bus) {
                printk(KERN_ERR "EEH: Cannot find PCI bus "
@@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
                return NULL;
        }
 
-       frozen_pdn = PCI_DN(frozen_dn);
-       frozen_pdn->eeh_freeze_count++;
+       frozen_edev = of_node_to_eeh_dev(frozen_dn);
+       frozen_edev->freeze_count++;
+       pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev));
+       drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev));
 
-       pci_str = eeh_pci_name(event->dev);
-       drv_str = pcid_name(event->dev);
-       
-       if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
+       if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES)
                goto excess_failures;
 
        printk(KERN_WARNING
           "EEH: This PCI device has failed %d times in the last hour:\n",
-               frozen_pdn->eeh_freeze_count);
+               frozen_edev->freeze_count);
 
-       if (frozen_pdn->pcidev) {
-               bus_pci_str = pci_name(frozen_pdn->pcidev);
-               bus_drv_str = pcid_name(frozen_pdn->pcidev);
+       if (frozen_edev->pdev) {
+               bus_pci_str = pci_name(frozen_edev->pdev);
+               bus_drv_str = eeh_pcid_name(frozen_edev->pdev);
                printk(KERN_WARNING
                        "EEH: Bus location=%s driver=%s pci addr=%s\n",
                        location, bus_drv_str, bus_pci_str);
@@ -395,9 +422,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
        pci_walk_bus(frozen_bus, eeh_report_error, &result);
 
        /* Get the current PCI slot state. This can take a long time,
-        * sometimes over 3 seconds for certain systems. */
-       rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
-       if (rc < 0) {
+        * sometimes over 3 seconds for certain systems.
+        */
+       rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000);
+       if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
                printk(KERN_WARNING "EEH: Permanent failure\n");
                goto hard_fail;
        }
@@ -406,14 +434,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
         * don't post the error log until after all dev drivers
         * have been informed.
         */
-       eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
+       eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP);
 
        /* If all device drivers were EEH-unaware, then shut
         * down all of the device drivers, and hope they
         * go down willingly, without panicing the system.
         */
        if (result == PCI_ERS_RESULT_NONE) {
-               rc = eeh_reset_device(frozen_pdn, frozen_bus);
+               rc = eeh_reset_device(frozen_edev, frozen_bus);
                if (rc) {
                        printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
                        goto hard_fail;
@@ -422,7 +450,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
        /* If all devices reported they can proceed, then re-enable MMIO */
        if (result == PCI_ERS_RESULT_CAN_RECOVER) {
-               rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
+               rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO);
 
                if (rc < 0)
                        goto hard_fail;
@@ -436,7 +464,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
        /* If all devices reported they can proceed, then re-enable DMA */
        if (result == PCI_ERS_RESULT_CAN_RECOVER) {
-               rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
+               rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA);
 
                if (rc < 0)
                        goto hard_fail;
@@ -454,7 +482,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
        /* If any device called out for a reset, then reset the slot */
        if (result == PCI_ERS_RESULT_NEED_RESET) {
-               rc = eeh_reset_device(frozen_pdn, NULL);
+               rc = eeh_reset_device(frozen_edev, NULL);
                if (rc) {
                        printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
                        goto hard_fail;
@@ -473,7 +501,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
        /* Tell all device drivers that they can resume operations */
        pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
 
-       return frozen_pdn;
+       return frozen_edev;
        
 excess_failures:
        /*
@@ -486,7 +514,7 @@ excess_failures:
                "has failed %d times in the last hour "
                "and has been permanently disabled.\n"
                "Please try reseating this device or replacing it.\n",
-               location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
+               location, drv_str, pci_str, frozen_edev->freeze_count);
        goto perm_error;
 
 hard_fail:
@@ -497,7 +525,7 @@ hard_fail:
                location, drv_str, pci_str);
 
 perm_error:
-       eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
+       eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM);
 
        /* Notify all devices that they're about to go down. */
        pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
@@ -508,4 +536,3 @@ perm_error:
        return NULL;
 }
 
-/* ---------- end of file ---------- */
index d2383cf..4a47525 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * eeh_event.c
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -46,7 +44,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher);
 DEFINE_MUTEX(eeh_event_mutex);
 
 /**
- * eeh_event_handler - dispatch EEH events.
+ * eeh_event_handler - Dispatch EEH events.
  * @dummy - unused
  *
  * The detection of a frozen slot can occur inside an interrupt,
@@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex);
 static int eeh_event_handler(void * dummy)
 {
        unsigned long flags;
-       struct eeh_event        *event;
-       struct pci_dn *pdn;
+       struct eeh_event *event;
+       struct eeh_dev *edev;
 
-       daemonize ("eehd");
+       daemonize("eehd");
        set_current_state(TASK_INTERRUPTIBLE);
 
        spin_lock_irqsave(&eeh_eventlist_lock, flags);
@@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy)
 
        /* Serialize processing of EEH events */
        mutex_lock(&eeh_event_mutex);
-       eeh_mark_slot(event->dn, EEH_MODE_RECOVERING);
+       edev = event->edev;
+       eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING);
 
        printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n",
-              eeh_pci_name(event->dev));
+              eeh_pci_name(edev->pdev));
+
+       edev = handle_eeh_events(event);
 
-       pdn = handle_eeh_events(event);
+       eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING);
+       pci_dev_put(edev->pdev);
 
-       eeh_clear_slot(event->dn, EEH_MODE_RECOVERING);
-       pci_dev_put(event->dev);
        kfree(event);
        mutex_unlock(&eeh_event_mutex);
 
        /* If there are no new errors after an hour, clear the counter. */
-       if (pdn && pdn->eeh_freeze_count>0) {
-               msleep_interruptible (3600*1000);
-               if (pdn->eeh_freeze_count>0)
-                       pdn->eeh_freeze_count--;
+       if (edev && edev->freeze_count>0) {
+               msleep_interruptible(3600*1000);
+               if (edev->freeze_count>0)
+                       edev->freeze_count--;
+
        }
 
        return 0;
 }
 
 /**
- * eeh_thread_launcher
+ * eeh_thread_launcher - Start kernel thread to handle EEH events
  * @dummy - unused
+ *
+ * This routine is called to start the kernel thread for processing
+ * EEH event.
  */
 static void eeh_thread_launcher(struct work_struct *dummy)
 {
@@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy)
 }
 
 /**
- * eeh_send_failure_event - generate a PCI error event
- * @dev pci device
+ * eeh_send_failure_event - Generate a PCI error event
+ * @edev: EEH device
  *
  * This routine can be called within an interrupt context;
  * the actual event will be delivered in a normal context
  * (from a workqueue).
  */
-int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev)
+int eeh_send_failure_event(struct eeh_dev *edev)
 {
        unsigned long flags;
        struct eeh_event *event;
+       struct device_node *dn = eeh_dev_to_of_node(edev);
        const char *location;
 
        if (!mem_init_done) {
@@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn,
        }
        event = kmalloc(sizeof(*event), GFP_ATOMIC);
        if (event == NULL) {
-               printk (KERN_ERR "EEH: out of memory, event not handled\n");
+               printk(KERN_ERR "EEH: out of memory, event not handled\n");
                return 1;
        }
 
-       if (dev)
-               pci_dev_get(dev);
+       if (edev->pdev)
+               pci_dev_get(edev->pdev);
 
-       event->dn = dn;
-       event->dev = dev;
+       event->edev = edev;
 
        /* We may or may not be called in an interrupt context */
        spin_lock_irqsave(&eeh_eventlist_lock, flags);
@@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn,
 
        return 0;
 }
-
-/********************** END OF FILE ******************************/
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
new file mode 100644 (file)
index 0000000..8752f79
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * The file intends to implement the platform dependent EEH operations on pseries.
+ * Actually, the pseries platform is built based on RTAS heavily. That means the
+ * pseries platform dependent EEH operations will be built on RTAS calls. The functions
+ * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has
+ * been done.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011.
+ * Copyright IBM Corporation 2001, 2005, 2006
+ * Copyright Dave Engebretsen & Todd Inglett 2001
+ * Copyright Linas Vepstas 2005, 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include <asm/eeh.h>
+#include <asm/eeh_event.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/rtas.h>
+
+/* RTAS tokens */
+static int ibm_set_eeh_option;
+static int ibm_set_slot_reset;
+static int ibm_read_slot_reset_state;
+static int ibm_read_slot_reset_state2;
+static int ibm_slot_error_detail;
+static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
+static int ibm_configure_bridge;
+static int ibm_configure_pe;
+
+/*
+ * Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
+static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
+static DEFINE_SPINLOCK(slot_errbuf_lock);
+static int eeh_error_buf_size;
+
+/**
+ * pseries_eeh_init - EEH platform dependent initialization
+ *
+ * EEH platform dependent initialization on pseries.
+ */
+static int pseries_eeh_init(void)
+{
+       /* figure out EEH RTAS function call tokens */
+       ibm_set_eeh_option              = rtas_token("ibm,set-eeh-option");
+       ibm_set_slot_reset              = rtas_token("ibm,set-slot-reset");
+       ibm_read_slot_reset_state2      = rtas_token("ibm,read-slot-reset-state2");
+       ibm_read_slot_reset_state       = rtas_token("ibm,read-slot-reset-state");
+       ibm_slot_error_detail           = rtas_token("ibm,slot-error-detail");
+       ibm_get_config_addr_info2       = rtas_token("ibm,get-config-addr-info2");
+       ibm_get_config_addr_info        = rtas_token("ibm,get-config-addr-info");
+       ibm_configure_pe                = rtas_token("ibm,configure-pe");
+       ibm_configure_bridge            = rtas_token ("ibm,configure-bridge");
+
+       /* necessary sanity check */
+       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n",
+                       __func__);
+               return -EINVAL;
+       } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n",
+                       __func__);
+               return -EINVAL;
+       } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
+                  ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and "
+                       "<ibm,read-slot-reset-state> invalid\n",
+                       __func__);
+               return -EINVAL;
+       } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n",
+                       __func__);
+               return -EINVAL;
+       } else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE &&
+                  ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and "
+                       "<ibm,get-config-addr-info> invalid\n",
+                       __func__);
+               return -EINVAL;
+       } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
+                  ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: RTAS service <ibm,configure-pe> and "
+                       "<ibm,configure-bridge> invalid\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       /* Initialize error log lock and size */
+       spin_lock_init(&slot_errbuf_lock);
+       eeh_error_buf_size = rtas_token("rtas-error-log-max");
+       if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
+               pr_warning("%s: unknown EEH error log size\n",
+                       __func__);
+               eeh_error_buf_size = 1024;
+       } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
+               pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
+                       __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
+               eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
+       }
+
+       return 0;
+}
+
+/**
+ * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable
+ * @dn: device node
+ * @option: operation to be issued
+ *
+ * The function is used to control the EEH functionality globally.
+ * Currently, following options are support according to PAPR:
+ * Enable EEH, Disable EEH, Enable MMIO and Enable DMA
+ */
+static int pseries_eeh_set_option(struct device_node *dn, int option)
+{
+       int ret = 0;
+       struct eeh_dev *edev;
+       const u32 *reg;
+       int config_addr;
+
+       edev = of_node_to_eeh_dev(dn);
+
+       /*
+        * When we're enabling or disabling EEH functioality on
+        * the particular PE, the PE config address is possibly
+        * unavailable. Therefore, we have to figure it out from
+        * the FDT node.
+        */
+       switch (option) {
+       case EEH_OPT_DISABLE:
+       case EEH_OPT_ENABLE:
+               reg = of_get_property(dn, "reg", NULL);
+               config_addr = reg[0];
+               break;
+
+       case EEH_OPT_THAW_MMIO:
+       case EEH_OPT_THAW_DMA:
+               config_addr = edev->config_addr;
+               if (edev->pe_config_addr)
+                       config_addr = edev->pe_config_addr;
+               break;
+
+       default:
+               pr_err("%s: Invalid option %d\n",
+                       __func__, option);
+               return -EINVAL;
+       }
+
+       ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+                       config_addr, BUID_HI(edev->phb->buid),
+                       BUID_LO(edev->phb->buid), option);
+
+       return ret;
+}
+
+/**
+ * pseries_eeh_get_pe_addr - Retrieve PE address
+ * @dn: device node
+ *
+ * Retrieve the assocated PE address. Actually, there're 2 RTAS
+ * function calls dedicated for the purpose. We need implement
+ * it through the new function and then the old one. Besides,
+ * you should make sure the config address is figured out from
+ * FDT node before calling the function.
+ *
+ * It's notable that zero'ed return value means invalid PE config
+ * address.
+ */
+static int pseries_eeh_get_pe_addr(struct device_node *dn)
+{
+       struct eeh_dev *edev;
+       int ret = 0;
+       int rets[3];
+
+       edev = of_node_to_eeh_dev(dn);
+
+       if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
+               /*
+                * First of all, we need to make sure there has one PE
+                * associated with the device. Otherwise, PE address is
+                * meaningless.
+                */
+               ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
+                               edev->config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid), 1);
+               if (ret || (rets[0] == 0))
+                       return 0;
+
+               /* Retrieve the associated PE config address */
+               ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
+                               edev->config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid), 0);
+               if (ret) {
+                       pr_warning("%s: Failed to get PE address for %s\n",
+                               __func__, dn->full_name);
+                       return 0;
+               }
+
+               return rets[0];
+       }
+
+       if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets,
+                               edev->config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid), 0);
+               if (ret) {
+                       pr_warning("%s: Failed to get PE address for %s\n",
+                               __func__, dn->full_name);
+                       return 0;
+               }
+
+               return rets[0];
+       }
+
+       return ret;
+}
+
+/**
+ * pseries_eeh_get_state - Retrieve PE state
+ * @dn: PE associated device node
+ * @state: return value
+ *
+ * Retrieve the state of the specified PE. On RTAS compliant
+ * pseries platform, there already has one dedicated RTAS function
+ * for the purpose. It's notable that the associated PE config address
+ * might be ready when calling the function. Therefore, endeavour to
+ * use the PE config address if possible. Further more, there're 2
+ * RTAS calls for the purpose, we need to try the new one and back
+ * to the old one if the new one couldn't work properly.
+ */
+static int pseries_eeh_get_state(struct device_node *dn, int *state)
+{
+       struct eeh_dev *edev;
+       int config_addr;
+       int ret;
+       int rets[4];
+       int result;
+
+       /* Figure out PE config address if possible */
+       edev = of_node_to_eeh_dev(dn);
+       config_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               config_addr = edev->pe_config_addr;
+
+       if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets,
+                               config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid));
+       } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) {
+               /* Fake PE unavailable info */
+               rets[2] = 0;
+               ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+                               config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid));
+       } else {
+               return EEH_STATE_NOT_SUPPORT;
+       }
+
+       if (ret)
+               return ret;
+
+       /* Parse the result out */
+       result = 0;
+       if (rets[1]) {
+               switch(rets[0]) {
+               case 0:
+                       result &= ~EEH_STATE_RESET_ACTIVE;
+                       result |= EEH_STATE_MMIO_ACTIVE;
+                       result |= EEH_STATE_DMA_ACTIVE;
+                       break;
+               case 1:
+                       result |= EEH_STATE_RESET_ACTIVE;
+                       result |= EEH_STATE_MMIO_ACTIVE;
+                       result |= EEH_STATE_DMA_ACTIVE;
+                       break;
+               case 2:
+                       result &= ~EEH_STATE_RESET_ACTIVE;
+                       result &= ~EEH_STATE_MMIO_ACTIVE;
+                       result &= ~EEH_STATE_DMA_ACTIVE;
+                       break;
+               case 4:
+                       result &= ~EEH_STATE_RESET_ACTIVE;
+                       result &= ~EEH_STATE_MMIO_ACTIVE;
+                       result &= ~EEH_STATE_DMA_ACTIVE;
+                       result |= EEH_STATE_MMIO_ENABLED;
+                       break;
+               case 5:
+                       if (rets[2]) {
+                               if (state) *state = rets[2];
+                               result = EEH_STATE_UNAVAILABLE;
+                       } else {
+                               result = EEH_STATE_NOT_SUPPORT;
+                       }
+               default:
+                       result = EEH_STATE_NOT_SUPPORT;
+               }
+       } else {
+               result = EEH_STATE_NOT_SUPPORT;
+       }
+
+       return result;
+}
+
+/**
+ * pseries_eeh_reset - Reset the specified PE
+ * @dn: PE associated device node
+ * @option: reset option
+ *
+ * Reset the specified PE
+ */
+static int pseries_eeh_reset(struct device_node *dn, int option)
+{
+       struct eeh_dev *edev;
+       int config_addr;
+       int ret;
+
+       /* Figure out PE address */
+       edev = of_node_to_eeh_dev(dn);
+       config_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               config_addr = edev->pe_config_addr;
+
+       /* Reset PE through RTAS call */
+       ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
+                       config_addr, BUID_HI(edev->phb->buid),
+                       BUID_LO(edev->phb->buid), option);
+
+       /* If fundamental-reset not supported, try hot-reset */
+       if (option == EEH_RESET_FUNDAMENTAL &&
+           ret == -8) {
+               ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
+                               config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid), EEH_RESET_HOT);
+       }
+
+       return ret;
+}
+
+/**
+ * pseries_eeh_wait_state - Wait for PE state
+ * @dn: PE associated device node
+ * @max_wait: maximal period in microsecond
+ *
+ * Wait for the state of associated PE. It might take some time
+ * to retrieve the PE's state.
+ */
+static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
+{
+       int ret;
+       int mwait;
+
+       /*
+        * According to PAPR, the state of PE might be temporarily
+        * unavailable. Under the circumstance, we have to wait
+        * for indicated time determined by firmware. The maximal
+        * wait time is 5 minutes, which is acquired from the original
+        * EEH implementation. Also, the original implementation
+        * also defined the minimal wait time as 1 second.
+        */
+#define EEH_STATE_MIN_WAIT_TIME        (1000)
+#define EEH_STATE_MAX_WAIT_TIME        (300 * 1000)
+
+       while (1) {
+               ret = pseries_eeh_get_state(dn, &mwait);
+
+               /*
+                * If the PE's state is temporarily unavailable,
+                * we have to wait for the specified time. Otherwise,
+                * the PE's state will be returned immediately.
+                */
+               if (ret != EEH_STATE_UNAVAILABLE)
+                       return ret;
+
+               if (max_wait <= 0) {
+                       pr_warning("%s: Timeout when getting PE's state (%d)\n",
+                               __func__, max_wait);
+                       return EEH_STATE_NOT_SUPPORT;
+               }
+
+               if (mwait <= 0) {
+                       pr_warning("%s: Firmware returned bad wait value %d\n",
+                               __func__, mwait);
+                       mwait = EEH_STATE_MIN_WAIT_TIME;
+               } else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
+                       pr_warning("%s: Firmware returned too long wait value %d\n",
+                               __func__, mwait);
+                       mwait = EEH_STATE_MAX_WAIT_TIME;
+               }
+
+               max_wait -= mwait;
+               msleep(mwait);
+       }
+
+       return EEH_STATE_NOT_SUPPORT;
+}
+
+/**
+ * pseries_eeh_get_log - Retrieve error log
+ * @dn: device node
+ * @severity: temporary or permanent error log
+ * @drv_log: driver log to be combined with retrieved error log
+ * @len: length of driver log
+ *
+ * Retrieve the temporary or permanent error from the PE.
+ * Actually, the error will be retrieved through the dedicated
+ * RTAS call.
+ */
+static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
+{
+       struct eeh_dev *edev;
+       int config_addr;
+       unsigned long flags;
+       int ret;
+
+       edev = of_node_to_eeh_dev(dn);
+       spin_lock_irqsave(&slot_errbuf_lock, flags);
+       memset(slot_errbuf, 0, eeh_error_buf_size);
+
+       /* Figure out the PE address */
+       config_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               config_addr = edev->pe_config_addr;
+
+       ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
+                       BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid),
+                       virt_to_phys(drv_log), len,
+                       virt_to_phys(slot_errbuf), eeh_error_buf_size,
+                       severity);
+       if (!ret)
+               log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+       spin_unlock_irqrestore(&slot_errbuf_lock, flags);
+
+       return ret;
+}
+
+/**
+ * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE
+ * @dn: PE associated device node
+ *
+ * The function will be called to reconfigure the bridges included
+ * in the specified PE so that the mulfunctional PE would be recovered
+ * again.
+ */
+static int pseries_eeh_configure_bridge(struct device_node *dn)
+{
+       struct eeh_dev *edev;
+       int config_addr;
+       int ret;
+
+       /* Figure out the PE address */
+       edev = of_node_to_eeh_dev(dn);
+       config_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               config_addr = edev->pe_config_addr;
+
+       /* Use new configure-pe function, if supported */
+       if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
+                               config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid));
+       } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
+                               config_addr, BUID_HI(edev->phb->buid),
+                               BUID_LO(edev->phb->buid));
+       } else {
+               return -EFAULT;
+       }
+
+       if (ret)
+               pr_warning("%s: Unable to configure bridge %d for %s\n",
+                       __func__, ret, dn->full_name);
+
+       return ret;
+}
+
+/**
+ * pseries_eeh_read_config - Read PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to read
+ * @val: return value
+ *
+ * Read config space from the speicifed device
+ */
+static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val)
+{
+       struct pci_dn *pdn;
+
+       pdn = PCI_DN(dn);
+
+       return rtas_read_config(pdn, where, size, val);
+}
+
+/**
+ * pseries_eeh_write_config - Write PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to write
+ * @val: value to be written
+ *
+ * Write config space to the specified device
+ */
+static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val)
+{
+       struct pci_dn *pdn;
+
+       pdn = PCI_DN(dn);
+
+       return rtas_write_config(pdn, where, size, val);
+}
+
+static struct eeh_ops pseries_eeh_ops = {
+       .name                   = "pseries",
+       .init                   = pseries_eeh_init,
+       .set_option             = pseries_eeh_set_option,
+       .get_pe_addr            = pseries_eeh_get_pe_addr,
+       .get_state              = pseries_eeh_get_state,
+       .reset                  = pseries_eeh_reset,
+       .wait_state             = pseries_eeh_wait_state,
+       .get_log                = pseries_eeh_get_log,
+       .configure_bridge       = pseries_eeh_configure_bridge,
+       .read_config            = pseries_eeh_read_config,
+       .write_config           = pseries_eeh_write_config
+};
+
+/**
+ * eeh_pseries_init - Register platform dependent EEH operations
+ *
+ * EEH initialization on pseries platform. This function should be
+ * called before any EEH related functions.
+ */
+int __init eeh_pseries_init(void)
+{
+       return eeh_ops_register(&pseries_eeh_ops);
+}
index eb744ee..243b351 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/pci-bridge.h>
 
 /**
- * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic
+ * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic
  * @_name: name of file in sysfs directory
  * @_memb: name of member in struct pci_dn to access
  * @_format: printf format for display
@@ -41,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev,      \
                struct device_attribute *attr, char *buf)          \
 {                                                        \
        struct pci_dev *pdev = to_pci_dev(dev);               \
-       struct device_node *dn = pci_device_to_OF_node(pdev); \
-       struct pci_dn *pdn;                                   \
+       struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);      \
                                                              \
-       if (!dn || PCI_DN(dn) == NULL)                        \
-               return 0;                                          \
+       if (!edev)                                            \
+               return 0;                                     \
                                                              \
-       pdn = PCI_DN(dn);                                     \
-       return sprintf(buf, _format "\n", pdn->_memb);        \
+       return sprintf(buf, _format "\n", edev->_memb);       \
 }                                                        \
 static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL);
 
-
-EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x");
-EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x");
-EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x");
-EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d");
-EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d");
-EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d");
+EEH_SHOW_ATTR(eeh_mode,            mode,            "0x%x");
+EEH_SHOW_ATTR(eeh_config_addr,     config_addr,     "0x%x");
+EEH_SHOW_ATTR(eeh_pe_config_addr,  pe_config_addr,  "0x%x");
+EEH_SHOW_ATTR(eeh_check_count,     check_count,     "%d"  );
+EEH_SHOW_ATTR(eeh_freeze_count,    freeze_count,    "%d"  );
+EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d"  );
 
 void eeh_sysfs_add_device(struct pci_dev *pdev)
 {
index 7bc73af..5f3ef87 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/udbg.h>
 #include <asm/smp.h>
 #include <asm/trace.h>
+#include <asm/firmware.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
index 38d24e7..109fdb7 100644 (file)
@@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total)
        if (!dn)
                return NULL;
 
-       dn = find_device_pe(dn);
+       dn = eeh_find_device_pe(dn);
        if (!dn)
                return NULL;
 
index 55d4ec1..fbb21fc 100644 (file)
@@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 
        pci_devs_phb_init_dynamic(phb);
 
+       /* Create EEH devices for the PHB */
+       eeh_dev_phb_init_dynamic(phb);
+
        if (dn->child)
                eeh_add_device_tree_early(dn);
 
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c
deleted file mode 100644 (file)
index 6e7742d..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Hypervisor-assisted dump
- *
- * Linas Vepstas, Manish Ahuja 2008
- * Copyright 2008 IBM Corp.
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the 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/gfp.h>
-#include <linux/init.h>
-#include <linux/kobject.h>
-#include <linux/mm.h>
-#include <linux/of.h>
-#include <linux/pfn.h>
-#include <linux/swap.h>
-#include <linux/sysfs.h>
-
-#include <asm/page.h>
-#include <asm/phyp_dump.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-
-/* Variables, used to communicate data between early boot and late boot */
-static struct phyp_dump phyp_dump_vars;
-struct phyp_dump *phyp_dump_info = &phyp_dump_vars;
-
-static int ibm_configure_kernel_dump;
-/* ------------------------------------------------- */
-/* RTAS interfaces to declare the dump regions */
-
-struct dump_section {
-       u32 dump_flags;
-       u16 source_type;
-       u16 error_flags;
-       u64 source_address;
-       u64 source_length;
-       u64 length_copied;
-       u64 destination_address;
-};
-
-struct phyp_dump_header {
-       u32 version;
-       u16 num_of_sections;
-       u16 status;
-
-       u32 first_offset_section;
-       u32 dump_disk_section;
-       u64 block_num_dd;
-       u64 num_of_blocks_dd;
-       u32 offset_dd;
-       u32 maxtime_to_auto;
-       /* No dump disk path string used */
-
-       struct dump_section cpu_data;
-       struct dump_section hpte_data;
-       struct dump_section kernel_data;
-};
-
-/* The dump header *must be* in low memory, so .bss it */
-static struct phyp_dump_header phdr;
-
-#define NUM_DUMP_SECTIONS      3
-#define DUMP_HEADER_VERSION    0x1
-#define DUMP_REQUEST_FLAG      0x1
-#define DUMP_SOURCE_CPU                0x0001
-#define DUMP_SOURCE_HPTE       0x0002
-#define DUMP_SOURCE_RMO                0x0011
-#define DUMP_ERROR_FLAG                0x2000
-#define DUMP_TRIGGERED         0x4000
-#define DUMP_PERFORMED         0x8000
-
-
-/**
- * init_dump_header() - initialize the header declaring a dump
- * Returns: length of dump save area.
- *
- * When the hypervisor saves crashed state, it needs to put
- * it somewhere. The dump header tells the hypervisor where
- * the data can be saved.
- */
-static unsigned long init_dump_header(struct phyp_dump_header *ph)
-{
-       unsigned long addr_offset = 0;
-
-       /* Set up the dump header */
-       ph->version = DUMP_HEADER_VERSION;
-       ph->num_of_sections = NUM_DUMP_SECTIONS;
-       ph->status = 0;
-
-       ph->first_offset_section =
-               (u32)offsetof(struct phyp_dump_header, cpu_data);
-       ph->dump_disk_section = 0;
-       ph->block_num_dd = 0;
-       ph->num_of_blocks_dd = 0;
-       ph->offset_dd = 0;
-
-       ph->maxtime_to_auto = 0; /* disabled */
-
-       /* The first two sections are mandatory */
-       ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG;
-       ph->cpu_data.source_type = DUMP_SOURCE_CPU;
-       ph->cpu_data.source_address = 0;
-       ph->cpu_data.source_length = phyp_dump_info->cpu_state_size;
-       ph->cpu_data.destination_address = addr_offset;
-       addr_offset += phyp_dump_info->cpu_state_size;
-
-       ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG;
-       ph->hpte_data.source_type = DUMP_SOURCE_HPTE;
-       ph->hpte_data.source_address = 0;
-       ph->hpte_data.source_length = phyp_dump_info->hpte_region_size;
-       ph->hpte_data.destination_address = addr_offset;
-       addr_offset += phyp_dump_info->hpte_region_size;
-
-       /* This section describes the low kernel region */
-       ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG;
-       ph->kernel_data.source_type = DUMP_SOURCE_RMO;
-       ph->kernel_data.source_address = PHYP_DUMP_RMR_START;
-       ph->kernel_data.source_length = PHYP_DUMP_RMR_END;
-       ph->kernel_data.destination_address = addr_offset;
-       addr_offset += ph->kernel_data.source_length;
-
-       return addr_offset;
-}
-
-static void print_dump_header(const struct phyp_dump_header *ph)
-{
-#ifdef DEBUG
-       if (ph == NULL)
-               return;
-
-       printk(KERN_INFO "dump header:\n");
-       /* setup some ph->sections required */
-       printk(KERN_INFO "version = %d\n", ph->version);
-       printk(KERN_INFO "Sections = %d\n", ph->num_of_sections);
-       printk(KERN_INFO "Status = 0x%x\n", ph->status);
-
-       /* No ph->disk, so all should be set to 0 */
-       printk(KERN_INFO "Offset to first section 0x%x\n",
-               ph->first_offset_section);
-       printk(KERN_INFO "dump disk sections should be zero\n");
-       printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section);
-       printk(KERN_INFO "block num = %lld\n", ph->block_num_dd);
-       printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd);
-       printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd);
-       printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto);
-
-       /*set cpu state and hpte states as well scratch pad area */
-       printk(KERN_INFO " CPU AREA\n");
-       printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags);
-       printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type);
-       printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags);
-       printk(KERN_INFO "cpu source_address =%llx\n",
-               ph->cpu_data.source_address);
-       printk(KERN_INFO "cpu source_length =%llx\n",
-               ph->cpu_data.source_length);
-       printk(KERN_INFO "cpu length_copied =%llx\n",
-               ph->cpu_data.length_copied);
-
-       printk(KERN_INFO " HPTE AREA\n");
-       printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags);
-       printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type);
-       printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags);
-       printk(KERN_INFO "HPTE source_address =%llx\n",
-               ph->hpte_data.source_address);
-       printk(KERN_INFO "HPTE source_length =%llx\n",
-               ph->hpte_data.source_length);
-       printk(KERN_INFO "HPTE length_copied =%llx\n",
-               ph->hpte_data.length_copied);
-
-       printk(KERN_INFO " SRSD AREA\n");
-       printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags);
-       printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type);
-       printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags);
-       printk(KERN_INFO "SRSD source_address =%llx\n",
-               ph->kernel_data.source_address);
-       printk(KERN_INFO "SRSD source_length =%llx\n",
-               ph->kernel_data.source_length);
-       printk(KERN_INFO "SRSD length_copied =%llx\n",
-               ph->kernel_data.length_copied);
-#endif
-}
-
-static ssize_t show_phyp_dump_active(struct kobject *kobj,
-                       struct kobj_attribute *attr, char *buf)
-{
-
-       /* create filesystem entry so kdump is phyp-dump aware */
-       return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot);
-}
-
-static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600,
-                                       show_phyp_dump_active,
-                                       NULL);
-
-static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
-{
-       int rc;
-
-       /* Add addr value if not initialized before */
-       if (ph->cpu_data.destination_address == 0) {
-               ph->cpu_data.destination_address += addr;
-               ph->hpte_data.destination_address += addr;
-               ph->kernel_data.destination_address += addr;
-       }
-
-       /* ToDo Invalidate kdump and free memory range. */
-
-       do {
-               rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
-                               1, ph, sizeof(struct phyp_dump_header));
-       } while (rtas_busy_delay(rc));
-
-       if (rc) {
-               printk(KERN_ERR "phyp-dump: unexpected error (%d) on "
-                                               "register\n", rc);
-               print_dump_header(ph);
-               return;
-       }
-
-       rc = sysfs_create_file(kernel_kobj, &pdl.attr);
-       if (rc)
-               printk(KERN_ERR "phyp-dump: unable to create sysfs"
-                               " file (%d)\n", rc);
-}
-
-static
-void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr)
-{
-       int rc;
-
-       /* Add addr value if not initialized before */
-       if (ph->cpu_data.destination_address == 0) {
-               ph->cpu_data.destination_address += addr;
-               ph->hpte_data.destination_address += addr;
-               ph->kernel_data.destination_address += addr;
-       }
-
-       do {
-               rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
-                               2, ph, sizeof(struct phyp_dump_header));
-       } while (rtas_busy_delay(rc));
-
-       if (rc) {
-               printk(KERN_ERR "phyp-dump: unexpected error (%d) "
-                                               "on invalidate\n", rc);
-               print_dump_header(ph);
-       }
-}
-
-/* ------------------------------------------------- */
-/**
- * release_memory_range -- release memory previously memblock_reserved
- * @start_pfn: starting physical frame number
- * @nr_pages: number of pages to free.
- *
- * This routine will release memory that had been previously
- * memblock_reserved in early boot. The released memory becomes
- * available for genreal use.
- */
-static void release_memory_range(unsigned long start_pfn,
-                       unsigned long nr_pages)
-{
-       struct page *rpage;
-       unsigned long end_pfn;
-       long i;
-
-       end_pfn = start_pfn + nr_pages;
-
-       for (i = start_pfn; i <= end_pfn; i++) {
-               rpage = pfn_to_page(i);
-               if (PageReserved(rpage)) {
-                       ClearPageReserved(rpage);
-                       init_page_count(rpage);
-                       __free_page(rpage);
-                       totalram_pages++;
-               }
-       }
-}
-
-/**
- * track_freed_range -- Counts the range being freed.
- * Once the counter goes to zero, it re-registers dump for
- * future use.
- */
-static void
-track_freed_range(unsigned long addr, unsigned long length)
-{
-       static unsigned long scratch_area_size, reserved_area_size;
-
-       if (addr < phyp_dump_info->init_reserve_start)
-               return;
-
-       if ((addr >= phyp_dump_info->init_reserve_start) &&
-           (addr <= phyp_dump_info->init_reserve_start +
-            phyp_dump_info->init_reserve_size))
-               reserved_area_size += length;
-
-       if ((addr >= phyp_dump_info->reserved_scratch_addr) &&
-           (addr <= phyp_dump_info->reserved_scratch_addr +
-            phyp_dump_info->reserved_scratch_size))
-               scratch_area_size += length;
-
-       if ((reserved_area_size == phyp_dump_info->init_reserve_size) &&
-           (scratch_area_size == phyp_dump_info->reserved_scratch_size)) {
-
-               invalidate_last_dump(&phdr,
-                               phyp_dump_info->reserved_scratch_addr);
-               register_dump_area(&phdr,
-                               phyp_dump_info->reserved_scratch_addr);
-       }
-}
-
-/* ------------------------------------------------- */
-/**
- * sysfs_release_region -- sysfs interface to release memory range.
- *
- * Usage:
- *   "echo <start addr> <length> > /sys/kernel/release_region"
- *
- * Example:
- *   "echo 0x40000000 0x10000000 > /sys/kernel/release_region"
- *
- * will release 256MB starting at 1GB.
- */
-static ssize_t store_release_region(struct kobject *kobj,
-                               struct kobj_attribute *attr,
-                               const char *buf, size_t count)
-{
-       unsigned long start_addr, length, end_addr;
-       unsigned long start_pfn, nr_pages;
-       ssize_t ret;
-
-       ret = sscanf(buf, "%lx %lx", &start_addr, &length);
-       if (ret != 2)
-               return -EINVAL;
-
-       track_freed_range(start_addr, length);
-
-       /* Range-check - don't free any reserved memory that
-        * wasn't reserved for phyp-dump */
-       if (start_addr < phyp_dump_info->init_reserve_start)
-               start_addr = phyp_dump_info->init_reserve_start;
-
-       end_addr = phyp_dump_info->init_reserve_start +
-                       phyp_dump_info->init_reserve_size;
-       if (start_addr+length > end_addr)
-               length = end_addr - start_addr;
-
-       /* Release the region of memory assed in by user */
-       start_pfn = PFN_DOWN(start_addr);
-       nr_pages = PFN_DOWN(length);
-       release_memory_range(start_pfn, nr_pages);
-
-       return count;
-}
-
-static ssize_t show_release_region(struct kobject *kobj,
-                       struct kobj_attribute *attr, char *buf)
-{
-       u64 second_addr_range;
-
-       /* total reserved size - start of scratch area */
-       second_addr_range = phyp_dump_info->init_reserve_size -
-                               phyp_dump_info->reserved_scratch_size;
-       return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:"
-                           " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n",
-               phdr.cpu_data.destination_address,
-               phdr.cpu_data.length_copied,
-               phdr.hpte_data.destination_address,
-               phdr.hpte_data.length_copied,
-               phdr.kernel_data.destination_address,
-               phdr.kernel_data.length_copied,
-               phyp_dump_info->init_reserve_start,
-               second_addr_range);
-}
-
-static struct kobj_attribute rr = __ATTR(release_region, 0600,
-                                       show_release_region,
-                                       store_release_region);
-
-static int __init phyp_dump_setup(void)
-{
-       struct device_node *rtas;
-       const struct phyp_dump_header *dump_header = NULL;
-       unsigned long dump_area_start;
-       unsigned long dump_area_length;
-       int header_len = 0;
-       int rc;
-
-       /* If no memory was reserved in early boot, there is nothing to do */
-       if (phyp_dump_info->init_reserve_size == 0)
-               return 0;
-
-       /* Return if phyp dump not supported */
-       if (!phyp_dump_info->phyp_dump_configured)
-               return -ENOSYS;
-
-       /* Is there dump data waiting for us? If there isn't,
-        * then register a new dump area, and release all of
-        * the rest of the reserved ram.
-        *
-        * The /rtas/ibm,kernel-dump rtas node is present only
-        * if there is dump data waiting for us.
-        */
-       rtas = of_find_node_by_path("/rtas");
-       if (rtas) {
-               dump_header = of_get_property(rtas, "ibm,kernel-dump",
-                                               &header_len);
-               of_node_put(rtas);
-       }
-
-       ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump");
-
-       print_dump_header(dump_header);
-       dump_area_length = init_dump_header(&phdr);
-       /* align down */
-       dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK;
-
-       if (dump_header == NULL) {
-               register_dump_area(&phdr, dump_area_start);
-               return 0;
-       }
-
-       /* re-register the dump area, if old dump was invalid */
-       if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) {
-               invalidate_last_dump(&phdr, dump_area_start);
-               register_dump_area(&phdr, dump_area_start);
-               return 0;
-       }
-
-       if (dump_header) {
-               phyp_dump_info->reserved_scratch_addr =
-                               dump_header->cpu_data.destination_address;
-               phyp_dump_info->reserved_scratch_size =
-                               dump_header->cpu_data.source_length +
-                               dump_header->hpte_data.source_length +
-                               dump_header->kernel_data.source_length;
-       }
-
-       /* Should we create a dump_subsys, analogous to s390/ipl.c ? */
-       rc = sysfs_create_file(kernel_kobj, &rr.attr);
-       if (rc)
-               printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n",
-                                                                       rc);
-
-       /* ToDo: re-register the dump area, for next time. */
-       return 0;
-}
-machine_subsys_initcall(pseries, phyp_dump_setup);
-
-int __init early_init_dt_scan_phyp_dump(unsigned long node,
-               const char *uname, int depth, void *data)
-{
-       const unsigned int *sizes;
-
-       phyp_dump_info->phyp_dump_configured = 0;
-       phyp_dump_info->phyp_dump_is_active = 0;
-
-       if (depth != 1 || strcmp(uname, "rtas") != 0)
-               return 0;
-
-       if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL))
-               phyp_dump_info->phyp_dump_configured++;
-
-       if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL))
-               phyp_dump_info->phyp_dump_is_active++;
-
-       sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
-                                   NULL);
-       if (!sizes)
-               return 0;
-
-       if (sizes[0] == 1)
-               phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]);
-
-       if (sizes[3] == 2)
-               phyp_dump_info->hpte_region_size =
-                                               *((unsigned long *)&sizes[4]);
-       return 1;
-}
-
-/* Look for phyp_dump= cmdline option */
-static int __init early_phyp_dump_enabled(char *p)
-{
-       phyp_dump_info->phyp_dump_at_boot = 1;
-
-        if (!p)
-                return 0;
-
-        if (strncmp(p, "1", 1) == 0)
-               phyp_dump_info->phyp_dump_at_boot = 1;
-        else if (strncmp(p, "0", 1) == 0)
-               phyp_dump_info->phyp_dump_at_boot = 0;
-
-        return 0;
-}
-early_param("phyp_dump", early_phyp_dump_enabled);
-
-/* Look for phyp_dump_reserve_size= cmdline option */
-static int __init early_phyp_dump_reserve_size(char *p)
-{
-        if (p)
-               phyp_dump_info->reserve_bootvar = memparse(p, &p);
-
-        return 0;
-}
-early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size);
index 085fd3f..a12e95a 100644 (file)
@@ -96,6 +96,20 @@ out:
        return index;
 }
 
+static void check_and_cede_processor(void)
+{
+       /*
+        * Interrupts are soft-disabled at this point,
+        * but not hard disabled. So an interrupt might have
+        * occurred before entering NAP, and would be potentially
+        * lost (edge events, decrementer events, etc...) unless
+        * we first hard disable then check.
+        */
+       hard_irq_disable();
+       if (get_paca()->irq_happened == 0)
+               cede_processor();
+}
+
 static int dedicated_cede_loop(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
                                int index)
@@ -108,7 +122,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
 
        ppc64_runlatch_off();
        HMT_medium();
-       cede_processor();
+       check_and_cede_processor();
 
        get_lppaca()->donate_dedicated_cpu = 0;
        dev->last_residency =
@@ -132,7 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
         * processor. When returning here, external interrupts
         * are enabled.
         */
-       cede_processor();
+       check_and_cede_processor();
 
        dev->last_residency =
                (int)idle_loop_epilog(in_purr, kt_before);
index f79f127..8f137af 100644 (file)
@@ -190,9 +190,8 @@ static void __init pseries_mpic_init_IRQ(void)
        BUG_ON(openpic_addr == 0);
 
        /* Setup the openpic driver */
-       mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0,
-                         16, 250, /* isu size, irq count */
-                         " MPIC     ");
+       mpic = mpic_alloc(pSeries_mpic_node, openpic_addr,
+                       MPIC_NO_RESET, 16, 0, " MPIC     ");
        BUG_ON(mpic == NULL);
 
        /* Add ISUs */
@@ -261,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act
        switch (action) {
        case PSERIES_RECONFIG_ADD:
                pci = np->parent->data;
-               if (pci)
+               if (pci) {
                        update_dn_pci_info(np, pci->phb);
+
+                       /* Create EEH device for the OF node */
+                       eeh_dev_init(np, pci->phb);
+               }
                break;
        default:
                err = NOTIFY_DONE;
@@ -382,6 +385,7 @@ static void __init pSeries_setup_arch(void)
 
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
+       eeh_pseries_init();
        find_and_init_phbs();
        pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
        eeh_init();
index 7b4df37..a84fecf 100644 (file)
@@ -29,3 +29,7 @@ config SCOM_DEBUGFS
        bool "Expose SCOM controllers via debugfs"
        depends on PPC_SCOM
        default n
+
+config GE_FPGA
+       bool
+       default n
index 5e37b47..1bd7ecb 100644 (file)
@@ -4,6 +4,8 @@ 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)
+mpic-msgr-obj-$(CONFIG_MPIC_MSGR)      += mpic_msgr.o
+obj-$(CONFIG_MPIC)             += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
 obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o
 fsl-msi-obj-$(CONFIG_PCI_MSI)  += fsl_msi.o
 obj-$(CONFIG_PPC_MSI_BITMAP)   += msi_bitmap.o
@@ -65,3 +67,5 @@ obj-$(CONFIG_PPC_SCOM)                += scom.o
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 obj-$(CONFIG_PPC_XICS)         += xics/
+
+obj-$(CONFIG_GE_FPGA)          += ge/
index 1164158..37a6909 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of_platform.h>
index 5f88797..cedabd0 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of_platform.h>
 #include <asm/io.h>
 
@@ -200,6 +201,9 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
        {
                .compatible = "fsl,p1022-l2-cache-controller",
        },
+       {
+               .compatible = "fsl,mpc8548-l2-cache-controller",
+       },
        {},
 };
 
index 0c01deb..6e097de 100644 (file)
@@ -410,6 +410,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
 
                msi->msi_regs = ioremap(res.start, resource_size(&res));
                if (!msi->msi_regs) {
+                       err = -ENOMEM;
                        dev_err(&dev->dev, "could not map node %s\n",
                                dev->dev.of_node->full_name);
                        goto error_out;
index a4c4f4a..5b6f556 100644 (file)
@@ -66,8 +66,8 @@
                "       li %0,%3\n"                     \
                "       b 2b\n"                         \
                ".section __ex_table,\"a\"\n"           \
-               "       .align 2\n"                     \
-               "       .long 1b,3b\n"                  \
+                       PPC_LONG_ALIGN "\n"             \
+                       PPC_LONG "1b,3b\n"              \
                ".text"                                 \
                : "=r" (err), "=r" (x)                  \
                : "b" (addr), "i" (-EFAULT), "0" (err))
index 1548578..14bd522 100644 (file)
 #define DOORBELL_DSR_TE                0x00000080
 #define DOORBELL_DSR_QFI       0x00000010
 #define DOORBELL_DSR_DIQI      0x00000001
-#define DOORBELL_TID_OFFSET    0x02
-#define DOORBELL_SID_OFFSET    0x04
-#define DOORBELL_INFO_OFFSET   0x06
 
 #define DOORBELL_MESSAGE_SIZE  0x08
-#define DBELL_SID(x)           (*(u16 *)(x + DOORBELL_SID_OFFSET))
-#define DBELL_TID(x)           (*(u16 *)(x + DOORBELL_TID_OFFSET))
-#define DBELL_INF(x)           (*(u16 *)(x + DOORBELL_INFO_OFFSET))
 
 struct rio_msg_regs {
        u32 omr;
@@ -193,6 +187,13 @@ struct fsl_rmu {
        int rxirq;
 };
 
+struct rio_dbell_msg {
+       u16 pad1;
+       u16 tid;
+       u16 sid;
+       u16 info;
+};
+
 /**
  * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
  * @irq: Linux interrupt number
@@ -311,8 +312,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance)
 
        /* XXX Need to check/dispatch until queue empty */
        if (dsr & DOORBELL_DSR_DIQI) {
-               u32 dmsg =
-                       (u32) fsl_dbell->dbell_ring.virt +
+               struct rio_dbell_msg *dmsg =
+                       fsl_dbell->dbell_ring.virt +
                        (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff);
                struct rio_dbell *dbell;
                int found = 0;
@@ -320,25 +321,25 @@ fsl_rio_dbell_handler(int irq, void *dev_instance)
                pr_debug
                        ("RIO: processing doorbell,"
                        " sid %2.2x tid %2.2x info %4.4x\n",
-                       DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+                       dmsg->sid, dmsg->tid, dmsg->info);
 
                for (i = 0; i < MAX_PORT_NUM; i++) {
                        if (fsl_dbell->mport[i]) {
                                list_for_each_entry(dbell,
                                        &fsl_dbell->mport[i]->dbells, node) {
                                        if ((dbell->res->start
-                                               <= DBELL_INF(dmsg))
+                                               <= dmsg->info)
                                                && (dbell->res->end
-                                               >= DBELL_INF(dmsg))) {
+                                               >= dmsg->info)) {
                                                found = 1;
                                                break;
                                        }
                                }
                                if (found && dbell->dinb) {
                                        dbell->dinb(fsl_dbell->mport[i],
-                                               dbell->dev_id, DBELL_SID(dmsg),
-                                               DBELL_TID(dmsg),
-                                               DBELL_INF(dmsg));
+                                               dbell->dev_id, dmsg->sid,
+                                               dmsg->tid,
+                                               dmsg->info);
                                        break;
                                }
                        }
@@ -348,8 +349,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance)
                        pr_debug
                                ("RIO: spurious doorbell,"
                                " sid %2.2x tid %2.2x info %4.4x\n",
-                               DBELL_SID(dmsg), DBELL_TID(dmsg),
-                               DBELL_INF(dmsg));
+                               dmsg->sid, dmsg->tid,
+                               dmsg->info);
                }
                setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
                out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
@@ -657,7 +658,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
        int ret = 0;
 
        pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
-                "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
+                "%p len %8.8zx\n", rdev->destid, mbox, buffer, len);
        if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
                ret = -EINVAL;
                goto out;
@@ -972,7 +973,8 @@ out:
 void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
 {
        struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
-       u32 phys_buf, virt_buf;
+       u32 phys_buf;
+       void *virt_buf;
        void *buf = NULL;
        int buf_idx;
 
@@ -982,7 +984,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
        if (phys_buf == in_be32(&rmu->msg_regs->ifqepar))
                goto out2;
 
-       virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf
+       virt_buf = rmu->msg_rx_ring.virt + (phys_buf
                                                - rmu->msg_rx_ring.phys);
        buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
        buf = rmu->msg_rx_ring.virt_buffer[buf_idx];
@@ -994,7 +996,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
        }
 
        /* Copy max message size, caller is expected to allocate that big */
-       memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+       memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE);
 
        /* Clear the available buffer */
        rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL;
diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile
new file mode 100644 (file)
index 0000000..8731ffc
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_GE_FPGA)          += ge_pic.o
diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c
new file mode 100644 (file)
index 0000000..2bcb78b
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Interrupt handling for GE FPGA based PIC
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ *
+ * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#include "ge_pic.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+#define GEF_PIC_NUM_IRQS       32
+
+/* Interrupt Controller Interface Registers */
+#define GEF_PIC_INTR_STATUS    0x0000
+
+#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
+#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
+#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
+
+#define GEF_PIC_MCP_MASK(cpu)  (0x0018 + (0x4 * cpu))
+#define GEF_PIC_CPU0_MCP_MASK  GEF_PIC_MCP_MASK(0)
+#define GEF_PIC_CPU1_MCP_MASK  GEF_PIC_MCP_MASK(1)
+
+
+static DEFINE_RAW_SPINLOCK(gef_pic_lock);
+
+static void __iomem *gef_pic_irq_reg_base;
+static struct irq_domain *gef_pic_irq_host;
+static int gef_pic_cascade_irq;
+
+/*
+ * Interrupt Controller Handling
+ *
+ * The interrupt controller handles interrupts for most on board interrupts,
+ * apart from PCI interrupts. For example on SBC610:
+ *
+ * 17:31 RO Reserved
+ * 16    RO PCI Express Doorbell 3 Status
+ * 15    RO PCI Express Doorbell 2 Status
+ * 14    RO PCI Express Doorbell 1 Status
+ * 13    RO PCI Express Doorbell 0 Status
+ * 12    RO Real Time Clock Interrupt Status
+ * 11    RO Temperature Interrupt Status
+ * 10    RO Temperature Critical Interrupt Status
+ * 9     RO Ethernet PHY1 Interrupt Status
+ * 8     RO Ethernet PHY3 Interrupt Status
+ * 7     RO PEX8548 Interrupt Status
+ * 6     RO Reserved
+ * 5     RO Watchdog 0 Interrupt Status
+ * 4     RO Watchdog 1 Interrupt Status
+ * 3     RO AXIS Message FIFO A Interrupt Status
+ * 2     RO AXIS Message FIFO B Interrupt Status
+ * 1     RO AXIS Message FIFO C Interrupt Status
+ * 0     RO AXIS Message FIFO D Interrupt Status
+ *
+ * Interrupts can be forwarded to one of two output lines. Nothing
+ * clever is done, so if the masks are incorrectly set, a single input
+ * interrupt could generate interrupts on both output lines!
+ *
+ * The dual lines are there to allow the chained interrupts to be easily
+ * passed into two different cores. We currently do not use this functionality
+ * in this driver.
+ *
+ * Controller can also be configured to generate Machine checks (MCP), again on
+ * two lines, to be attached to two different cores. It is suggested that these
+ * should be masked out.
+ */
+
+void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned int cascade_irq;
+
+       /*
+        * See if we actually have an interrupt, call generic handling code if
+        * we do.
+        */
+       cascade_irq = gef_pic_get_irq();
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       chip->irq_eoi(&desc->irq_data);
+}
+
+static void gef_pic_mask(struct irq_data *d)
+{
+       unsigned long flags;
+       unsigned int hwirq = irqd_to_hwirq(d);
+       u32 mask;
+
+       raw_spin_lock_irqsave(&gef_pic_lock, flags);
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+       mask &= ~(1 << hwirq);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static void gef_pic_mask_ack(struct irq_data *d)
+{
+       /* Don't think we actually have to do anything to ack an interrupt,
+        * we just need to clear down the devices interrupt and it will go away
+        */
+       gef_pic_mask(d);
+}
+
+static void gef_pic_unmask(struct irq_data *d)
+{
+       unsigned long flags;
+       unsigned int hwirq = irqd_to_hwirq(d);
+       u32 mask;
+
+       raw_spin_lock_irqsave(&gef_pic_lock, flags);
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+       mask |= (1 << hwirq);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static struct irq_chip gef_pic_chip = {
+       .name           = "gefp",
+       .irq_mask       = gef_pic_mask,
+       .irq_mask_ack   = gef_pic_mask_ack,
+       .irq_unmask     = gef_pic_unmask,
+};
+
+
+/* When an interrupt is being configured, this call allows some flexibilty
+ * in deciding which irq_chip structure is used
+ */
+static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
+                         irq_hw_number_t hwirq)
+{
+       /* All interrupts are LEVEL sensitive */
+       irq_set_status_flags(virq, IRQ_LEVEL);
+       irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
+
+       return 0;
+}
+
+static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
+                           const u32 *intspec, unsigned int intsize,
+                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+
+       *out_hwirq = intspec[0];
+       if (intsize > 1)
+               *out_flags = intspec[1];
+       else
+               *out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+       return 0;
+}
+
+static const struct irq_domain_ops gef_pic_host_ops = {
+       .map    = gef_pic_host_map,
+       .xlate  = gef_pic_host_xlate,
+};
+
+
+/*
+ * Initialisation of PIC, this should be called in BSP
+ */
+void __init gef_pic_init(struct device_node *np)
+{
+       unsigned long flags;
+
+       /* Map the devices registers into memory */
+       gef_pic_irq_reg_base = of_iomap(np, 0);
+
+       raw_spin_lock_irqsave(&gef_pic_lock, flags);
+
+       /* Initialise everything as masked. */
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
+
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
+       out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
+
+       raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
+
+       /* Map controller */
+       gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
+       if (gef_pic_cascade_irq == NO_IRQ) {
+               printk(KERN_ERR "SBC610: failed to map cascade interrupt");
+               return;
+       }
+
+       /* Setup an irq_domain structure */
+       gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
+                                         &gef_pic_host_ops, NULL);
+       if (gef_pic_irq_host == NULL)
+               return;
+
+       /* Chain with parent controller */
+       irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
+}
+
+/*
+ * This is called when we receive an interrupt with apparently comes from this
+ * chip - check, returning the highest interrupt generated or return NO_IRQ
+ */
+unsigned int gef_pic_get_irq(void)
+{
+       u32 cause, mask, active;
+       unsigned int virq = NO_IRQ;
+       int hwirq;
+
+       cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
+
+       mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+
+       active = cause & mask;
+
+       if (active) {
+               for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
+                       if (active & (0x1 << hwirq))
+                               break;
+               }
+               virq = irq_linear_revmap(gef_pic_irq_host,
+                       (irq_hw_number_t)hwirq);
+       }
+
+       return virq;
+}
+
diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h
new file mode 100644 (file)
index 0000000..6149916
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __GEF_PIC_H__
+#define __GEF_PIC_H__
+
+#include <linux/init.h>
+
+void gef_pic_cascade(unsigned int, struct irq_desc *);
+unsigned int gef_pic_get_irq(void);
+void gef_pic_init(struct device_node *);
+
+#endif /* __GEF_PIC_H__ */
+
index c83a512..9ac71eb 100644 (file)
@@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
        DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
            mpic, d->irq, src, flow_type);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return -EINVAL;
 
        if (flow_type == IRQ_TYPE_NONE)
@@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
        DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
            mpic, virq, src, vector);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return;
 
        vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
@@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid)
        DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
            mpic, virq, src, cpuid);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return;
 
        mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
@@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
                return 0;
        }
 
-       if (hw >= mpic->irq_count)
+       if (hw >= mpic->num_sources)
                return -EINVAL;
 
        mpic_msi_reserve_hwirq(mpic, hw);
@@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        u32 greg_feature;
        const char *vers;
        const u32 *psrc;
+       u32 last_irq;
 
        /* Default MPIC search parameters */
        static const struct of_device_id __initconst mpic_device_id[] = {
@@ -1182,6 +1183,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
                }
        }
 
+       /* Read extra device-tree properties into the flags variable */
+       if (of_get_property(node, "big-endian", NULL))
+               flags |= MPIC_BIG_ENDIAN;
+       if (of_get_property(node, "pic-no-reset", NULL))
+               flags |= MPIC_NO_RESET;
+       if (of_get_property(node, "single-cpu-affinity", NULL))
+               flags |= MPIC_SINGLE_DEST_CPU;
+       if (of_device_is_compatible(node, "fsl,mpic"))
+               flags |= MPIC_FSL;
+
        mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
        if (mpic == NULL)
                goto err_of_node_put;
@@ -1189,15 +1200,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->name = name;
        mpic->node = node;
        mpic->paddr = phys_addr;
+       mpic->flags = flags;
 
        mpic->hc_irq = mpic_irq_chip;
        mpic->hc_irq.name = name;
-       if (!(flags & MPIC_SECONDARY))
+       if (!(mpic->flags & MPIC_SECONDARY))
                mpic->hc_irq.irq_set_affinity = mpic_set_affinity;
 #ifdef CONFIG_MPIC_U3_HT_IRQS
        mpic->hc_ht_irq = mpic_irq_ht_chip;
        mpic->hc_ht_irq.name = name;
-       if (!(flags & MPIC_SECONDARY))
+       if (!(mpic->flags & MPIC_SECONDARY))
                mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
@@ -1209,12 +1221,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->hc_tm = mpic_tm_chip;
        mpic->hc_tm.name = name;
 
-       mpic->flags = flags;
-       mpic->isu_size = isu_size;
-       mpic->irq_count = irq_count;
        mpic->num_sources = 0; /* so far */
 
-       if (flags & MPIC_LARGE_VECTORS)
+       if (mpic->flags & MPIC_LARGE_VECTORS)
                intvec_top = 2047;
        else
                intvec_top = 255;
@@ -1233,12 +1242,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->ipi_vecs[3]   = intvec_top - 1;
        mpic->spurious_vec  = intvec_top;
 
-       /* Check for "big-endian" in device-tree */
-       if (of_get_property(mpic->node, "big-endian", NULL) != NULL)
-               mpic->flags |= MPIC_BIG_ENDIAN;
-       if (of_device_is_compatible(mpic->node, "fsl,mpic"))
-               mpic->flags |= MPIC_FSL;
-
        /* Look for protected sources */
        psrc = of_get_property(mpic->node, "protected-sources", &psize);
        if (psrc) {
@@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
 #ifdef CONFIG_MPIC_WEIRD
-       mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
+       mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)];
 #endif
 
        /* default register type */
-       if (flags & MPIC_BIG_ENDIAN)
+       if (mpic->flags & MPIC_BIG_ENDIAN)
                mpic->reg_type = mpic_access_mmio_be;
        else
                mpic->reg_type = mpic_access_mmio_le;
@@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node,
         * only if the kernel includes DCR support.
         */
 #ifdef CONFIG_PPC_DCR
-       if (flags & MPIC_USES_DCR)
+       if (mpic->flags & MPIC_USES_DCR)
                mpic->reg_type = mpic_access_dcr;
 #else
-       BUG_ON(flags & MPIC_USES_DCR);
+       BUG_ON(mpic->flags & MPIC_USES_DCR);
 #endif
 
        /* Map the global registers */
@@ -1283,10 +1286,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        /* When using a device-node, reset requests are only honored if the MPIC
         * is allowed to reset.
         */
-       if (of_get_property(mpic->node, "pic-no-reset", NULL))
-               mpic->flags |= MPIC_NO_RESET;
-
-       if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+       if (!(mpic->flags & MPIC_NO_RESET)) {
                printk(KERN_DEBUG "mpic: Resetting\n");
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
@@ -1297,30 +1297,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
        /* CoreInt */
-       if (flags & MPIC_ENABLE_COREINT)
+       if (mpic->flags & MPIC_ENABLE_COREINT)
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
                           | MPIC_GREG_GCONF_COREINT);
 
-       if (flags & MPIC_ENABLE_MCK)
+       if (mpic->flags & MPIC_ENABLE_MCK)
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
                           | MPIC_GREG_GCONF_MCK);
 
-       /*
-        * Read feature register.  For non-ISU MPICs, num sources as well. On
-        * ISU MPICs, sources are counted as ISUs are added
-        */
-       greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
-       if (isu_size == 0) {
-               if (flags & MPIC_BROKEN_FRR_NIRQS)
-                       mpic->num_sources = mpic->irq_count;
-               else
-                       mpic->num_sources =
-                               ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
-                                >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
-       }
-
        /*
         * The MPIC driver will crash if there are more cores than we
         * can initialize, so we may as well catch that problem here.
@@ -1336,17 +1322,41 @@ struct mpic * __init mpic_alloc(struct device_node *node,
                         0x1000);
        }
 
+       /*
+        * Read feature register.  For non-ISU MPICs, num sources as well. On
+        * ISU MPICs, sources are counted as ISUs are added
+        */
+       greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
+
+       /*
+        * By default, the last source number comes from the MPIC, but the
+        * device-tree and board support code can override it on buggy hw.
+        * If we get passed an isu_size (multi-isu MPIC) then we use that
+        * as a default instead of the value read from the HW.
+        */
+       last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+                               >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT;    
+       if (isu_size)
+               last_irq = isu_size  * MPIC_MAX_ISU - 1;
+       of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq);
+       if (irq_count)
+               last_irq = irq_count - 1;
+
        /* Initialize main ISU if none provided */
-       if (mpic->isu_size == 0) {
-               mpic->isu_size = mpic->num_sources;
+       if (!isu_size) {
+               isu_size = last_irq + 1;
+               mpic->num_sources = isu_size;
                mpic_map(mpic, mpic->paddr, &mpic->isus[0],
-                        MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+                               MPIC_INFO(IRQ_BASE),
+                               MPIC_INFO(IRQ_STRIDE) * isu_size);
        }
+
+       mpic->isu_size = isu_size;
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
        mpic->isu_mask = (1 << mpic->isu_shift) - 1;
 
        mpic->irqhost = irq_domain_add_linear(mpic->node,
-                                      isu_size ? isu_size : mpic->num_sources,
+                                      last_irq + 1,
                                       &mpic_host_ops, mpic);
 
        /*
@@ -1380,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->next = mpics;
        mpics = mpic;
 
-       if (!(flags & MPIC_SECONDARY)) {
+       if (!(mpic->flags & MPIC_SECONDARY)) {
                mpic_primary = mpic;
                irq_set_default_host(mpic->irqhost);
        }
@@ -1447,10 +1457,6 @@ void __init mpic_init(struct mpic *mpic)
                               (mpic->ipi_vecs[0] + i));
        }
 
-       /* Initialize interrupt sources */
-       if (mpic->irq_count == 0)
-               mpic->irq_count = mpic->num_sources;
-
        /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
        if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) {
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c
new file mode 100644 (file)
index 0000000..6e7fa38
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
+ *
+ * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
+ * Mingkai Hu from 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/of_platform.h>
+#include <linux/errno.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <asm/mpic_msgr.h>
+
+#define MPIC_MSGR_REGISTERS_PER_BLOCK  4
+#define MPIC_MSGR_STRIDE               0x10
+#define MPIC_MSGR_MER_OFFSET           0x100
+#define MSGR_INUSE                     0
+#define MSGR_FREE                      1
+
+static struct mpic_msgr **mpic_msgrs;
+static unsigned int mpic_msgr_count;
+
+static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value)
+{
+       out_be32(msgr->mer, value);
+}
+
+static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr)
+{
+       return in_be32(msgr->mer);
+}
+
+static inline void _mpic_msgr_disable(struct mpic_msgr *msgr)
+{
+       u32 mer = _mpic_msgr_mer_read(msgr);
+
+       _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num));
+}
+
+struct mpic_msgr *mpic_msgr_get(unsigned int reg_num)
+{
+       unsigned long flags;
+       struct mpic_msgr *msgr;
+
+       /* Assume busy until proven otherwise.  */
+       msgr = ERR_PTR(-EBUSY);
+
+       if (reg_num >= mpic_msgr_count)
+               return ERR_PTR(-ENODEV);
+
+       raw_spin_lock_irqsave(&msgr->lock, flags);
+       if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) {
+               msgr = mpic_msgrs[reg_num];
+               msgr->in_use = MSGR_INUSE;
+       }
+       raw_spin_unlock_irqrestore(&msgr->lock, flags);
+
+       return msgr;
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_get);
+
+void mpic_msgr_put(struct mpic_msgr *msgr)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&msgr->lock, flags);
+       msgr->in_use = MSGR_FREE;
+       _mpic_msgr_disable(msgr);
+       raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_put);
+
+void mpic_msgr_enable(struct mpic_msgr *msgr)
+{
+       unsigned long flags;
+       u32 mer;
+
+       raw_spin_lock_irqsave(&msgr->lock, flags);
+       mer = _mpic_msgr_mer_read(msgr);
+       _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num));
+       raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_enable);
+
+void mpic_msgr_disable(struct mpic_msgr *msgr)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&msgr->lock, flags);
+       _mpic_msgr_disable(msgr);
+       raw_spin_unlock_irqrestore(&msgr->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mpic_msgr_disable);
+
+/* The following three functions are used to compute the order and number of
+ * the message register blocks.  They are clearly very inefficent.  However,
+ * they are called *only* a few times during device initialization.
+ */
+static unsigned int mpic_msgr_number_of_blocks(void)
+{
+       unsigned int count;
+       struct device_node *aliases;
+
+       count = 0;
+       aliases = of_find_node_by_name(NULL, "aliases");
+
+       if (aliases) {
+               char buf[32];
+
+               for (;;) {
+                       snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
+                       if (!of_find_property(aliases, buf, NULL))
+                               break;
+
+                       count += 1;
+               }
+       }
+
+       return count;
+}
+
+static unsigned int mpic_msgr_number_of_registers(void)
+{
+       return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK;
+}
+
+static int mpic_msgr_block_number(struct device_node *node)
+{
+       struct device_node *aliases;
+       unsigned int index, number_of_blocks;
+       char buf[64];
+
+       number_of_blocks = mpic_msgr_number_of_blocks();
+       aliases = of_find_node_by_name(NULL, "aliases");
+       if (!aliases)
+               return -1;
+
+       for (index = 0; index < number_of_blocks; ++index) {
+               struct property *prop;
+
+               snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
+               prop = of_find_property(aliases, buf, NULL);
+               if (node == of_find_node_by_path(prop->value))
+                       break;
+       }
+
+       return index == number_of_blocks ? -1 : index;
+}
+
+/* The probe function for a single message register block.
+ */
+static __devinit int mpic_msgr_probe(struct platform_device *dev)
+{
+       void __iomem *msgr_block_addr;
+       int block_number;
+       struct resource rsrc;
+       unsigned int i;
+       unsigned int irq_index;
+       struct device_node *np = dev->dev.of_node;
+       unsigned int receive_mask;
+       const unsigned int *prop;
+
+       if (!np) {
+               dev_err(&dev->dev, "Device OF-Node is NULL");
+               return -EFAULT;
+       }
+
+       /* Allocate the message register array upon the first device
+        * registered.
+        */
+       if (!mpic_msgrs) {
+               mpic_msgr_count = mpic_msgr_number_of_registers();
+               dev_info(&dev->dev, "Found %d message registers\n",
+                               mpic_msgr_count);
+
+               mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count,
+                                                        GFP_KERNEL);
+               if (!mpic_msgrs) {
+                       dev_err(&dev->dev,
+                               "No memory for message register blocks\n");
+                       return -ENOMEM;
+               }
+       }
+       dev_info(&dev->dev, "Of-device full name %s\n", np->full_name);
+
+       /* IO map the message register block. */
+       of_address_to_resource(np, 0, &rsrc);
+       msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start);
+       if (!msgr_block_addr) {
+               dev_err(&dev->dev, "Failed to iomap MPIC message registers");
+               return -EFAULT;
+       }
+
+       /* Ensure the block has a defined order. */
+       block_number = mpic_msgr_block_number(np);
+       if (block_number < 0) {
+               dev_err(&dev->dev,
+                       "Failed to find message register block alias\n");
+               return -ENODEV;
+       }
+       dev_info(&dev->dev, "Setting up message register block %d\n",
+                       block_number);
+
+       /* Grab the receive mask which specifies what registers can receive
+        * interrupts.
+        */
+       prop = of_get_property(np, "mpic-msgr-receive-mask", NULL);
+       receive_mask = (prop) ? *prop : 0xF;
+
+       /* Build up the appropriate message register data structures. */
+       for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) {
+               struct mpic_msgr *msgr;
+               unsigned int reg_number;
+
+               msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL);
+               if (!msgr) {
+                       dev_err(&dev->dev, "No memory for message register\n");
+                       return -ENOMEM;
+               }
+
+               reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
+               msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
+               msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET;
+               msgr->in_use = MSGR_FREE;
+               msgr->num = i;
+               raw_spin_lock_init(&msgr->lock);
+
+               if (receive_mask & (1 << i)) {
+                       struct resource irq;
+
+                       if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) {
+                               dev_err(&dev->dev,
+                                               "Missing interrupt specifier");
+                               kfree(msgr);
+                               return -EFAULT;
+                       }
+                       msgr->irq = irq.start;
+                       irq_index += 1;
+               } else {
+                       msgr->irq = NO_IRQ;
+               }
+
+               mpic_msgrs[reg_number] = msgr;
+               mpic_msgr_disable(msgr);
+               dev_info(&dev->dev, "Register %d initialized: irq %d\n",
+                               reg_number, msgr->irq);
+
+       }
+
+       return 0;
+}
+
+static const struct of_device_id mpic_msgr_ids[] = {
+       {
+               .compatible = "fsl,mpic-v3.1-msgr",
+               .data = NULL,
+       },
+       {}
+};
+
+static struct platform_driver mpic_msgr_driver = {
+       .driver = {
+               .name = "mpic-msgr",
+               .owner = THIS_MODULE,
+               .of_match_table = mpic_msgr_ids,
+       },
+       .probe = mpic_msgr_probe,
+};
+
+static __init int mpic_msgr_init(void)
+{
+       return platform_driver_register(&mpic_msgr_driver);
+}
+subsys_initcall(mpic_msgr_init);
index 0622aa9..bbf342c 100644 (file)
@@ -54,7 +54,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
        for (i = 100; i < 105; i++)
                msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
-       for (i = 124; i < mpic->irq_count; i++)
+       for (i = 124; i < mpic->num_sources; i++)
                msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
 
@@ -83,7 +83,7 @@ int mpic_msi_init_allocator(struct mpic *mpic)
 {
        int rc;
 
-       rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
+       rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources,
                              mpic->irqhost->of_node);
        if (rc)
                return rc;
index 4f05f75..56e8b3c 100644 (file)
@@ -1050,6 +1050,74 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
        .check_link     = ppc4xx_pciex_check_link_sdr,
 };
 
+static int __init apm821xx_pciex_core_init(struct device_node *np)
+{
+       /* Return the number of pcie port */
+       return 1;
+}
+
+static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+       u32 val;
+
+       /*
+        * Do a software reset on PCIe ports.
+        * This code is to fix the issue that pci drivers doesn't re-assign
+        * bus number for PCIE devices after Uboot
+        * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
+        * PT quad port, SAS LSI 1064E)
+        */
+
+       mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
+       mdelay(10);
+
+       if (port->endpoint)
+               val = PTYPE_LEGACY_ENDPOINT << 20;
+       else
+               val = PTYPE_ROOT_PORT << 20;
+
+       val |= LNKW_X1 << 12;
+
+       mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
+       mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
+       mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
+
+       mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
+       mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
+       mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
+
+       mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
+       mdelay(50);
+       mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
+
+       mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+               mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
+               (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
+
+       /* Poll for PHY reset */
+       val = PESDR0_460EX_RSTSTA - port->sdr_base;
+       if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) {
+               printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__);
+               return -EBUSY;
+       } else {
+               mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+                       (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
+                       ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
+                       PESDRx_RCSSET_RSTPYN);
+
+               port->has_ibpre = 1;
+               return 0;
+       }
+}
+
+static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = {
+       .want_sdr   = true,
+       .core_init      = apm821xx_pciex_core_init,
+       .port_init_hw   = apm821xx_pciex_init_port_hw,
+       .setup_utl      = ppc460ex_pciex_init_utl,
+       .check_link = ppc4xx_pciex_check_link_sdr,
+};
+
 static int __init ppc460sx_pciex_core_init(struct device_node *np)
 {
        /* HSS drive amplitude */
@@ -1362,6 +1430,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
                ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
        if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
                ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
+       if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx"))
+               ppc4xx_pciex_hwops = &apm821xx_pcie_hwops;
 #endif /* CONFIG_44x    */
 #ifdef CONFIG_40x
        if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
index cb95eea..68a9cbb 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/irq_regs.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
-#include <asm/firmware.h>
 #include <asm/setjmp.h>
 #include <asm/reg.h>
 
@@ -1437,7 +1436,8 @@ static void excprint(struct pt_regs *fp)
 
        printf("  current = 0x%lx\n", current);
 #ifdef CONFIG_PPC64
-       printf("  paca    = 0x%lx\n", get_paca());
+       printf("  paca    = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
+              local_paca, local_paca->soft_enabled, local_paca->irq_happened);
 #endif
        if (current) {
                printf("    pid   = %ld, comm = %s\n",
@@ -1634,25 +1634,6 @@ static void super_regs(void)
                       mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
                printf("sp   = "REG"  sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
                printf("toc  = "REG"  dar  = "REG"\n", toc, mfspr(SPRN_DAR));
-#ifdef CONFIG_PPC_ISERIES
-               if (firmware_has_feature(FW_FEATURE_ISERIES)) {
-                       struct paca_struct *ptrPaca;
-                       struct lppaca *ptrLpPaca;
-
-                       /* Dump out relevant Paca data areas. */
-                       printf("Paca: \n");
-                       ptrPaca = get_paca();
-
-                       printf("  Local Processor Control Area (LpPaca): \n");
-                       ptrLpPaca = ptrPaca->lppaca_ptr;
-                       printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n",
-                              ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
-                       printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n",
-                              ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
-                       printf("    Saved Gpr5=%.16lx \n",
-                               ptrLpPaca->gpr5_dword.saved_gpr5);
-               }
-#endif
 
                return;
        }
@@ -2644,7 +2625,7 @@ static void dump_slb(void)
 static void dump_stab(void)
 {
        int i;
-       unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
+       unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
 
        printf("Segment table contents of cpu %x\n", smp_processor_id());
 
@@ -2855,10 +2836,6 @@ static void dump_tlb_book3e(void)
 
 static void xmon_init(int enable)
 {
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return;
-#endif
        if (enable) {
                __debugger = xmon;
                __debugger_ipi = xmon_ipi;
@@ -2895,10 +2872,6 @@ static struct sysrq_key_op sysrq_xmon_op = {
 
 static int __init setup_xmon_sysrq(void)
 {
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return 0;
-#endif
        register_sysrq_key('x', &sysrq_xmon_op);
        return 0;
 }
index 8a2a887..6a2cb56 100644 (file)
@@ -293,11 +293,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        root_inode->i_op = &simple_dir_inode_operations;
        root_inode->i_fop = &simple_dir_operations;
-       sb->s_root = root_dentry = d_alloc_root(root_inode);
-       if (!root_dentry) {
-               iput(root_inode);
+       sb->s_root = root_dentry = d_make_root(root_inode);
+       if (!root_dentry)
                return -ENOMEM;
-       }
        if (MACHINE_IS_VM)
                rc = hypfs_vm_create_files(sb, root_dentry);
        else
index 30509b9..53e8b49 100644 (file)
@@ -12,7 +12,7 @@
 typedef struct mm_context {
        struct mm_id id;
        struct uml_arch_mm_context arch;
-       struct page **stub_pages;
+       struct page *stub_pages[2];
 } mm_context_t;
 
 extern void __switch_mm(struct mm_id * mm_idp);
index 591b3d8..aa4a743 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/sched.h>
 #include <asm/mmu.h>
 
-extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+extern void uml_setup_stubs(struct mm_struct *mm);
 extern void arch_exit_mmap(struct mm_struct *mm);
 
 #define deactivate_mm(tsk,mm)  do { } while (0)
@@ -23,7 +23,9 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
         * when the new ->mm is used for the first time.
         */
        __switch_mm(&new->context.id);
-       arch_dup_mmap(old, new);
+       down_write(&new->mmap_sem);
+       uml_setup_stubs(new);
+       up_write(&new->mmap_sem);
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
@@ -39,6 +41,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        }
 }
 
+static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+       uml_setup_stubs(mm);
+}
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, 
                                  struct task_struct *tsk)
 {
index 1aee587..4947b31 100644 (file)
@@ -92,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
                goto out_free;
        }
 
-       to_mm->stub_pages = NULL;
-
        return 0;
 
  out_free:
@@ -103,7 +101,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
        return ret;
 }
 
-void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+void uml_setup_stubs(struct mm_struct *mm)
 {
        struct page **pages;
        int err, ret;
@@ -120,29 +118,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
        if (ret)
                goto out;
 
-       pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL);
-       if (pages == NULL) {
-               printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page "
-                      "pointers\n");
-               goto out;
-       }
-
-       pages[0] = virt_to_page(&__syscall_stub_start);
-       pages[1] = virt_to_page(mm->context.id.stack);
-       mm->context.stub_pages = pages;
+       mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start);
+       mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
 
        /* dup_mmap already holds mmap_sem */
        err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
                                      VM_READ | VM_MAYREAD | VM_EXEC |
-                                     VM_MAYEXEC | VM_DONTCOPY, pages);
+                                     VM_MAYEXEC | VM_DONTCOPY,
+                                     mm->context.stub_pages);
        if (err) {
                printk(KERN_ERR "install_special_mapping returned %d\n", err);
-               goto out_free;
+               goto out;
        }
        return;
 
-out_free:
-       kfree(pages);
 out:
        force_sigsegv(SIGSEGV, current);
 }
@@ -151,8 +140,6 @@ void arch_exit_mmap(struct mm_struct *mm)
 {
        pte_t *pte;
 
-       if (mm->context.stub_pages != NULL)
-               kfree(mm->context.stub_pages);
        pte = virt_to_pte(mm, STUB_CODE);
        if (pte != NULL)
                pte_clear(mm, STUB_CODE, pte);
index 2b0b963..e191ac0 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
 obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
+obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
@@ -25,6 +26,7 @@ salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
 serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
 
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
+camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
index b05aa16..7967474 100644 (file)
@@ -25,6 +25,7 @@
  *
  */
 
+#include <asm/processor.h>
 #include <crypto/blowfish.h>
 #include <linux/crypto.h>
 #include <linux/init.h>
@@ -76,27 +77,6 @@ static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src);
 }
 
-static struct crypto_alg bf_alg = {
-       .cra_name               =       "blowfish",
-       .cra_driver_name        =       "blowfish-asm",
-       .cra_priority           =       200,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       BF_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct bf_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(bf_alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       BF_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       BF_MAX_KEY_SIZE,
-                       .cia_setkey             =       blowfish_setkey,
-                       .cia_encrypt            =       blowfish_encrypt,
-                       .cia_decrypt            =       blowfish_decrypt,
-               }
-       }
-};
-
 static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
                     void (*fn)(struct bf_ctx *, u8 *, const u8 *),
                     void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *))
@@ -160,28 +140,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way);
 }
 
-static struct crypto_alg blk_ecb_alg = {
-       .cra_name               = "ecb(blowfish)",
-       .cra_driver_name        = "ecb-blowfish-asm",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = BF_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct bf_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = BF_MIN_KEY_SIZE,
-                       .max_keysize    = BF_MAX_KEY_SIZE,
-                       .setkey         = blowfish_setkey,
-                       .encrypt        = ecb_encrypt,
-                       .decrypt        = ecb_decrypt,
-               },
-       },
-};
-
 static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
                                  struct blkcipher_walk *walk)
 {
@@ -307,29 +265,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_cbc_alg = {
-       .cra_name               = "cbc(blowfish)",
-       .cra_driver_name        = "cbc-blowfish-asm",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = BF_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct bf_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = BF_MIN_KEY_SIZE,
-                       .max_keysize    = BF_MAX_KEY_SIZE,
-                       .ivsize         = BF_BLOCK_SIZE,
-                       .setkey         = blowfish_setkey,
-                       .encrypt        = cbc_encrypt,
-                       .decrypt        = cbc_decrypt,
-               },
-       },
-};
-
 static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk)
 {
        u8 *ctrblk = walk->iv;
@@ -423,7 +358,67 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_ctr_alg = {
+static struct crypto_alg bf_algs[4] = { {
+       .cra_name               = "blowfish",
+       .cra_driver_name        = "blowfish-asm",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(bf_algs[0].cra_list),
+       .cra_u = {
+               .cipher = {
+                       .cia_min_keysize        = BF_MIN_KEY_SIZE,
+                       .cia_max_keysize        = BF_MAX_KEY_SIZE,
+                       .cia_setkey             = blowfish_setkey,
+                       .cia_encrypt            = blowfish_encrypt,
+                       .cia_decrypt            = blowfish_decrypt,
+               }
+       }
+}, {
+       .cra_name               = "ecb(blowfish)",
+       .cra_driver_name        = "ecb-blowfish-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(bf_algs[1].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .setkey         = blowfish_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(blowfish)",
+       .cra_driver_name        = "cbc-blowfish-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(bf_algs[2].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .ivsize         = BF_BLOCK_SIZE,
+                       .setkey         = blowfish_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
        .cra_name               = "ctr(blowfish)",
        .cra_driver_name        = "ctr-blowfish-asm",
        .cra_priority           = 300,
@@ -433,7 +428,7 @@ static struct crypto_alg blk_ctr_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ctr_alg.cra_list),
+       .cra_list               = LIST_HEAD_INIT(bf_algs[3].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = BF_MIN_KEY_SIZE,
@@ -444,43 +439,45 @@ static struct crypto_alg blk_ctr_alg = {
                        .decrypt        = ctr_crypt,
                },
        },
-};
+} };
+
+static bool is_blacklisted_cpu(void)
+{
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return false;
+
+       if (boot_cpu_data.x86 == 0x0f) {
+               /*
+                * On Pentium 4, blowfish-x86_64 is slower than generic C
+                * implementation because use of 64bit rotates (which are really
+                * slow on P4). Therefore blacklist P4s.
+                */
+               return true;
+       }
+
+       return false;
+}
+
+static int force;
+module_param(force, int, 0);
+MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
 
 static int __init init(void)
 {
-       int err;
+       if (!force && is_blacklisted_cpu()) {
+               printk(KERN_INFO
+                       "blowfish-x86_64: performance on this CPU "
+                       "would be suboptimal: disabling "
+                       "blowfish-x86_64.\n");
+               return -ENODEV;
+       }
 
-       err = crypto_register_alg(&bf_alg);
-       if (err)
-               goto bf_err;
-       err = crypto_register_alg(&blk_ecb_alg);
-       if (err)
-               goto ecb_err;
-       err = crypto_register_alg(&blk_cbc_alg);
-       if (err)
-               goto cbc_err;
-       err = crypto_register_alg(&blk_ctr_alg);
-       if (err)
-               goto ctr_err;
-
-       return 0;
-
-ctr_err:
-       crypto_unregister_alg(&blk_cbc_alg);
-cbc_err:
-       crypto_unregister_alg(&blk_ecb_alg);
-ecb_err:
-       crypto_unregister_alg(&bf_alg);
-bf_err:
-       return err;
+       return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs));
 }
 
 static void __exit fini(void)
 {
-       crypto_unregister_alg(&blk_ctr_alg);
-       crypto_unregister_alg(&blk_cbc_alg);
-       crypto_unregister_alg(&blk_ecb_alg);
-       crypto_unregister_alg(&bf_alg);
+       crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs));
 }
 
 module_init(init);
diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S
new file mode 100644 (file)
index 0000000..0b33743
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Camellia Cipher Algorithm (x86_64)
+ *
+ * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ *
+ */
+
+.file "camellia-x86_64-asm_64.S"
+.text
+
+.extern camellia_sp10011110;
+.extern camellia_sp22000222;
+.extern camellia_sp03303033;
+.extern camellia_sp00444404;
+.extern camellia_sp02220222;
+.extern camellia_sp30333033;
+.extern camellia_sp44044404;
+.extern camellia_sp11101110;
+
+#define sp10011110 camellia_sp10011110
+#define sp22000222 camellia_sp22000222
+#define sp03303033 camellia_sp03303033
+#define sp00444404 camellia_sp00444404
+#define sp02220222 camellia_sp02220222
+#define sp30333033 camellia_sp30333033
+#define sp44044404 camellia_sp44044404
+#define sp11101110 camellia_sp11101110
+
+#define CAMELLIA_TABLE_BYTE_LEN 272
+
+/* struct camellia_ctx: */
+#define key_table 0
+#define key_length CAMELLIA_TABLE_BYTE_LEN
+
+/* register macros */
+#define CTX %rdi
+#define RIO %rsi
+#define RIOd %esi
+
+#define RAB0 %rax
+#define RCD0 %rcx
+#define RAB1 %rbx
+#define RCD1 %rdx
+
+#define RAB0d %eax
+#define RCD0d %ecx
+#define RAB1d %ebx
+#define RCD1d %edx
+
+#define RAB0bl %al
+#define RCD0bl %cl
+#define RAB1bl %bl
+#define RCD1bl %dl
+
+#define RAB0bh %ah
+#define RCD0bh %ch
+#define RAB1bh %bh
+#define RCD1bh %dh
+
+#define RT0 %rsi
+#define RT1 %rbp
+#define RT2 %r8
+
+#define RT0d %esi
+#define RT1d %ebp
+#define RT2d %r8d
+
+#define RT2bl %r8b
+
+#define RXOR %r9
+#define RRBP %r10
+#define RDST %r11
+
+#define RXORd %r9d
+#define RXORbl %r9b
+
+#define xor2ror16(T0, T1, tmp1, tmp2, ab, dst) \
+       movzbl ab ## bl,                tmp2 ## d; \
+       movzbl ab ## bh,                tmp1 ## d; \
+       rorq $16,                       ab; \
+       xorq T0(, tmp2, 8),             dst; \
+       xorq T1(, tmp1, 8),             dst;
+
+/**********************************************************************
+  1-way camellia
+ **********************************************************************/
+#define roundsm(ab, subkey, cd) \
+       movq (key_table + ((subkey) * 2) * 4)(CTX),     RT2; \
+       \
+       xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \
+       xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \
+       xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \
+       xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \
+       \
+       xorq RT2,                                       cd ## 0;
+
+#define fls(l, r, kl, kr) \
+       movl (key_table + ((kl) * 2) * 4)(CTX),         RT0d; \
+       andl l ## 0d,                                   RT0d; \
+       roll $1,                                        RT0d; \
+       shlq $32,                                       RT0; \
+       xorq RT0,                                       l ## 0; \
+       movq (key_table + ((kr) * 2) * 4)(CTX),         RT1; \
+       orq r ## 0,                                     RT1; \
+       shrq $32,                                       RT1; \
+       xorq RT1,                                       r ## 0; \
+       \
+       movq (key_table + ((kl) * 2) * 4)(CTX),         RT2; \
+       orq l ## 0,                                     RT2; \
+       shrq $32,                                       RT2; \
+       xorq RT2,                                       l ## 0; \
+       movl (key_table + ((kr) * 2) * 4)(CTX),         RT0d; \
+       andl r ## 0d,                                   RT0d; \
+       roll $1,                                        RT0d; \
+       shlq $32,                                       RT0; \
+       xorq RT0,                                       r ## 0;
+
+#define enc_rounds(i) \
+       roundsm(RAB, i + 2, RCD); \
+       roundsm(RCD, i + 3, RAB); \
+       roundsm(RAB, i + 4, RCD); \
+       roundsm(RCD, i + 5, RAB); \
+       roundsm(RAB, i + 6, RCD); \
+       roundsm(RCD, i + 7, RAB);
+
+#define enc_fls(i) \
+       fls(RAB, RCD, i + 0, i + 1);
+
+#define enc_inpack() \
+       movq (RIO),                     RAB0; \
+       bswapq                          RAB0; \
+       rolq $32,                       RAB0; \
+       movq 4*2(RIO),                  RCD0; \
+       bswapq                          RCD0; \
+       rorq $32,                       RCD0; \
+       xorq key_table(CTX),            RAB0;
+
+#define enc_outunpack(op, max) \
+       xorq key_table(CTX, max, 8),    RCD0; \
+       rorq $32,                       RCD0; \
+       bswapq                          RCD0; \
+       op ## q RCD0,                   (RIO); \
+       rolq $32,                       RAB0; \
+       bswapq                          RAB0; \
+       op ## q RAB0,                   4*2(RIO);
+
+#define dec_rounds(i) \
+       roundsm(RAB, i + 7, RCD); \
+       roundsm(RCD, i + 6, RAB); \
+       roundsm(RAB, i + 5, RCD); \
+       roundsm(RCD, i + 4, RAB); \
+       roundsm(RAB, i + 3, RCD); \
+       roundsm(RCD, i + 2, RAB);
+
+#define dec_fls(i) \
+       fls(RAB, RCD, i + 1, i + 0);
+
+#define dec_inpack(max) \
+       movq (RIO),                     RAB0; \
+       bswapq                          RAB0; \
+       rolq $32,                       RAB0; \
+       movq 4*2(RIO),                  RCD0; \
+       bswapq                          RCD0; \
+       rorq $32,                       RCD0; \
+       xorq key_table(CTX, max, 8),    RAB0;
+
+#define dec_outunpack() \
+       xorq key_table(CTX),            RCD0; \
+       rorq $32,                       RCD0; \
+       bswapq                          RCD0; \
+       movq RCD0,                      (RIO); \
+       rolq $32,                       RAB0; \
+       bswapq                          RAB0; \
+       movq RAB0,                      4*2(RIO);
+
+.global __camellia_enc_blk;
+.type   __camellia_enc_blk,@function;
+
+__camellia_enc_blk:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: bool xor
+        */
+       movq %rbp, RRBP;
+
+       movq %rcx, RXOR;
+       movq %rsi, RDST;
+       movq %rdx, RIO;
+
+       enc_inpack();
+
+       enc_rounds(0);
+       enc_fls(8);
+       enc_rounds(8);
+       enc_fls(16);
+       enc_rounds(16);
+       movl $24, RT1d; /* max */
+
+       cmpb $16, key_length(CTX);
+       je __enc_done;
+
+       enc_fls(24);
+       enc_rounds(24);
+       movl $32, RT1d; /* max */
+
+__enc_done:
+       testb RXORbl, RXORbl;
+       movq RDST, RIO;
+
+       jnz __enc_xor;
+
+       enc_outunpack(mov, RT1);
+
+       movq RRBP, %rbp;
+       ret;
+
+__enc_xor:
+       enc_outunpack(xor, RT1);
+
+       movq RRBP, %rbp;
+       ret;
+
+.global camellia_dec_blk;
+.type   camellia_dec_blk,@function;
+
+camellia_dec_blk:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+       cmpl $16, key_length(CTX);
+       movl $32, RT2d;
+       movl $24, RXORd;
+       cmovel RXORd, RT2d; /* max */
+
+       movq %rbp, RRBP;
+       movq %rsi, RDST;
+       movq %rdx, RIO;
+
+       dec_inpack(RT2);
+
+       cmpb $24, RT2bl;
+       je __dec_rounds16;
+
+       dec_rounds(24);
+       dec_fls(24);
+
+__dec_rounds16:
+       dec_rounds(16);
+       dec_fls(16);
+       dec_rounds(8);
+       dec_fls(8);
+       dec_rounds(0);
+
+       movq RDST, RIO;
+
+       dec_outunpack();
+
+       movq RRBP, %rbp;
+       ret;
+
+/**********************************************************************
+  2-way camellia
+ **********************************************************************/
+#define roundsm2(ab, subkey, cd) \
+       movq (key_table + ((subkey) * 2) * 4)(CTX),     RT2; \
+       xorq RT2,                                       cd ## 1; \
+       \
+       xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \
+       xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \
+       xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \
+       xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \
+       \
+               xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 1, cd ## 1); \
+               xorq RT2,                                       cd ## 0; \
+               xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 1, cd ## 1); \
+               xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 1, cd ## 1); \
+               xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 1, cd ## 1);
+
+#define fls2(l, r, kl, kr) \
+       movl (key_table + ((kl) * 2) * 4)(CTX),         RT0d; \
+       andl l ## 0d,                                   RT0d; \
+       roll $1,                                        RT0d; \
+       shlq $32,                                       RT0; \
+       xorq RT0,                                       l ## 0; \
+       movq (key_table + ((kr) * 2) * 4)(CTX),         RT1; \
+       orq r ## 0,                                     RT1; \
+       shrq $32,                                       RT1; \
+       xorq RT1,                                       r ## 0; \
+       \
+               movl (key_table + ((kl) * 2) * 4)(CTX),         RT2d; \
+               andl l ## 1d,                                   RT2d; \
+               roll $1,                                        RT2d; \
+               shlq $32,                                       RT2; \
+               xorq RT2,                                       l ## 1; \
+               movq (key_table + ((kr) * 2) * 4)(CTX),         RT0; \
+               orq r ## 1,                                     RT0; \
+               shrq $32,                                       RT0; \
+               xorq RT0,                                       r ## 1; \
+       \
+       movq (key_table + ((kl) * 2) * 4)(CTX),         RT1; \
+       orq l ## 0,                                     RT1; \
+       shrq $32,                                       RT1; \
+       xorq RT1,                                       l ## 0; \
+       movl (key_table + ((kr) * 2) * 4)(CTX),         RT2d; \
+       andl r ## 0d,                                   RT2d; \
+       roll $1,                                        RT2d; \
+       shlq $32,                                       RT2; \
+       xorq RT2,                                       r ## 0; \
+       \
+               movq (key_table + ((kl) * 2) * 4)(CTX),         RT0; \
+               orq l ## 1,                                     RT0; \
+               shrq $32,                                       RT0; \
+               xorq RT0,                                       l ## 1; \
+               movl (key_table + ((kr) * 2) * 4)(CTX),         RT1d; \
+               andl r ## 1d,                                   RT1d; \
+               roll $1,                                        RT1d; \
+               shlq $32,                                       RT1; \
+               xorq RT1,                                       r ## 1;
+
+#define enc_rounds2(i) \
+       roundsm2(RAB, i + 2, RCD); \
+       roundsm2(RCD, i + 3, RAB); \
+       roundsm2(RAB, i + 4, RCD); \
+       roundsm2(RCD, i + 5, RAB); \
+       roundsm2(RAB, i + 6, RCD); \
+       roundsm2(RCD, i + 7, RAB);
+
+#define enc_fls2(i) \
+       fls2(RAB, RCD, i + 0, i + 1);
+
+#define enc_inpack2() \
+       movq (RIO),                     RAB0; \
+       bswapq                          RAB0; \
+       rorq $32,                       RAB0; \
+       movq 4*2(RIO),                  RCD0; \
+       bswapq                          RCD0; \
+       rolq $32,                       RCD0; \
+       xorq key_table(CTX),            RAB0; \
+       \
+               movq 8*2(RIO),                  RAB1; \
+               bswapq                          RAB1; \
+               rorq $32,                       RAB1; \
+               movq 12*2(RIO),                 RCD1; \
+               bswapq                          RCD1; \
+               rolq $32,                       RCD1; \
+               xorq key_table(CTX),            RAB1;
+
+#define enc_outunpack2(op, max) \
+       xorq key_table(CTX, max, 8),    RCD0; \
+       rolq $32,                       RCD0; \
+       bswapq                          RCD0; \
+       op ## q RCD0,                   (RIO); \
+       rorq $32,                       RAB0; \
+       bswapq                          RAB0; \
+       op ## q RAB0,                   4*2(RIO); \
+       \
+               xorq key_table(CTX, max, 8),    RCD1; \
+               rolq $32,                       RCD1; \
+               bswapq                          RCD1; \
+               op ## q RCD1,                   8*2(RIO); \
+               rorq $32,                       RAB1; \
+               bswapq                          RAB1; \
+               op ## q RAB1,                   12*2(RIO);
+
+#define dec_rounds2(i) \
+       roundsm2(RAB, i + 7, RCD); \
+       roundsm2(RCD, i + 6, RAB); \
+       roundsm2(RAB, i + 5, RCD); \
+       roundsm2(RCD, i + 4, RAB); \
+       roundsm2(RAB, i + 3, RCD); \
+       roundsm2(RCD, i + 2, RAB);
+
+#define dec_fls2(i) \
+       fls2(RAB, RCD, i + 1, i + 0);
+
+#define dec_inpack2(max) \
+       movq (RIO),                     RAB0; \
+       bswapq                          RAB0; \
+       rorq $32,                       RAB0; \
+       movq 4*2(RIO),                  RCD0; \
+       bswapq                          RCD0; \
+       rolq $32,                       RCD0; \
+       xorq key_table(CTX, max, 8),    RAB0; \
+       \
+               movq 8*2(RIO),                  RAB1; \
+               bswapq                          RAB1; \
+               rorq $32,                       RAB1; \
+               movq 12*2(RIO),                 RCD1; \
+               bswapq                          RCD1; \
+               rolq $32,                       RCD1; \
+               xorq key_table(CTX, max, 8),    RAB1;
+
+#define dec_outunpack2() \
+       xorq key_table(CTX),            RCD0; \
+       rolq $32,                       RCD0; \
+       bswapq                          RCD0; \
+       movq RCD0,                      (RIO); \
+       rorq $32,                       RAB0; \
+       bswapq                          RAB0; \
+       movq RAB0,                      4*2(RIO); \
+       \
+               xorq key_table(CTX),            RCD1; \
+               rolq $32,                       RCD1; \
+               bswapq                          RCD1; \
+               movq RCD1,                      8*2(RIO); \
+               rorq $32,                       RAB1; \
+               bswapq                          RAB1; \
+               movq RAB1,                      12*2(RIO);
+
+.global __camellia_enc_blk_2way;
+.type   __camellia_enc_blk_2way,@function;
+
+__camellia_enc_blk_2way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: bool xor
+        */
+       pushq %rbx;
+
+       movq %rbp, RRBP;
+       movq %rcx, RXOR;
+       movq %rsi, RDST;
+       movq %rdx, RIO;
+
+       enc_inpack2();
+
+       enc_rounds2(0);
+       enc_fls2(8);
+       enc_rounds2(8);
+       enc_fls2(16);
+       enc_rounds2(16);
+       movl $24, RT2d; /* max */
+
+       cmpb $16, key_length(CTX);
+       je __enc2_done;
+
+       enc_fls2(24);
+       enc_rounds2(24);
+       movl $32, RT2d; /* max */
+
+__enc2_done:
+       test RXORbl, RXORbl;
+       movq RDST, RIO;
+       jnz __enc2_xor;
+
+       enc_outunpack2(mov, RT2);
+
+       movq RRBP, %rbp;
+       popq %rbx;
+       ret;
+
+__enc2_xor:
+       enc_outunpack2(xor, RT2);
+
+       movq RRBP, %rbp;
+       popq %rbx;
+       ret;
+
+.global camellia_dec_blk_2way;
+.type   camellia_dec_blk_2way,@function;
+
+camellia_dec_blk_2way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+       cmpl $16, key_length(CTX);
+       movl $32, RT2d;
+       movl $24, RXORd;
+       cmovel RXORd, RT2d; /* max */
+
+       movq %rbx, RXOR;
+       movq %rbp, RRBP;
+       movq %rsi, RDST;
+       movq %rdx, RIO;
+
+       dec_inpack2(RT2);
+
+       cmpb $24, RT2bl;
+       je __dec2_rounds16;
+
+       dec_rounds2(24);
+       dec_fls2(24);
+
+__dec2_rounds16:
+       dec_rounds2(16);
+       dec_fls2(16);
+       dec_rounds2(8);
+       dec_fls2(8);
+       dec_rounds2(0);
+
+       movq RDST, RIO;
+
+       dec_outunpack2();
+
+       movq RRBP, %rbp;
+       movq RXOR, %rbx;
+       ret;
diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c
new file mode 100644 (file)
index 0000000..1ca36a9
--- /dev/null
@@ -0,0 +1,1952 @@
+/*
+ * Glue Code for assembler optimized version of Camellia
+ *
+ * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * Camellia parts based on code by:
+ *  Copyright (C) 2006 NTT (Nippon Telegraph and Telephone Corporation)
+ * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
+ *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ * CTR part based on code (crypto/ctr.c) by:
+ *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/unaligned.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <crypto/b128ops.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+
+#define CAMELLIA_MIN_KEY_SIZE  16
+#define CAMELLIA_MAX_KEY_SIZE  32
+#define CAMELLIA_BLOCK_SIZE    16
+#define CAMELLIA_TABLE_BYTE_LEN        272
+
+struct camellia_ctx {
+       u64 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
+       u32 key_length;
+};
+
+/* regular block cipher functions */
+asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst,
+                                  const u8 *src, bool xor);
+asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst,
+                                const u8 *src);
+
+/* 2-way parallel cipher functions */
+asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst,
+                                       const u8 *src, bool xor);
+asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst,
+                                     const u8 *src);
+
+static inline void camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst,
+                                   const u8 *src)
+{
+       __camellia_enc_blk(ctx, dst, src, false);
+}
+
+static inline void camellia_enc_blk_xor(struct camellia_ctx *ctx, u8 *dst,
+                                       const u8 *src)
+{
+       __camellia_enc_blk(ctx, dst, src, true);
+}
+
+static inline void camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst,
+                                        const u8 *src)
+{
+       __camellia_enc_blk_2way(ctx, dst, src, false);
+}
+
+static inline void camellia_enc_blk_xor_2way(struct camellia_ctx *ctx, u8 *dst,
+                                            const u8 *src)
+{
+       __camellia_enc_blk_2way(ctx, dst, src, true);
+}
+
+static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       camellia_enc_blk(crypto_tfm_ctx(tfm), dst, src);
+}
+
+static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       camellia_dec_blk(crypto_tfm_ctx(tfm), dst, src);
+}
+
+/* camellia sboxes */
+const u64 camellia_sp10011110[256] = {
+       0x7000007070707000, 0x8200008282828200, 0x2c00002c2c2c2c00,
+       0xec0000ecececec00, 0xb30000b3b3b3b300, 0x2700002727272700,
+       0xc00000c0c0c0c000, 0xe50000e5e5e5e500, 0xe40000e4e4e4e400,
+       0x8500008585858500, 0x5700005757575700, 0x3500003535353500,
+       0xea0000eaeaeaea00, 0x0c00000c0c0c0c00, 0xae0000aeaeaeae00,
+       0x4100004141414100, 0x2300002323232300, 0xef0000efefefef00,
+       0x6b00006b6b6b6b00, 0x9300009393939300, 0x4500004545454500,
+       0x1900001919191900, 0xa50000a5a5a5a500, 0x2100002121212100,
+       0xed0000edededed00, 0x0e00000e0e0e0e00, 0x4f00004f4f4f4f00,
+       0x4e00004e4e4e4e00, 0x1d00001d1d1d1d00, 0x6500006565656500,
+       0x9200009292929200, 0xbd0000bdbdbdbd00, 0x8600008686868600,
+       0xb80000b8b8b8b800, 0xaf0000afafafaf00, 0x8f00008f8f8f8f00,
+       0x7c00007c7c7c7c00, 0xeb0000ebebebeb00, 0x1f00001f1f1f1f00,
+       0xce0000cececece00, 0x3e00003e3e3e3e00, 0x3000003030303000,
+       0xdc0000dcdcdcdc00, 0x5f00005f5f5f5f00, 0x5e00005e5e5e5e00,
+       0xc50000c5c5c5c500, 0x0b00000b0b0b0b00, 0x1a00001a1a1a1a00,
+       0xa60000a6a6a6a600, 0xe10000e1e1e1e100, 0x3900003939393900,
+       0xca0000cacacaca00, 0xd50000d5d5d5d500, 0x4700004747474700,
+       0x5d00005d5d5d5d00, 0x3d00003d3d3d3d00, 0xd90000d9d9d9d900,
+       0x0100000101010100, 0x5a00005a5a5a5a00, 0xd60000d6d6d6d600,
+       0x5100005151515100, 0x5600005656565600, 0x6c00006c6c6c6c00,
+       0x4d00004d4d4d4d00, 0x8b00008b8b8b8b00, 0x0d00000d0d0d0d00,
+       0x9a00009a9a9a9a00, 0x6600006666666600, 0xfb0000fbfbfbfb00,
+       0xcc0000cccccccc00, 0xb00000b0b0b0b000, 0x2d00002d2d2d2d00,
+       0x7400007474747400, 0x1200001212121200, 0x2b00002b2b2b2b00,
+       0x2000002020202000, 0xf00000f0f0f0f000, 0xb10000b1b1b1b100,
+       0x8400008484848400, 0x9900009999999900, 0xdf0000dfdfdfdf00,
+       0x4c00004c4c4c4c00, 0xcb0000cbcbcbcb00, 0xc20000c2c2c2c200,
+       0x3400003434343400, 0x7e00007e7e7e7e00, 0x7600007676767600,
+       0x0500000505050500, 0x6d00006d6d6d6d00, 0xb70000b7b7b7b700,
+       0xa90000a9a9a9a900, 0x3100003131313100, 0xd10000d1d1d1d100,
+       0x1700001717171700, 0x0400000404040400, 0xd70000d7d7d7d700,
+       0x1400001414141400, 0x5800005858585800, 0x3a00003a3a3a3a00,
+       0x6100006161616100, 0xde0000dededede00, 0x1b00001b1b1b1b00,
+       0x1100001111111100, 0x1c00001c1c1c1c00, 0x3200003232323200,
+       0x0f00000f0f0f0f00, 0x9c00009c9c9c9c00, 0x1600001616161600,
+       0x5300005353535300, 0x1800001818181800, 0xf20000f2f2f2f200,
+       0x2200002222222200, 0xfe0000fefefefe00, 0x4400004444444400,
+       0xcf0000cfcfcfcf00, 0xb20000b2b2b2b200, 0xc30000c3c3c3c300,
+       0xb50000b5b5b5b500, 0x7a00007a7a7a7a00, 0x9100009191919100,
+       0x2400002424242400, 0x0800000808080800, 0xe80000e8e8e8e800,
+       0xa80000a8a8a8a800, 0x6000006060606000, 0xfc0000fcfcfcfc00,
+       0x6900006969696900, 0x5000005050505000, 0xaa0000aaaaaaaa00,
+       0xd00000d0d0d0d000, 0xa00000a0a0a0a000, 0x7d00007d7d7d7d00,
+       0xa10000a1a1a1a100, 0x8900008989898900, 0x6200006262626200,
+       0x9700009797979700, 0x5400005454545400, 0x5b00005b5b5b5b00,
+       0x1e00001e1e1e1e00, 0x9500009595959500, 0xe00000e0e0e0e000,
+       0xff0000ffffffff00, 0x6400006464646400, 0xd20000d2d2d2d200,
+       0x1000001010101000, 0xc40000c4c4c4c400, 0x0000000000000000,
+       0x4800004848484800, 0xa30000a3a3a3a300, 0xf70000f7f7f7f700,
+       0x7500007575757500, 0xdb0000dbdbdbdb00, 0x8a00008a8a8a8a00,
+       0x0300000303030300, 0xe60000e6e6e6e600, 0xda0000dadadada00,
+       0x0900000909090900, 0x3f00003f3f3f3f00, 0xdd0000dddddddd00,
+       0x9400009494949400, 0x8700008787878700, 0x5c00005c5c5c5c00,
+       0x8300008383838300, 0x0200000202020200, 0xcd0000cdcdcdcd00,
+       0x4a00004a4a4a4a00, 0x9000009090909000, 0x3300003333333300,
+       0x7300007373737300, 0x6700006767676700, 0xf60000f6f6f6f600,
+       0xf30000f3f3f3f300, 0x9d00009d9d9d9d00, 0x7f00007f7f7f7f00,
+       0xbf0000bfbfbfbf00, 0xe20000e2e2e2e200, 0x5200005252525200,
+       0x9b00009b9b9b9b00, 0xd80000d8d8d8d800, 0x2600002626262600,
+       0xc80000c8c8c8c800, 0x3700003737373700, 0xc60000c6c6c6c600,
+       0x3b00003b3b3b3b00, 0x8100008181818100, 0x9600009696969600,
+       0x6f00006f6f6f6f00, 0x4b00004b4b4b4b00, 0x1300001313131300,
+       0xbe0000bebebebe00, 0x6300006363636300, 0x2e00002e2e2e2e00,
+       0xe90000e9e9e9e900, 0x7900007979797900, 0xa70000a7a7a7a700,
+       0x8c00008c8c8c8c00, 0x9f00009f9f9f9f00, 0x6e00006e6e6e6e00,
+       0xbc0000bcbcbcbc00, 0x8e00008e8e8e8e00, 0x2900002929292900,
+       0xf50000f5f5f5f500, 0xf90000f9f9f9f900, 0xb60000b6b6b6b600,
+       0x2f00002f2f2f2f00, 0xfd0000fdfdfdfd00, 0xb40000b4b4b4b400,
+       0x5900005959595900, 0x7800007878787800, 0x9800009898989800,
+       0x0600000606060600, 0x6a00006a6a6a6a00, 0xe70000e7e7e7e700,
+       0x4600004646464600, 0x7100007171717100, 0xba0000babababa00,
+       0xd40000d4d4d4d400, 0x2500002525252500, 0xab0000abababab00,
+       0x4200004242424200, 0x8800008888888800, 0xa20000a2a2a2a200,
+       0x8d00008d8d8d8d00, 0xfa0000fafafafa00, 0x7200007272727200,
+       0x0700000707070700, 0xb90000b9b9b9b900, 0x5500005555555500,
+       0xf80000f8f8f8f800, 0xee0000eeeeeeee00, 0xac0000acacacac00,
+       0x0a00000a0a0a0a00, 0x3600003636363600, 0x4900004949494900,
+       0x2a00002a2a2a2a00, 0x6800006868686800, 0x3c00003c3c3c3c00,
+       0x3800003838383800, 0xf10000f1f1f1f100, 0xa40000a4a4a4a400,
+       0x4000004040404000, 0x2800002828282800, 0xd30000d3d3d3d300,
+       0x7b00007b7b7b7b00, 0xbb0000bbbbbbbb00, 0xc90000c9c9c9c900,
+       0x4300004343434300, 0xc10000c1c1c1c100, 0x1500001515151500,
+       0xe30000e3e3e3e300, 0xad0000adadadad00, 0xf40000f4f4f4f400,
+       0x7700007777777700, 0xc70000c7c7c7c700, 0x8000008080808000,
+       0x9e00009e9e9e9e00,
+};
+
+const u64 camellia_sp22000222[256] = {
+       0xe0e0000000e0e0e0, 0x0505000000050505, 0x5858000000585858,
+       0xd9d9000000d9d9d9, 0x6767000000676767, 0x4e4e0000004e4e4e,
+       0x8181000000818181, 0xcbcb000000cbcbcb, 0xc9c9000000c9c9c9,
+       0x0b0b0000000b0b0b, 0xaeae000000aeaeae, 0x6a6a0000006a6a6a,
+       0xd5d5000000d5d5d5, 0x1818000000181818, 0x5d5d0000005d5d5d,
+       0x8282000000828282, 0x4646000000464646, 0xdfdf000000dfdfdf,
+       0xd6d6000000d6d6d6, 0x2727000000272727, 0x8a8a0000008a8a8a,
+       0x3232000000323232, 0x4b4b0000004b4b4b, 0x4242000000424242,
+       0xdbdb000000dbdbdb, 0x1c1c0000001c1c1c, 0x9e9e0000009e9e9e,
+       0x9c9c0000009c9c9c, 0x3a3a0000003a3a3a, 0xcaca000000cacaca,
+       0x2525000000252525, 0x7b7b0000007b7b7b, 0x0d0d0000000d0d0d,
+       0x7171000000717171, 0x5f5f0000005f5f5f, 0x1f1f0000001f1f1f,
+       0xf8f8000000f8f8f8, 0xd7d7000000d7d7d7, 0x3e3e0000003e3e3e,
+       0x9d9d0000009d9d9d, 0x7c7c0000007c7c7c, 0x6060000000606060,
+       0xb9b9000000b9b9b9, 0xbebe000000bebebe, 0xbcbc000000bcbcbc,
+       0x8b8b0000008b8b8b, 0x1616000000161616, 0x3434000000343434,
+       0x4d4d0000004d4d4d, 0xc3c3000000c3c3c3, 0x7272000000727272,
+       0x9595000000959595, 0xabab000000ababab, 0x8e8e0000008e8e8e,
+       0xbaba000000bababa, 0x7a7a0000007a7a7a, 0xb3b3000000b3b3b3,
+       0x0202000000020202, 0xb4b4000000b4b4b4, 0xadad000000adadad,
+       0xa2a2000000a2a2a2, 0xacac000000acacac, 0xd8d8000000d8d8d8,
+       0x9a9a0000009a9a9a, 0x1717000000171717, 0x1a1a0000001a1a1a,
+       0x3535000000353535, 0xcccc000000cccccc, 0xf7f7000000f7f7f7,
+       0x9999000000999999, 0x6161000000616161, 0x5a5a0000005a5a5a,
+       0xe8e8000000e8e8e8, 0x2424000000242424, 0x5656000000565656,
+       0x4040000000404040, 0xe1e1000000e1e1e1, 0x6363000000636363,
+       0x0909000000090909, 0x3333000000333333, 0xbfbf000000bfbfbf,
+       0x9898000000989898, 0x9797000000979797, 0x8585000000858585,
+       0x6868000000686868, 0xfcfc000000fcfcfc, 0xecec000000ececec,
+       0x0a0a0000000a0a0a, 0xdada000000dadada, 0x6f6f0000006f6f6f,
+       0x5353000000535353, 0x6262000000626262, 0xa3a3000000a3a3a3,
+       0x2e2e0000002e2e2e, 0x0808000000080808, 0xafaf000000afafaf,
+       0x2828000000282828, 0xb0b0000000b0b0b0, 0x7474000000747474,
+       0xc2c2000000c2c2c2, 0xbdbd000000bdbdbd, 0x3636000000363636,
+       0x2222000000222222, 0x3838000000383838, 0x6464000000646464,
+       0x1e1e0000001e1e1e, 0x3939000000393939, 0x2c2c0000002c2c2c,
+       0xa6a6000000a6a6a6, 0x3030000000303030, 0xe5e5000000e5e5e5,
+       0x4444000000444444, 0xfdfd000000fdfdfd, 0x8888000000888888,
+       0x9f9f0000009f9f9f, 0x6565000000656565, 0x8787000000878787,
+       0x6b6b0000006b6b6b, 0xf4f4000000f4f4f4, 0x2323000000232323,
+       0x4848000000484848, 0x1010000000101010, 0xd1d1000000d1d1d1,
+       0x5151000000515151, 0xc0c0000000c0c0c0, 0xf9f9000000f9f9f9,
+       0xd2d2000000d2d2d2, 0xa0a0000000a0a0a0, 0x5555000000555555,
+       0xa1a1000000a1a1a1, 0x4141000000414141, 0xfafa000000fafafa,
+       0x4343000000434343, 0x1313000000131313, 0xc4c4000000c4c4c4,
+       0x2f2f0000002f2f2f, 0xa8a8000000a8a8a8, 0xb6b6000000b6b6b6,
+       0x3c3c0000003c3c3c, 0x2b2b0000002b2b2b, 0xc1c1000000c1c1c1,
+       0xffff000000ffffff, 0xc8c8000000c8c8c8, 0xa5a5000000a5a5a5,
+       0x2020000000202020, 0x8989000000898989, 0x0000000000000000,
+       0x9090000000909090, 0x4747000000474747, 0xefef000000efefef,
+       0xeaea000000eaeaea, 0xb7b7000000b7b7b7, 0x1515000000151515,
+       0x0606000000060606, 0xcdcd000000cdcdcd, 0xb5b5000000b5b5b5,
+       0x1212000000121212, 0x7e7e0000007e7e7e, 0xbbbb000000bbbbbb,
+       0x2929000000292929, 0x0f0f0000000f0f0f, 0xb8b8000000b8b8b8,
+       0x0707000000070707, 0x0404000000040404, 0x9b9b0000009b9b9b,
+       0x9494000000949494, 0x2121000000212121, 0x6666000000666666,
+       0xe6e6000000e6e6e6, 0xcece000000cecece, 0xeded000000ededed,
+       0xe7e7000000e7e7e7, 0x3b3b0000003b3b3b, 0xfefe000000fefefe,
+       0x7f7f0000007f7f7f, 0xc5c5000000c5c5c5, 0xa4a4000000a4a4a4,
+       0x3737000000373737, 0xb1b1000000b1b1b1, 0x4c4c0000004c4c4c,
+       0x9191000000919191, 0x6e6e0000006e6e6e, 0x8d8d0000008d8d8d,
+       0x7676000000767676, 0x0303000000030303, 0x2d2d0000002d2d2d,
+       0xdede000000dedede, 0x9696000000969696, 0x2626000000262626,
+       0x7d7d0000007d7d7d, 0xc6c6000000c6c6c6, 0x5c5c0000005c5c5c,
+       0xd3d3000000d3d3d3, 0xf2f2000000f2f2f2, 0x4f4f0000004f4f4f,
+       0x1919000000191919, 0x3f3f0000003f3f3f, 0xdcdc000000dcdcdc,
+       0x7979000000797979, 0x1d1d0000001d1d1d, 0x5252000000525252,
+       0xebeb000000ebebeb, 0xf3f3000000f3f3f3, 0x6d6d0000006d6d6d,
+       0x5e5e0000005e5e5e, 0xfbfb000000fbfbfb, 0x6969000000696969,
+       0xb2b2000000b2b2b2, 0xf0f0000000f0f0f0, 0x3131000000313131,
+       0x0c0c0000000c0c0c, 0xd4d4000000d4d4d4, 0xcfcf000000cfcfcf,
+       0x8c8c0000008c8c8c, 0xe2e2000000e2e2e2, 0x7575000000757575,
+       0xa9a9000000a9a9a9, 0x4a4a0000004a4a4a, 0x5757000000575757,
+       0x8484000000848484, 0x1111000000111111, 0x4545000000454545,
+       0x1b1b0000001b1b1b, 0xf5f5000000f5f5f5, 0xe4e4000000e4e4e4,
+       0x0e0e0000000e0e0e, 0x7373000000737373, 0xaaaa000000aaaaaa,
+       0xf1f1000000f1f1f1, 0xdddd000000dddddd, 0x5959000000595959,
+       0x1414000000141414, 0x6c6c0000006c6c6c, 0x9292000000929292,
+       0x5454000000545454, 0xd0d0000000d0d0d0, 0x7878000000787878,
+       0x7070000000707070, 0xe3e3000000e3e3e3, 0x4949000000494949,
+       0x8080000000808080, 0x5050000000505050, 0xa7a7000000a7a7a7,
+       0xf6f6000000f6f6f6, 0x7777000000777777, 0x9393000000939393,
+       0x8686000000868686, 0x8383000000838383, 0x2a2a0000002a2a2a,
+       0xc7c7000000c7c7c7, 0x5b5b0000005b5b5b, 0xe9e9000000e9e9e9,
+       0xeeee000000eeeeee, 0x8f8f0000008f8f8f, 0x0101000000010101,
+       0x3d3d0000003d3d3d,
+};
+
+const u64 camellia_sp03303033[256] = {
+       0x0038380038003838, 0x0041410041004141, 0x0016160016001616,
+       0x0076760076007676, 0x00d9d900d900d9d9, 0x0093930093009393,
+       0x0060600060006060, 0x00f2f200f200f2f2, 0x0072720072007272,
+       0x00c2c200c200c2c2, 0x00abab00ab00abab, 0x009a9a009a009a9a,
+       0x0075750075007575, 0x0006060006000606, 0x0057570057005757,
+       0x00a0a000a000a0a0, 0x0091910091009191, 0x00f7f700f700f7f7,
+       0x00b5b500b500b5b5, 0x00c9c900c900c9c9, 0x00a2a200a200a2a2,
+       0x008c8c008c008c8c, 0x00d2d200d200d2d2, 0x0090900090009090,
+       0x00f6f600f600f6f6, 0x0007070007000707, 0x00a7a700a700a7a7,
+       0x0027270027002727, 0x008e8e008e008e8e, 0x00b2b200b200b2b2,
+       0x0049490049004949, 0x00dede00de00dede, 0x0043430043004343,
+       0x005c5c005c005c5c, 0x00d7d700d700d7d7, 0x00c7c700c700c7c7,
+       0x003e3e003e003e3e, 0x00f5f500f500f5f5, 0x008f8f008f008f8f,
+       0x0067670067006767, 0x001f1f001f001f1f, 0x0018180018001818,
+       0x006e6e006e006e6e, 0x00afaf00af00afaf, 0x002f2f002f002f2f,
+       0x00e2e200e200e2e2, 0x0085850085008585, 0x000d0d000d000d0d,
+       0x0053530053005353, 0x00f0f000f000f0f0, 0x009c9c009c009c9c,
+       0x0065650065006565, 0x00eaea00ea00eaea, 0x00a3a300a300a3a3,
+       0x00aeae00ae00aeae, 0x009e9e009e009e9e, 0x00ecec00ec00ecec,
+       0x0080800080008080, 0x002d2d002d002d2d, 0x006b6b006b006b6b,
+       0x00a8a800a800a8a8, 0x002b2b002b002b2b, 0x0036360036003636,
+       0x00a6a600a600a6a6, 0x00c5c500c500c5c5, 0x0086860086008686,
+       0x004d4d004d004d4d, 0x0033330033003333, 0x00fdfd00fd00fdfd,
+       0x0066660066006666, 0x0058580058005858, 0x0096960096009696,
+       0x003a3a003a003a3a, 0x0009090009000909, 0x0095950095009595,
+       0x0010100010001010, 0x0078780078007878, 0x00d8d800d800d8d8,
+       0x0042420042004242, 0x00cccc00cc00cccc, 0x00efef00ef00efef,
+       0x0026260026002626, 0x00e5e500e500e5e5, 0x0061610061006161,
+       0x001a1a001a001a1a, 0x003f3f003f003f3f, 0x003b3b003b003b3b,
+       0x0082820082008282, 0x00b6b600b600b6b6, 0x00dbdb00db00dbdb,
+       0x00d4d400d400d4d4, 0x0098980098009898, 0x00e8e800e800e8e8,
+       0x008b8b008b008b8b, 0x0002020002000202, 0x00ebeb00eb00ebeb,
+       0x000a0a000a000a0a, 0x002c2c002c002c2c, 0x001d1d001d001d1d,
+       0x00b0b000b000b0b0, 0x006f6f006f006f6f, 0x008d8d008d008d8d,
+       0x0088880088008888, 0x000e0e000e000e0e, 0x0019190019001919,
+       0x0087870087008787, 0x004e4e004e004e4e, 0x000b0b000b000b0b,
+       0x00a9a900a900a9a9, 0x000c0c000c000c0c, 0x0079790079007979,
+       0x0011110011001111, 0x007f7f007f007f7f, 0x0022220022002222,
+       0x00e7e700e700e7e7, 0x0059590059005959, 0x00e1e100e100e1e1,
+       0x00dada00da00dada, 0x003d3d003d003d3d, 0x00c8c800c800c8c8,
+       0x0012120012001212, 0x0004040004000404, 0x0074740074007474,
+       0x0054540054005454, 0x0030300030003030, 0x007e7e007e007e7e,
+       0x00b4b400b400b4b4, 0x0028280028002828, 0x0055550055005555,
+       0x0068680068006868, 0x0050500050005050, 0x00bebe00be00bebe,
+       0x00d0d000d000d0d0, 0x00c4c400c400c4c4, 0x0031310031003131,
+       0x00cbcb00cb00cbcb, 0x002a2a002a002a2a, 0x00adad00ad00adad,
+       0x000f0f000f000f0f, 0x00caca00ca00caca, 0x0070700070007070,
+       0x00ffff00ff00ffff, 0x0032320032003232, 0x0069690069006969,
+       0x0008080008000808, 0x0062620062006262, 0x0000000000000000,
+       0x0024240024002424, 0x00d1d100d100d1d1, 0x00fbfb00fb00fbfb,
+       0x00baba00ba00baba, 0x00eded00ed00eded, 0x0045450045004545,
+       0x0081810081008181, 0x0073730073007373, 0x006d6d006d006d6d,
+       0x0084840084008484, 0x009f9f009f009f9f, 0x00eeee00ee00eeee,
+       0x004a4a004a004a4a, 0x00c3c300c300c3c3, 0x002e2e002e002e2e,
+       0x00c1c100c100c1c1, 0x0001010001000101, 0x00e6e600e600e6e6,
+       0x0025250025002525, 0x0048480048004848, 0x0099990099009999,
+       0x00b9b900b900b9b9, 0x00b3b300b300b3b3, 0x007b7b007b007b7b,
+       0x00f9f900f900f9f9, 0x00cece00ce00cece, 0x00bfbf00bf00bfbf,
+       0x00dfdf00df00dfdf, 0x0071710071007171, 0x0029290029002929,
+       0x00cdcd00cd00cdcd, 0x006c6c006c006c6c, 0x0013130013001313,
+       0x0064640064006464, 0x009b9b009b009b9b, 0x0063630063006363,
+       0x009d9d009d009d9d, 0x00c0c000c000c0c0, 0x004b4b004b004b4b,
+       0x00b7b700b700b7b7, 0x00a5a500a500a5a5, 0x0089890089008989,
+       0x005f5f005f005f5f, 0x00b1b100b100b1b1, 0x0017170017001717,
+       0x00f4f400f400f4f4, 0x00bcbc00bc00bcbc, 0x00d3d300d300d3d3,
+       0x0046460046004646, 0x00cfcf00cf00cfcf, 0x0037370037003737,
+       0x005e5e005e005e5e, 0x0047470047004747, 0x0094940094009494,
+       0x00fafa00fa00fafa, 0x00fcfc00fc00fcfc, 0x005b5b005b005b5b,
+       0x0097970097009797, 0x00fefe00fe00fefe, 0x005a5a005a005a5a,
+       0x00acac00ac00acac, 0x003c3c003c003c3c, 0x004c4c004c004c4c,
+       0x0003030003000303, 0x0035350035003535, 0x00f3f300f300f3f3,
+       0x0023230023002323, 0x00b8b800b800b8b8, 0x005d5d005d005d5d,
+       0x006a6a006a006a6a, 0x0092920092009292, 0x00d5d500d500d5d5,
+       0x0021210021002121, 0x0044440044004444, 0x0051510051005151,
+       0x00c6c600c600c6c6, 0x007d7d007d007d7d, 0x0039390039003939,
+       0x0083830083008383, 0x00dcdc00dc00dcdc, 0x00aaaa00aa00aaaa,
+       0x007c7c007c007c7c, 0x0077770077007777, 0x0056560056005656,
+       0x0005050005000505, 0x001b1b001b001b1b, 0x00a4a400a400a4a4,
+       0x0015150015001515, 0x0034340034003434, 0x001e1e001e001e1e,
+       0x001c1c001c001c1c, 0x00f8f800f800f8f8, 0x0052520052005252,
+       0x0020200020002020, 0x0014140014001414, 0x00e9e900e900e9e9,
+       0x00bdbd00bd00bdbd, 0x00dddd00dd00dddd, 0x00e4e400e400e4e4,
+       0x00a1a100a100a1a1, 0x00e0e000e000e0e0, 0x008a8a008a008a8a,
+       0x00f1f100f100f1f1, 0x00d6d600d600d6d6, 0x007a7a007a007a7a,
+       0x00bbbb00bb00bbbb, 0x00e3e300e300e3e3, 0x0040400040004040,
+       0x004f4f004f004f4f,
+};
+
+const u64 camellia_sp00444404[256] = {
+       0x0000707070700070, 0x00002c2c2c2c002c, 0x0000b3b3b3b300b3,
+       0x0000c0c0c0c000c0, 0x0000e4e4e4e400e4, 0x0000575757570057,
+       0x0000eaeaeaea00ea, 0x0000aeaeaeae00ae, 0x0000232323230023,
+       0x00006b6b6b6b006b, 0x0000454545450045, 0x0000a5a5a5a500a5,
+       0x0000edededed00ed, 0x00004f4f4f4f004f, 0x00001d1d1d1d001d,
+       0x0000929292920092, 0x0000868686860086, 0x0000afafafaf00af,
+       0x00007c7c7c7c007c, 0x00001f1f1f1f001f, 0x00003e3e3e3e003e,
+       0x0000dcdcdcdc00dc, 0x00005e5e5e5e005e, 0x00000b0b0b0b000b,
+       0x0000a6a6a6a600a6, 0x0000393939390039, 0x0000d5d5d5d500d5,
+       0x00005d5d5d5d005d, 0x0000d9d9d9d900d9, 0x00005a5a5a5a005a,
+       0x0000515151510051, 0x00006c6c6c6c006c, 0x00008b8b8b8b008b,
+       0x00009a9a9a9a009a, 0x0000fbfbfbfb00fb, 0x0000b0b0b0b000b0,
+       0x0000747474740074, 0x00002b2b2b2b002b, 0x0000f0f0f0f000f0,
+       0x0000848484840084, 0x0000dfdfdfdf00df, 0x0000cbcbcbcb00cb,
+       0x0000343434340034, 0x0000767676760076, 0x00006d6d6d6d006d,
+       0x0000a9a9a9a900a9, 0x0000d1d1d1d100d1, 0x0000040404040004,
+       0x0000141414140014, 0x00003a3a3a3a003a, 0x0000dededede00de,
+       0x0000111111110011, 0x0000323232320032, 0x00009c9c9c9c009c,
+       0x0000535353530053, 0x0000f2f2f2f200f2, 0x0000fefefefe00fe,
+       0x0000cfcfcfcf00cf, 0x0000c3c3c3c300c3, 0x00007a7a7a7a007a,
+       0x0000242424240024, 0x0000e8e8e8e800e8, 0x0000606060600060,
+       0x0000696969690069, 0x0000aaaaaaaa00aa, 0x0000a0a0a0a000a0,
+       0x0000a1a1a1a100a1, 0x0000626262620062, 0x0000545454540054,
+       0x00001e1e1e1e001e, 0x0000e0e0e0e000e0, 0x0000646464640064,
+       0x0000101010100010, 0x0000000000000000, 0x0000a3a3a3a300a3,
+       0x0000757575750075, 0x00008a8a8a8a008a, 0x0000e6e6e6e600e6,
+       0x0000090909090009, 0x0000dddddddd00dd, 0x0000878787870087,
+       0x0000838383830083, 0x0000cdcdcdcd00cd, 0x0000909090900090,
+       0x0000737373730073, 0x0000f6f6f6f600f6, 0x00009d9d9d9d009d,
+       0x0000bfbfbfbf00bf, 0x0000525252520052, 0x0000d8d8d8d800d8,
+       0x0000c8c8c8c800c8, 0x0000c6c6c6c600c6, 0x0000818181810081,
+       0x00006f6f6f6f006f, 0x0000131313130013, 0x0000636363630063,
+       0x0000e9e9e9e900e9, 0x0000a7a7a7a700a7, 0x00009f9f9f9f009f,
+       0x0000bcbcbcbc00bc, 0x0000292929290029, 0x0000f9f9f9f900f9,
+       0x00002f2f2f2f002f, 0x0000b4b4b4b400b4, 0x0000787878780078,
+       0x0000060606060006, 0x0000e7e7e7e700e7, 0x0000717171710071,
+       0x0000d4d4d4d400d4, 0x0000abababab00ab, 0x0000888888880088,
+       0x00008d8d8d8d008d, 0x0000727272720072, 0x0000b9b9b9b900b9,
+       0x0000f8f8f8f800f8, 0x0000acacacac00ac, 0x0000363636360036,
+       0x00002a2a2a2a002a, 0x00003c3c3c3c003c, 0x0000f1f1f1f100f1,
+       0x0000404040400040, 0x0000d3d3d3d300d3, 0x0000bbbbbbbb00bb,
+       0x0000434343430043, 0x0000151515150015, 0x0000adadadad00ad,
+       0x0000777777770077, 0x0000808080800080, 0x0000828282820082,
+       0x0000ecececec00ec, 0x0000272727270027, 0x0000e5e5e5e500e5,
+       0x0000858585850085, 0x0000353535350035, 0x00000c0c0c0c000c,
+       0x0000414141410041, 0x0000efefefef00ef, 0x0000939393930093,
+       0x0000191919190019, 0x0000212121210021, 0x00000e0e0e0e000e,
+       0x00004e4e4e4e004e, 0x0000656565650065, 0x0000bdbdbdbd00bd,
+       0x0000b8b8b8b800b8, 0x00008f8f8f8f008f, 0x0000ebebebeb00eb,
+       0x0000cececece00ce, 0x0000303030300030, 0x00005f5f5f5f005f,
+       0x0000c5c5c5c500c5, 0x00001a1a1a1a001a, 0x0000e1e1e1e100e1,
+       0x0000cacacaca00ca, 0x0000474747470047, 0x00003d3d3d3d003d,
+       0x0000010101010001, 0x0000d6d6d6d600d6, 0x0000565656560056,
+       0x00004d4d4d4d004d, 0x00000d0d0d0d000d, 0x0000666666660066,
+       0x0000cccccccc00cc, 0x00002d2d2d2d002d, 0x0000121212120012,
+       0x0000202020200020, 0x0000b1b1b1b100b1, 0x0000999999990099,
+       0x00004c4c4c4c004c, 0x0000c2c2c2c200c2, 0x00007e7e7e7e007e,
+       0x0000050505050005, 0x0000b7b7b7b700b7, 0x0000313131310031,
+       0x0000171717170017, 0x0000d7d7d7d700d7, 0x0000585858580058,
+       0x0000616161610061, 0x00001b1b1b1b001b, 0x00001c1c1c1c001c,
+       0x00000f0f0f0f000f, 0x0000161616160016, 0x0000181818180018,
+       0x0000222222220022, 0x0000444444440044, 0x0000b2b2b2b200b2,
+       0x0000b5b5b5b500b5, 0x0000919191910091, 0x0000080808080008,
+       0x0000a8a8a8a800a8, 0x0000fcfcfcfc00fc, 0x0000505050500050,
+       0x0000d0d0d0d000d0, 0x00007d7d7d7d007d, 0x0000898989890089,
+       0x0000979797970097, 0x00005b5b5b5b005b, 0x0000959595950095,
+       0x0000ffffffff00ff, 0x0000d2d2d2d200d2, 0x0000c4c4c4c400c4,
+       0x0000484848480048, 0x0000f7f7f7f700f7, 0x0000dbdbdbdb00db,
+       0x0000030303030003, 0x0000dadadada00da, 0x00003f3f3f3f003f,
+       0x0000949494940094, 0x00005c5c5c5c005c, 0x0000020202020002,
+       0x00004a4a4a4a004a, 0x0000333333330033, 0x0000676767670067,
+       0x0000f3f3f3f300f3, 0x00007f7f7f7f007f, 0x0000e2e2e2e200e2,
+       0x00009b9b9b9b009b, 0x0000262626260026, 0x0000373737370037,
+       0x00003b3b3b3b003b, 0x0000969696960096, 0x00004b4b4b4b004b,
+       0x0000bebebebe00be, 0x00002e2e2e2e002e, 0x0000797979790079,
+       0x00008c8c8c8c008c, 0x00006e6e6e6e006e, 0x00008e8e8e8e008e,
+       0x0000f5f5f5f500f5, 0x0000b6b6b6b600b6, 0x0000fdfdfdfd00fd,
+       0x0000595959590059, 0x0000989898980098, 0x00006a6a6a6a006a,
+       0x0000464646460046, 0x0000babababa00ba, 0x0000252525250025,
+       0x0000424242420042, 0x0000a2a2a2a200a2, 0x0000fafafafa00fa,
+       0x0000070707070007, 0x0000555555550055, 0x0000eeeeeeee00ee,
+       0x00000a0a0a0a000a, 0x0000494949490049, 0x0000686868680068,
+       0x0000383838380038, 0x0000a4a4a4a400a4, 0x0000282828280028,
+       0x00007b7b7b7b007b, 0x0000c9c9c9c900c9, 0x0000c1c1c1c100c1,
+       0x0000e3e3e3e300e3, 0x0000f4f4f4f400f4, 0x0000c7c7c7c700c7,
+       0x00009e9e9e9e009e,
+};
+
+const u64 camellia_sp02220222[256] = {
+       0x00e0e0e000e0e0e0, 0x0005050500050505, 0x0058585800585858,
+       0x00d9d9d900d9d9d9, 0x0067676700676767, 0x004e4e4e004e4e4e,
+       0x0081818100818181, 0x00cbcbcb00cbcbcb, 0x00c9c9c900c9c9c9,
+       0x000b0b0b000b0b0b, 0x00aeaeae00aeaeae, 0x006a6a6a006a6a6a,
+       0x00d5d5d500d5d5d5, 0x0018181800181818, 0x005d5d5d005d5d5d,
+       0x0082828200828282, 0x0046464600464646, 0x00dfdfdf00dfdfdf,
+       0x00d6d6d600d6d6d6, 0x0027272700272727, 0x008a8a8a008a8a8a,
+       0x0032323200323232, 0x004b4b4b004b4b4b, 0x0042424200424242,
+       0x00dbdbdb00dbdbdb, 0x001c1c1c001c1c1c, 0x009e9e9e009e9e9e,
+       0x009c9c9c009c9c9c, 0x003a3a3a003a3a3a, 0x00cacaca00cacaca,
+       0x0025252500252525, 0x007b7b7b007b7b7b, 0x000d0d0d000d0d0d,
+       0x0071717100717171, 0x005f5f5f005f5f5f, 0x001f1f1f001f1f1f,
+       0x00f8f8f800f8f8f8, 0x00d7d7d700d7d7d7, 0x003e3e3e003e3e3e,
+       0x009d9d9d009d9d9d, 0x007c7c7c007c7c7c, 0x0060606000606060,
+       0x00b9b9b900b9b9b9, 0x00bebebe00bebebe, 0x00bcbcbc00bcbcbc,
+       0x008b8b8b008b8b8b, 0x0016161600161616, 0x0034343400343434,
+       0x004d4d4d004d4d4d, 0x00c3c3c300c3c3c3, 0x0072727200727272,
+       0x0095959500959595, 0x00ababab00ababab, 0x008e8e8e008e8e8e,
+       0x00bababa00bababa, 0x007a7a7a007a7a7a, 0x00b3b3b300b3b3b3,
+       0x0002020200020202, 0x00b4b4b400b4b4b4, 0x00adadad00adadad,
+       0x00a2a2a200a2a2a2, 0x00acacac00acacac, 0x00d8d8d800d8d8d8,
+       0x009a9a9a009a9a9a, 0x0017171700171717, 0x001a1a1a001a1a1a,
+       0x0035353500353535, 0x00cccccc00cccccc, 0x00f7f7f700f7f7f7,
+       0x0099999900999999, 0x0061616100616161, 0x005a5a5a005a5a5a,
+       0x00e8e8e800e8e8e8, 0x0024242400242424, 0x0056565600565656,
+       0x0040404000404040, 0x00e1e1e100e1e1e1, 0x0063636300636363,
+       0x0009090900090909, 0x0033333300333333, 0x00bfbfbf00bfbfbf,
+       0x0098989800989898, 0x0097979700979797, 0x0085858500858585,
+       0x0068686800686868, 0x00fcfcfc00fcfcfc, 0x00ececec00ececec,
+       0x000a0a0a000a0a0a, 0x00dadada00dadada, 0x006f6f6f006f6f6f,
+       0x0053535300535353, 0x0062626200626262, 0x00a3a3a300a3a3a3,
+       0x002e2e2e002e2e2e, 0x0008080800080808, 0x00afafaf00afafaf,
+       0x0028282800282828, 0x00b0b0b000b0b0b0, 0x0074747400747474,
+       0x00c2c2c200c2c2c2, 0x00bdbdbd00bdbdbd, 0x0036363600363636,
+       0x0022222200222222, 0x0038383800383838, 0x0064646400646464,
+       0x001e1e1e001e1e1e, 0x0039393900393939, 0x002c2c2c002c2c2c,
+       0x00a6a6a600a6a6a6, 0x0030303000303030, 0x00e5e5e500e5e5e5,
+       0x0044444400444444, 0x00fdfdfd00fdfdfd, 0x0088888800888888,
+       0x009f9f9f009f9f9f, 0x0065656500656565, 0x0087878700878787,
+       0x006b6b6b006b6b6b, 0x00f4f4f400f4f4f4, 0x0023232300232323,
+       0x0048484800484848, 0x0010101000101010, 0x00d1d1d100d1d1d1,
+       0x0051515100515151, 0x00c0c0c000c0c0c0, 0x00f9f9f900f9f9f9,
+       0x00d2d2d200d2d2d2, 0x00a0a0a000a0a0a0, 0x0055555500555555,
+       0x00a1a1a100a1a1a1, 0x0041414100414141, 0x00fafafa00fafafa,
+       0x0043434300434343, 0x0013131300131313, 0x00c4c4c400c4c4c4,
+       0x002f2f2f002f2f2f, 0x00a8a8a800a8a8a8, 0x00b6b6b600b6b6b6,
+       0x003c3c3c003c3c3c, 0x002b2b2b002b2b2b, 0x00c1c1c100c1c1c1,
+       0x00ffffff00ffffff, 0x00c8c8c800c8c8c8, 0x00a5a5a500a5a5a5,
+       0x0020202000202020, 0x0089898900898989, 0x0000000000000000,
+       0x0090909000909090, 0x0047474700474747, 0x00efefef00efefef,
+       0x00eaeaea00eaeaea, 0x00b7b7b700b7b7b7, 0x0015151500151515,
+       0x0006060600060606, 0x00cdcdcd00cdcdcd, 0x00b5b5b500b5b5b5,
+       0x0012121200121212, 0x007e7e7e007e7e7e, 0x00bbbbbb00bbbbbb,
+       0x0029292900292929, 0x000f0f0f000f0f0f, 0x00b8b8b800b8b8b8,
+       0x0007070700070707, 0x0004040400040404, 0x009b9b9b009b9b9b,
+       0x0094949400949494, 0x0021212100212121, 0x0066666600666666,
+       0x00e6e6e600e6e6e6, 0x00cecece00cecece, 0x00ededed00ededed,
+       0x00e7e7e700e7e7e7, 0x003b3b3b003b3b3b, 0x00fefefe00fefefe,
+       0x007f7f7f007f7f7f, 0x00c5c5c500c5c5c5, 0x00a4a4a400a4a4a4,
+       0x0037373700373737, 0x00b1b1b100b1b1b1, 0x004c4c4c004c4c4c,
+       0x0091919100919191, 0x006e6e6e006e6e6e, 0x008d8d8d008d8d8d,
+       0x0076767600767676, 0x0003030300030303, 0x002d2d2d002d2d2d,
+       0x00dedede00dedede, 0x0096969600969696, 0x0026262600262626,
+       0x007d7d7d007d7d7d, 0x00c6c6c600c6c6c6, 0x005c5c5c005c5c5c,
+       0x00d3d3d300d3d3d3, 0x00f2f2f200f2f2f2, 0x004f4f4f004f4f4f,
+       0x0019191900191919, 0x003f3f3f003f3f3f, 0x00dcdcdc00dcdcdc,
+       0x0079797900797979, 0x001d1d1d001d1d1d, 0x0052525200525252,
+       0x00ebebeb00ebebeb, 0x00f3f3f300f3f3f3, 0x006d6d6d006d6d6d,
+       0x005e5e5e005e5e5e, 0x00fbfbfb00fbfbfb, 0x0069696900696969,
+       0x00b2b2b200b2b2b2, 0x00f0f0f000f0f0f0, 0x0031313100313131,
+       0x000c0c0c000c0c0c, 0x00d4d4d400d4d4d4, 0x00cfcfcf00cfcfcf,
+       0x008c8c8c008c8c8c, 0x00e2e2e200e2e2e2, 0x0075757500757575,
+       0x00a9a9a900a9a9a9, 0x004a4a4a004a4a4a, 0x0057575700575757,
+       0x0084848400848484, 0x0011111100111111, 0x0045454500454545,
+       0x001b1b1b001b1b1b, 0x00f5f5f500f5f5f5, 0x00e4e4e400e4e4e4,
+       0x000e0e0e000e0e0e, 0x0073737300737373, 0x00aaaaaa00aaaaaa,
+       0x00f1f1f100f1f1f1, 0x00dddddd00dddddd, 0x0059595900595959,
+       0x0014141400141414, 0x006c6c6c006c6c6c, 0x0092929200929292,
+       0x0054545400545454, 0x00d0d0d000d0d0d0, 0x0078787800787878,
+       0x0070707000707070, 0x00e3e3e300e3e3e3, 0x0049494900494949,
+       0x0080808000808080, 0x0050505000505050, 0x00a7a7a700a7a7a7,
+       0x00f6f6f600f6f6f6, 0x0077777700777777, 0x0093939300939393,
+       0x0086868600868686, 0x0083838300838383, 0x002a2a2a002a2a2a,
+       0x00c7c7c700c7c7c7, 0x005b5b5b005b5b5b, 0x00e9e9e900e9e9e9,
+       0x00eeeeee00eeeeee, 0x008f8f8f008f8f8f, 0x0001010100010101,
+       0x003d3d3d003d3d3d,
+};
+
+const u64 camellia_sp30333033[256] = {
+       0x3800383838003838, 0x4100414141004141, 0x1600161616001616,
+       0x7600767676007676, 0xd900d9d9d900d9d9, 0x9300939393009393,
+       0x6000606060006060, 0xf200f2f2f200f2f2, 0x7200727272007272,
+       0xc200c2c2c200c2c2, 0xab00ababab00abab, 0x9a009a9a9a009a9a,
+       0x7500757575007575, 0x0600060606000606, 0x5700575757005757,
+       0xa000a0a0a000a0a0, 0x9100919191009191, 0xf700f7f7f700f7f7,
+       0xb500b5b5b500b5b5, 0xc900c9c9c900c9c9, 0xa200a2a2a200a2a2,
+       0x8c008c8c8c008c8c, 0xd200d2d2d200d2d2, 0x9000909090009090,
+       0xf600f6f6f600f6f6, 0x0700070707000707, 0xa700a7a7a700a7a7,
+       0x2700272727002727, 0x8e008e8e8e008e8e, 0xb200b2b2b200b2b2,
+       0x4900494949004949, 0xde00dedede00dede, 0x4300434343004343,
+       0x5c005c5c5c005c5c, 0xd700d7d7d700d7d7, 0xc700c7c7c700c7c7,
+       0x3e003e3e3e003e3e, 0xf500f5f5f500f5f5, 0x8f008f8f8f008f8f,
+       0x6700676767006767, 0x1f001f1f1f001f1f, 0x1800181818001818,
+       0x6e006e6e6e006e6e, 0xaf00afafaf00afaf, 0x2f002f2f2f002f2f,
+       0xe200e2e2e200e2e2, 0x8500858585008585, 0x0d000d0d0d000d0d,
+       0x5300535353005353, 0xf000f0f0f000f0f0, 0x9c009c9c9c009c9c,
+       0x6500656565006565, 0xea00eaeaea00eaea, 0xa300a3a3a300a3a3,
+       0xae00aeaeae00aeae, 0x9e009e9e9e009e9e, 0xec00ececec00ecec,
+       0x8000808080008080, 0x2d002d2d2d002d2d, 0x6b006b6b6b006b6b,
+       0xa800a8a8a800a8a8, 0x2b002b2b2b002b2b, 0x3600363636003636,
+       0xa600a6a6a600a6a6, 0xc500c5c5c500c5c5, 0x8600868686008686,
+       0x4d004d4d4d004d4d, 0x3300333333003333, 0xfd00fdfdfd00fdfd,
+       0x6600666666006666, 0x5800585858005858, 0x9600969696009696,
+       0x3a003a3a3a003a3a, 0x0900090909000909, 0x9500959595009595,
+       0x1000101010001010, 0x7800787878007878, 0xd800d8d8d800d8d8,
+       0x4200424242004242, 0xcc00cccccc00cccc, 0xef00efefef00efef,
+       0x2600262626002626, 0xe500e5e5e500e5e5, 0x6100616161006161,
+       0x1a001a1a1a001a1a, 0x3f003f3f3f003f3f, 0x3b003b3b3b003b3b,
+       0x8200828282008282, 0xb600b6b6b600b6b6, 0xdb00dbdbdb00dbdb,
+       0xd400d4d4d400d4d4, 0x9800989898009898, 0xe800e8e8e800e8e8,
+       0x8b008b8b8b008b8b, 0x0200020202000202, 0xeb00ebebeb00ebeb,
+       0x0a000a0a0a000a0a, 0x2c002c2c2c002c2c, 0x1d001d1d1d001d1d,
+       0xb000b0b0b000b0b0, 0x6f006f6f6f006f6f, 0x8d008d8d8d008d8d,
+       0x8800888888008888, 0x0e000e0e0e000e0e, 0x1900191919001919,
+       0x8700878787008787, 0x4e004e4e4e004e4e, 0x0b000b0b0b000b0b,
+       0xa900a9a9a900a9a9, 0x0c000c0c0c000c0c, 0x7900797979007979,
+       0x1100111111001111, 0x7f007f7f7f007f7f, 0x2200222222002222,
+       0xe700e7e7e700e7e7, 0x5900595959005959, 0xe100e1e1e100e1e1,
+       0xda00dadada00dada, 0x3d003d3d3d003d3d, 0xc800c8c8c800c8c8,
+       0x1200121212001212, 0x0400040404000404, 0x7400747474007474,
+       0x5400545454005454, 0x3000303030003030, 0x7e007e7e7e007e7e,
+       0xb400b4b4b400b4b4, 0x2800282828002828, 0x5500555555005555,
+       0x6800686868006868, 0x5000505050005050, 0xbe00bebebe00bebe,
+       0xd000d0d0d000d0d0, 0xc400c4c4c400c4c4, 0x3100313131003131,
+       0xcb00cbcbcb00cbcb, 0x2a002a2a2a002a2a, 0xad00adadad00adad,
+       0x0f000f0f0f000f0f, 0xca00cacaca00caca, 0x7000707070007070,
+       0xff00ffffff00ffff, 0x3200323232003232, 0x6900696969006969,
+       0x0800080808000808, 0x6200626262006262, 0x0000000000000000,
+       0x2400242424002424, 0xd100d1d1d100d1d1, 0xfb00fbfbfb00fbfb,
+       0xba00bababa00baba, 0xed00ededed00eded, 0x4500454545004545,
+       0x8100818181008181, 0x7300737373007373, 0x6d006d6d6d006d6d,
+       0x8400848484008484, 0x9f009f9f9f009f9f, 0xee00eeeeee00eeee,
+       0x4a004a4a4a004a4a, 0xc300c3c3c300c3c3, 0x2e002e2e2e002e2e,
+       0xc100c1c1c100c1c1, 0x0100010101000101, 0xe600e6e6e600e6e6,
+       0x2500252525002525, 0x4800484848004848, 0x9900999999009999,
+       0xb900b9b9b900b9b9, 0xb300b3b3b300b3b3, 0x7b007b7b7b007b7b,
+       0xf900f9f9f900f9f9, 0xce00cecece00cece, 0xbf00bfbfbf00bfbf,
+       0xdf00dfdfdf00dfdf, 0x7100717171007171, 0x2900292929002929,
+       0xcd00cdcdcd00cdcd, 0x6c006c6c6c006c6c, 0x1300131313001313,
+       0x6400646464006464, 0x9b009b9b9b009b9b, 0x6300636363006363,
+       0x9d009d9d9d009d9d, 0xc000c0c0c000c0c0, 0x4b004b4b4b004b4b,
+       0xb700b7b7b700b7b7, 0xa500a5a5a500a5a5, 0x8900898989008989,
+       0x5f005f5f5f005f5f, 0xb100b1b1b100b1b1, 0x1700171717001717,
+       0xf400f4f4f400f4f4, 0xbc00bcbcbc00bcbc, 0xd300d3d3d300d3d3,
+       0x4600464646004646, 0xcf00cfcfcf00cfcf, 0x3700373737003737,
+       0x5e005e5e5e005e5e, 0x4700474747004747, 0x9400949494009494,
+       0xfa00fafafa00fafa, 0xfc00fcfcfc00fcfc, 0x5b005b5b5b005b5b,
+       0x9700979797009797, 0xfe00fefefe00fefe, 0x5a005a5a5a005a5a,
+       0xac00acacac00acac, 0x3c003c3c3c003c3c, 0x4c004c4c4c004c4c,
+       0x0300030303000303, 0x3500353535003535, 0xf300f3f3f300f3f3,
+       0x2300232323002323, 0xb800b8b8b800b8b8, 0x5d005d5d5d005d5d,
+       0x6a006a6a6a006a6a, 0x9200929292009292, 0xd500d5d5d500d5d5,
+       0x2100212121002121, 0x4400444444004444, 0x5100515151005151,
+       0xc600c6c6c600c6c6, 0x7d007d7d7d007d7d, 0x3900393939003939,
+       0x8300838383008383, 0xdc00dcdcdc00dcdc, 0xaa00aaaaaa00aaaa,
+       0x7c007c7c7c007c7c, 0x7700777777007777, 0x5600565656005656,
+       0x0500050505000505, 0x1b001b1b1b001b1b, 0xa400a4a4a400a4a4,
+       0x1500151515001515, 0x3400343434003434, 0x1e001e1e1e001e1e,
+       0x1c001c1c1c001c1c, 0xf800f8f8f800f8f8, 0x5200525252005252,
+       0x2000202020002020, 0x1400141414001414, 0xe900e9e9e900e9e9,
+       0xbd00bdbdbd00bdbd, 0xdd00dddddd00dddd, 0xe400e4e4e400e4e4,
+       0xa100a1a1a100a1a1, 0xe000e0e0e000e0e0, 0x8a008a8a8a008a8a,
+       0xf100f1f1f100f1f1, 0xd600d6d6d600d6d6, 0x7a007a7a7a007a7a,
+       0xbb00bbbbbb00bbbb, 0xe300e3e3e300e3e3, 0x4000404040004040,
+       0x4f004f4f4f004f4f,
+};
+
+const u64 camellia_sp44044404[256] = {
+       0x7070007070700070, 0x2c2c002c2c2c002c, 0xb3b300b3b3b300b3,
+       0xc0c000c0c0c000c0, 0xe4e400e4e4e400e4, 0x5757005757570057,
+       0xeaea00eaeaea00ea, 0xaeae00aeaeae00ae, 0x2323002323230023,
+       0x6b6b006b6b6b006b, 0x4545004545450045, 0xa5a500a5a5a500a5,
+       0xeded00ededed00ed, 0x4f4f004f4f4f004f, 0x1d1d001d1d1d001d,
+       0x9292009292920092, 0x8686008686860086, 0xafaf00afafaf00af,
+       0x7c7c007c7c7c007c, 0x1f1f001f1f1f001f, 0x3e3e003e3e3e003e,
+       0xdcdc00dcdcdc00dc, 0x5e5e005e5e5e005e, 0x0b0b000b0b0b000b,
+       0xa6a600a6a6a600a6, 0x3939003939390039, 0xd5d500d5d5d500d5,
+       0x5d5d005d5d5d005d, 0xd9d900d9d9d900d9, 0x5a5a005a5a5a005a,
+       0x5151005151510051, 0x6c6c006c6c6c006c, 0x8b8b008b8b8b008b,
+       0x9a9a009a9a9a009a, 0xfbfb00fbfbfb00fb, 0xb0b000b0b0b000b0,
+       0x7474007474740074, 0x2b2b002b2b2b002b, 0xf0f000f0f0f000f0,
+       0x8484008484840084, 0xdfdf00dfdfdf00df, 0xcbcb00cbcbcb00cb,
+       0x3434003434340034, 0x7676007676760076, 0x6d6d006d6d6d006d,
+       0xa9a900a9a9a900a9, 0xd1d100d1d1d100d1, 0x0404000404040004,
+       0x1414001414140014, 0x3a3a003a3a3a003a, 0xdede00dedede00de,
+       0x1111001111110011, 0x3232003232320032, 0x9c9c009c9c9c009c,
+       0x5353005353530053, 0xf2f200f2f2f200f2, 0xfefe00fefefe00fe,
+       0xcfcf00cfcfcf00cf, 0xc3c300c3c3c300c3, 0x7a7a007a7a7a007a,
+       0x2424002424240024, 0xe8e800e8e8e800e8, 0x6060006060600060,
+       0x6969006969690069, 0xaaaa00aaaaaa00aa, 0xa0a000a0a0a000a0,
+       0xa1a100a1a1a100a1, 0x6262006262620062, 0x5454005454540054,
+       0x1e1e001e1e1e001e, 0xe0e000e0e0e000e0, 0x6464006464640064,
+       0x1010001010100010, 0x0000000000000000, 0xa3a300a3a3a300a3,
+       0x7575007575750075, 0x8a8a008a8a8a008a, 0xe6e600e6e6e600e6,
+       0x0909000909090009, 0xdddd00dddddd00dd, 0x8787008787870087,
+       0x8383008383830083, 0xcdcd00cdcdcd00cd, 0x9090009090900090,
+       0x7373007373730073, 0xf6f600f6f6f600f6, 0x9d9d009d9d9d009d,
+       0xbfbf00bfbfbf00bf, 0x5252005252520052, 0xd8d800d8d8d800d8,
+       0xc8c800c8c8c800c8, 0xc6c600c6c6c600c6, 0x8181008181810081,
+       0x6f6f006f6f6f006f, 0x1313001313130013, 0x6363006363630063,
+       0xe9e900e9e9e900e9, 0xa7a700a7a7a700a7, 0x9f9f009f9f9f009f,
+       0xbcbc00bcbcbc00bc, 0x2929002929290029, 0xf9f900f9f9f900f9,
+       0x2f2f002f2f2f002f, 0xb4b400b4b4b400b4, 0x7878007878780078,
+       0x0606000606060006, 0xe7e700e7e7e700e7, 0x7171007171710071,
+       0xd4d400d4d4d400d4, 0xabab00ababab00ab, 0x8888008888880088,
+       0x8d8d008d8d8d008d, 0x7272007272720072, 0xb9b900b9b9b900b9,
+       0xf8f800f8f8f800f8, 0xacac00acacac00ac, 0x3636003636360036,
+       0x2a2a002a2a2a002a, 0x3c3c003c3c3c003c, 0xf1f100f1f1f100f1,
+       0x4040004040400040, 0xd3d300d3d3d300d3, 0xbbbb00bbbbbb00bb,
+       0x4343004343430043, 0x1515001515150015, 0xadad00adadad00ad,
+       0x7777007777770077, 0x8080008080800080, 0x8282008282820082,
+       0xecec00ececec00ec, 0x2727002727270027, 0xe5e500e5e5e500e5,
+       0x8585008585850085, 0x3535003535350035, 0x0c0c000c0c0c000c,
+       0x4141004141410041, 0xefef00efefef00ef, 0x9393009393930093,
+       0x1919001919190019, 0x2121002121210021, 0x0e0e000e0e0e000e,
+       0x4e4e004e4e4e004e, 0x6565006565650065, 0xbdbd00bdbdbd00bd,
+       0xb8b800b8b8b800b8, 0x8f8f008f8f8f008f, 0xebeb00ebebeb00eb,
+       0xcece00cecece00ce, 0x3030003030300030, 0x5f5f005f5f5f005f,
+       0xc5c500c5c5c500c5, 0x1a1a001a1a1a001a, 0xe1e100e1e1e100e1,
+       0xcaca00cacaca00ca, 0x4747004747470047, 0x3d3d003d3d3d003d,
+       0x0101000101010001, 0xd6d600d6d6d600d6, 0x5656005656560056,
+       0x4d4d004d4d4d004d, 0x0d0d000d0d0d000d, 0x6666006666660066,
+       0xcccc00cccccc00cc, 0x2d2d002d2d2d002d, 0x1212001212120012,
+       0x2020002020200020, 0xb1b100b1b1b100b1, 0x9999009999990099,
+       0x4c4c004c4c4c004c, 0xc2c200c2c2c200c2, 0x7e7e007e7e7e007e,
+       0x0505000505050005, 0xb7b700b7b7b700b7, 0x3131003131310031,
+       0x1717001717170017, 0xd7d700d7d7d700d7, 0x5858005858580058,
+       0x6161006161610061, 0x1b1b001b1b1b001b, 0x1c1c001c1c1c001c,
+       0x0f0f000f0f0f000f, 0x1616001616160016, 0x1818001818180018,
+       0x2222002222220022, 0x4444004444440044, 0xb2b200b2b2b200b2,
+       0xb5b500b5b5b500b5, 0x9191009191910091, 0x0808000808080008,
+       0xa8a800a8a8a800a8, 0xfcfc00fcfcfc00fc, 0x5050005050500050,
+       0xd0d000d0d0d000d0, 0x7d7d007d7d7d007d, 0x8989008989890089,
+       0x9797009797970097, 0x5b5b005b5b5b005b, 0x9595009595950095,
+       0xffff00ffffff00ff, 0xd2d200d2d2d200d2, 0xc4c400c4c4c400c4,
+       0x4848004848480048, 0xf7f700f7f7f700f7, 0xdbdb00dbdbdb00db,
+       0x0303000303030003, 0xdada00dadada00da, 0x3f3f003f3f3f003f,
+       0x9494009494940094, 0x5c5c005c5c5c005c, 0x0202000202020002,
+       0x4a4a004a4a4a004a, 0x3333003333330033, 0x6767006767670067,
+       0xf3f300f3f3f300f3, 0x7f7f007f7f7f007f, 0xe2e200e2e2e200e2,
+       0x9b9b009b9b9b009b, 0x2626002626260026, 0x3737003737370037,
+       0x3b3b003b3b3b003b, 0x9696009696960096, 0x4b4b004b4b4b004b,
+       0xbebe00bebebe00be, 0x2e2e002e2e2e002e, 0x7979007979790079,
+       0x8c8c008c8c8c008c, 0x6e6e006e6e6e006e, 0x8e8e008e8e8e008e,
+       0xf5f500f5f5f500f5, 0xb6b600b6b6b600b6, 0xfdfd00fdfdfd00fd,
+       0x5959005959590059, 0x9898009898980098, 0x6a6a006a6a6a006a,
+       0x4646004646460046, 0xbaba00bababa00ba, 0x2525002525250025,
+       0x4242004242420042, 0xa2a200a2a2a200a2, 0xfafa00fafafa00fa,
+       0x0707000707070007, 0x5555005555550055, 0xeeee00eeeeee00ee,
+       0x0a0a000a0a0a000a, 0x4949004949490049, 0x6868006868680068,
+       0x3838003838380038, 0xa4a400a4a4a400a4, 0x2828002828280028,
+       0x7b7b007b7b7b007b, 0xc9c900c9c9c900c9, 0xc1c100c1c1c100c1,
+       0xe3e300e3e3e300e3, 0xf4f400f4f4f400f4, 0xc7c700c7c7c700c7,
+       0x9e9e009e9e9e009e,
+};
+
+const u64 camellia_sp11101110[256] = {
+       0x7070700070707000, 0x8282820082828200, 0x2c2c2c002c2c2c00,
+       0xececec00ececec00, 0xb3b3b300b3b3b300, 0x2727270027272700,
+       0xc0c0c000c0c0c000, 0xe5e5e500e5e5e500, 0xe4e4e400e4e4e400,
+       0x8585850085858500, 0x5757570057575700, 0x3535350035353500,
+       0xeaeaea00eaeaea00, 0x0c0c0c000c0c0c00, 0xaeaeae00aeaeae00,
+       0x4141410041414100, 0x2323230023232300, 0xefefef00efefef00,
+       0x6b6b6b006b6b6b00, 0x9393930093939300, 0x4545450045454500,
+       0x1919190019191900, 0xa5a5a500a5a5a500, 0x2121210021212100,
+       0xededed00ededed00, 0x0e0e0e000e0e0e00, 0x4f4f4f004f4f4f00,
+       0x4e4e4e004e4e4e00, 0x1d1d1d001d1d1d00, 0x6565650065656500,
+       0x9292920092929200, 0xbdbdbd00bdbdbd00, 0x8686860086868600,
+       0xb8b8b800b8b8b800, 0xafafaf00afafaf00, 0x8f8f8f008f8f8f00,
+       0x7c7c7c007c7c7c00, 0xebebeb00ebebeb00, 0x1f1f1f001f1f1f00,
+       0xcecece00cecece00, 0x3e3e3e003e3e3e00, 0x3030300030303000,
+       0xdcdcdc00dcdcdc00, 0x5f5f5f005f5f5f00, 0x5e5e5e005e5e5e00,
+       0xc5c5c500c5c5c500, 0x0b0b0b000b0b0b00, 0x1a1a1a001a1a1a00,
+       0xa6a6a600a6a6a600, 0xe1e1e100e1e1e100, 0x3939390039393900,
+       0xcacaca00cacaca00, 0xd5d5d500d5d5d500, 0x4747470047474700,
+       0x5d5d5d005d5d5d00, 0x3d3d3d003d3d3d00, 0xd9d9d900d9d9d900,
+       0x0101010001010100, 0x5a5a5a005a5a5a00, 0xd6d6d600d6d6d600,
+       0x5151510051515100, 0x5656560056565600, 0x6c6c6c006c6c6c00,
+       0x4d4d4d004d4d4d00, 0x8b8b8b008b8b8b00, 0x0d0d0d000d0d0d00,
+       0x9a9a9a009a9a9a00, 0x6666660066666600, 0xfbfbfb00fbfbfb00,
+       0xcccccc00cccccc00, 0xb0b0b000b0b0b000, 0x2d2d2d002d2d2d00,
+       0x7474740074747400, 0x1212120012121200, 0x2b2b2b002b2b2b00,
+       0x2020200020202000, 0xf0f0f000f0f0f000, 0xb1b1b100b1b1b100,
+       0x8484840084848400, 0x9999990099999900, 0xdfdfdf00dfdfdf00,
+       0x4c4c4c004c4c4c00, 0xcbcbcb00cbcbcb00, 0xc2c2c200c2c2c200,
+       0x3434340034343400, 0x7e7e7e007e7e7e00, 0x7676760076767600,
+       0x0505050005050500, 0x6d6d6d006d6d6d00, 0xb7b7b700b7b7b700,
+       0xa9a9a900a9a9a900, 0x3131310031313100, 0xd1d1d100d1d1d100,
+       0x1717170017171700, 0x0404040004040400, 0xd7d7d700d7d7d700,
+       0x1414140014141400, 0x5858580058585800, 0x3a3a3a003a3a3a00,
+       0x6161610061616100, 0xdedede00dedede00, 0x1b1b1b001b1b1b00,
+       0x1111110011111100, 0x1c1c1c001c1c1c00, 0x3232320032323200,
+       0x0f0f0f000f0f0f00, 0x9c9c9c009c9c9c00, 0x1616160016161600,
+       0x5353530053535300, 0x1818180018181800, 0xf2f2f200f2f2f200,
+       0x2222220022222200, 0xfefefe00fefefe00, 0x4444440044444400,
+       0xcfcfcf00cfcfcf00, 0xb2b2b200b2b2b200, 0xc3c3c300c3c3c300,
+       0xb5b5b500b5b5b500, 0x7a7a7a007a7a7a00, 0x9191910091919100,
+       0x2424240024242400, 0x0808080008080800, 0xe8e8e800e8e8e800,
+       0xa8a8a800a8a8a800, 0x6060600060606000, 0xfcfcfc00fcfcfc00,
+       0x6969690069696900, 0x5050500050505000, 0xaaaaaa00aaaaaa00,
+       0xd0d0d000d0d0d000, 0xa0a0a000a0a0a000, 0x7d7d7d007d7d7d00,
+       0xa1a1a100a1a1a100, 0x8989890089898900, 0x6262620062626200,
+       0x9797970097979700, 0x5454540054545400, 0x5b5b5b005b5b5b00,
+       0x1e1e1e001e1e1e00, 0x9595950095959500, 0xe0e0e000e0e0e000,
+       0xffffff00ffffff00, 0x6464640064646400, 0xd2d2d200d2d2d200,
+       0x1010100010101000, 0xc4c4c400c4c4c400, 0x0000000000000000,
+       0x4848480048484800, 0xa3a3a300a3a3a300, 0xf7f7f700f7f7f700,
+       0x7575750075757500, 0xdbdbdb00dbdbdb00, 0x8a8a8a008a8a8a00,
+       0x0303030003030300, 0xe6e6e600e6e6e600, 0xdadada00dadada00,
+       0x0909090009090900, 0x3f3f3f003f3f3f00, 0xdddddd00dddddd00,
+       0x9494940094949400, 0x8787870087878700, 0x5c5c5c005c5c5c00,
+       0x8383830083838300, 0x0202020002020200, 0xcdcdcd00cdcdcd00,
+       0x4a4a4a004a4a4a00, 0x9090900090909000, 0x3333330033333300,
+       0x7373730073737300, 0x6767670067676700, 0xf6f6f600f6f6f600,
+       0xf3f3f300f3f3f300, 0x9d9d9d009d9d9d00, 0x7f7f7f007f7f7f00,
+       0xbfbfbf00bfbfbf00, 0xe2e2e200e2e2e200, 0x5252520052525200,
+       0x9b9b9b009b9b9b00, 0xd8d8d800d8d8d800, 0x2626260026262600,
+       0xc8c8c800c8c8c800, 0x3737370037373700, 0xc6c6c600c6c6c600,
+       0x3b3b3b003b3b3b00, 0x8181810081818100, 0x9696960096969600,
+       0x6f6f6f006f6f6f00, 0x4b4b4b004b4b4b00, 0x1313130013131300,
+       0xbebebe00bebebe00, 0x6363630063636300, 0x2e2e2e002e2e2e00,
+       0xe9e9e900e9e9e900, 0x7979790079797900, 0xa7a7a700a7a7a700,
+       0x8c8c8c008c8c8c00, 0x9f9f9f009f9f9f00, 0x6e6e6e006e6e6e00,
+       0xbcbcbc00bcbcbc00, 0x8e8e8e008e8e8e00, 0x2929290029292900,
+       0xf5f5f500f5f5f500, 0xf9f9f900f9f9f900, 0xb6b6b600b6b6b600,
+       0x2f2f2f002f2f2f00, 0xfdfdfd00fdfdfd00, 0xb4b4b400b4b4b400,
+       0x5959590059595900, 0x7878780078787800, 0x9898980098989800,
+       0x0606060006060600, 0x6a6a6a006a6a6a00, 0xe7e7e700e7e7e700,
+       0x4646460046464600, 0x7171710071717100, 0xbababa00bababa00,
+       0xd4d4d400d4d4d400, 0x2525250025252500, 0xababab00ababab00,
+       0x4242420042424200, 0x8888880088888800, 0xa2a2a200a2a2a200,
+       0x8d8d8d008d8d8d00, 0xfafafa00fafafa00, 0x7272720072727200,
+       0x0707070007070700, 0xb9b9b900b9b9b900, 0x5555550055555500,
+       0xf8f8f800f8f8f800, 0xeeeeee00eeeeee00, 0xacacac00acacac00,
+       0x0a0a0a000a0a0a00, 0x3636360036363600, 0x4949490049494900,
+       0x2a2a2a002a2a2a00, 0x6868680068686800, 0x3c3c3c003c3c3c00,
+       0x3838380038383800, 0xf1f1f100f1f1f100, 0xa4a4a400a4a4a400,
+       0x4040400040404000, 0x2828280028282800, 0xd3d3d300d3d3d300,
+       0x7b7b7b007b7b7b00, 0xbbbbbb00bbbbbb00, 0xc9c9c900c9c9c900,
+       0x4343430043434300, 0xc1c1c100c1c1c100, 0x1515150015151500,
+       0xe3e3e300e3e3e300, 0xadadad00adadad00, 0xf4f4f400f4f4f400,
+       0x7777770077777700, 0xc7c7c700c7c7c700, 0x8080800080808000,
+       0x9e9e9e009e9e9e00,
+};
+
+/* key constants */
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+/* macros */
+#define ROLDQ(l, r, bits) ({ \
+       u64 t = l;                                      \
+       l = (l << bits) | (r >> (64 - bits));           \
+       r = (r << bits) | (t >> (64 - bits));           \
+})
+
+#define CAMELLIA_F(x, kl, kr, y) ({ \
+       u64 ii = x ^ (((u64)kl << 32) | kr);                            \
+       y = camellia_sp11101110[(uint8_t)ii];                           \
+       y ^= camellia_sp44044404[(uint8_t)(ii >> 8)];                   \
+       ii >>= 16;                                                      \
+       y ^= camellia_sp30333033[(uint8_t)ii];                          \
+       y ^= camellia_sp02220222[(uint8_t)(ii >> 8)];                   \
+       ii >>= 16;                                                      \
+       y ^= camellia_sp00444404[(uint8_t)ii];                          \
+       y ^= camellia_sp03303033[(uint8_t)(ii >> 8)];                   \
+       ii >>= 16;                                                      \
+       y ^= camellia_sp22000222[(uint8_t)ii];                          \
+       y ^= camellia_sp10011110[(uint8_t)(ii >> 8)];                   \
+       y = ror64(y, 32);                                               \
+})
+
+#define SET_SUBKEY_LR(INDEX, sRL) (subkey[(INDEX)] = ror64((sRL), 32))
+
+static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max)
+{
+       u64 kw4, tt;
+       u32 dw, tl, tr;
+
+       /* absorb kw2 to other subkeys */
+       /* round 2 */
+       subRL[3] ^= subRL[1];
+       /* round 4 */
+       subRL[5] ^= subRL[1];
+       /* round 6 */
+       subRL[7] ^= subRL[1];
+
+       subRL[1] ^= (subRL[1] & ~subRL[9]) << 32;
+       /* modified for FLinv(kl2) */
+       dw = (subRL[1] & subRL[9]) >> 32,
+               subRL[1] ^= rol32(dw, 1);
+
+       /* round 8 */
+       subRL[11] ^= subRL[1];
+       /* round 10 */
+       subRL[13] ^= subRL[1];
+       /* round 12 */
+       subRL[15] ^= subRL[1];
+
+       subRL[1] ^= (subRL[1] & ~subRL[17]) << 32;
+       /* modified for FLinv(kl4) */
+       dw = (subRL[1] & subRL[17]) >> 32,
+               subRL[1] ^= rol32(dw, 1);
+
+       /* round 14 */
+       subRL[19] ^= subRL[1];
+       /* round 16 */
+       subRL[21] ^= subRL[1];
+       /* round 18 */
+       subRL[23] ^= subRL[1];
+
+       if (max == 24) {
+               /* kw3 */
+               subRL[24] ^= subRL[1];
+
+               /* absorb kw4 to other subkeys */
+               kw4 = subRL[25];
+       } else {
+               subRL[1] ^= (subRL[1] & ~subRL[25]) << 32;
+               /* modified for FLinv(kl6) */
+               dw = (subRL[1] & subRL[25]) >> 32,
+                       subRL[1] ^= rol32(dw, 1);
+
+               /* round 20 */
+               subRL[27] ^= subRL[1];
+               /* round 22 */
+               subRL[29] ^= subRL[1];
+               /* round 24 */
+               subRL[31] ^= subRL[1];
+               /* kw3 */
+               subRL[32] ^= subRL[1];
+
+               /* absorb kw4 to other subkeys */
+               kw4 = subRL[33];
+               /* round 23 */
+               subRL[30] ^= kw4;
+               /* round 21 */
+               subRL[28] ^= kw4;
+               /* round 19 */
+               subRL[26] ^= kw4;
+
+               kw4 ^= (kw4 & ~subRL[24]) << 32;
+               /* modified for FL(kl5) */
+               dw = (kw4 & subRL[24]) >> 32,
+                       kw4 ^= rol32(dw, 1);
+       }
+
+       /* round 17 */
+       subRL[22] ^= kw4;
+       /* round 15 */
+       subRL[20] ^= kw4;
+       /* round 13 */
+       subRL[18] ^= kw4;
+
+       kw4 ^= (kw4 & ~subRL[16]) << 32;
+       /* modified for FL(kl3) */
+       dw = (kw4 & subRL[16]) >> 32,
+               kw4 ^= rol32(dw, 1);
+
+       /* round 11 */
+       subRL[14] ^= kw4;
+       /* round 9 */
+       subRL[12] ^= kw4;
+       /* round 7 */
+       subRL[10] ^= kw4;
+
+       kw4 ^= (kw4 & ~subRL[8]) << 32;
+       /* modified for FL(kl1) */
+       dw = (kw4 & subRL[8]) >> 32,
+               kw4 ^= rol32(dw, 1);
+
+       /* round 5 */
+       subRL[6] ^= kw4;
+       /* round 3 */
+       subRL[4] ^= kw4;
+       /* round 1 */
+       subRL[2] ^= kw4;
+       /* kw1 */
+       subRL[0] ^= kw4;
+
+       /* key XOR is end of F-function */
+       SET_SUBKEY_LR(0, subRL[0] ^ subRL[2]);                  /* kw1 */
+       SET_SUBKEY_LR(2, subRL[3]);                             /* round 1 */
+       SET_SUBKEY_LR(3, subRL[2] ^ subRL[4]);                  /* round 2 */
+       SET_SUBKEY_LR(4, subRL[3] ^ subRL[5]);                  /* round 3 */
+       SET_SUBKEY_LR(5, subRL[4] ^ subRL[6]);                  /* round 4 */
+       SET_SUBKEY_LR(6, subRL[5] ^ subRL[7]);                  /* round 5 */
+
+       tl = (subRL[10] >> 32) ^ (subRL[10] & ~subRL[8]);
+       dw = tl & (subRL[8] >> 32),                             /* FL(kl1) */
+               tr = subRL[10] ^ rol32(dw, 1);
+       tt = (tr | ((u64)tl << 32));
+
+       SET_SUBKEY_LR(7, subRL[6] ^ tt);                        /* round 6 */
+       SET_SUBKEY_LR(8, subRL[8]);                             /* FL(kl1) */
+       SET_SUBKEY_LR(9, subRL[9]);                             /* FLinv(kl2) */
+
+       tl = (subRL[7] >> 32) ^ (subRL[7] & ~subRL[9]);
+       dw = tl & (subRL[9] >> 32),                             /* FLinv(kl2) */
+               tr = subRL[7] ^ rol32(dw, 1);
+       tt = (tr | ((u64)tl << 32));
+
+       SET_SUBKEY_LR(10, subRL[11] ^ tt);                      /* round 7 */
+       SET_SUBKEY_LR(11, subRL[10] ^ subRL[12]);               /* round 8 */
+       SET_SUBKEY_LR(12, subRL[11] ^ subRL[13]);               /* round 9 */
+       SET_SUBKEY_LR(13, subRL[12] ^ subRL[14]);               /* round 10 */
+       SET_SUBKEY_LR(14, subRL[13] ^ subRL[15]);               /* round 11 */
+
+       tl = (subRL[18] >> 32) ^ (subRL[18] & ~subRL[16]);
+       dw = tl & (subRL[16] >> 32),                            /* FL(kl3) */
+               tr = subRL[18] ^ rol32(dw, 1);
+       tt = (tr | ((u64)tl << 32));
+
+       SET_SUBKEY_LR(15, subRL[14] ^ tt);                      /* round 12 */
+       SET_SUBKEY_LR(16, subRL[16]);                           /* FL(kl3) */
+       SET_SUBKEY_LR(17, subRL[17]);                           /* FLinv(kl4) */
+
+       tl = (subRL[15] >> 32) ^ (subRL[15] & ~subRL[17]);
+       dw = tl & (subRL[17] >> 32),                            /* FLinv(kl4) */
+               tr = subRL[15] ^ rol32(dw, 1);
+       tt = (tr | ((u64)tl << 32));
+
+       SET_SUBKEY_LR(18, subRL[19] ^ tt);                      /* round 13 */
+       SET_SUBKEY_LR(19, subRL[18] ^ subRL[20]);               /* round 14 */
+       SET_SUBKEY_LR(20, subRL[19] ^ subRL[21]);               /* round 15 */
+       SET_SUBKEY_LR(21, subRL[20] ^ subRL[22]);               /* round 16 */
+       SET_SUBKEY_LR(22, subRL[21] ^ subRL[23]);               /* round 17 */
+
+       if (max == 24) {
+               SET_SUBKEY_LR(23, subRL[22]);                   /* round 18 */
+               SET_SUBKEY_LR(24, subRL[24] ^ subRL[23]);       /* kw3 */
+       } else {
+               tl = (subRL[26] >> 32) ^ (subRL[26] & ~subRL[24]);
+               dw = tl & (subRL[24] >> 32),                    /* FL(kl5) */
+                       tr = subRL[26] ^ rol32(dw, 1);
+               tt = (tr | ((u64)tl << 32));
+
+               SET_SUBKEY_LR(23, subRL[22] ^ tt);              /* round 18 */
+               SET_SUBKEY_LR(24, subRL[24]);                   /* FL(kl5) */
+               SET_SUBKEY_LR(25, subRL[25]);                   /* FLinv(kl6) */
+
+               tl = (subRL[23] >> 32) ^ (subRL[23] & ~subRL[25]);
+               dw = tl & (subRL[25] >> 32),                    /* FLinv(kl6) */
+                       tr = subRL[23] ^ rol32(dw, 1);
+               tt = (tr | ((u64)tl << 32));
+
+               SET_SUBKEY_LR(26, subRL[27] ^ tt);              /* round 19 */
+               SET_SUBKEY_LR(27, subRL[26] ^ subRL[28]);       /* round 20 */
+               SET_SUBKEY_LR(28, subRL[27] ^ subRL[29]);       /* round 21 */
+               SET_SUBKEY_LR(29, subRL[28] ^ subRL[30]);       /* round 22 */
+               SET_SUBKEY_LR(30, subRL[29] ^ subRL[31]);       /* round 23 */
+               SET_SUBKEY_LR(31, subRL[30]);                   /* round 24 */
+               SET_SUBKEY_LR(32, subRL[32] ^ subRL[31]);       /* kw3 */
+       }
+}
+
+static void camellia_setup128(const unsigned char *key, u64 *subkey)
+{
+       u64 kl, kr, ww;
+       u64 subRL[26];
+
+       /**
+        *  k == kl || kr (|| is concatenation)
+        */
+       kl = get_unaligned_be64(key);
+       kr = get_unaligned_be64(key + 8);
+
+       /* generate KL dependent subkeys */
+       /* kw1 */
+       subRL[0] = kl;
+       /* kw2 */
+       subRL[1] = kr;
+
+       /* rotation left shift 15bit */
+       ROLDQ(kl, kr, 15);
+
+       /* k3 */
+       subRL[4] = kl;
+       /* k4 */
+       subRL[5] = kr;
+
+       /* rotation left shift 15+30bit */
+       ROLDQ(kl, kr, 30);
+
+       /* k7 */
+       subRL[10] = kl;
+       /* k8 */
+       subRL[11] = kr;
+
+       /* rotation left shift 15+30+15bit */
+       ROLDQ(kl, kr, 15);
+
+       /* k10 */
+       subRL[13] = kr;
+       /* rotation left shift 15+30+15+17 bit */
+       ROLDQ(kl, kr, 17);
+
+       /* kl3 */
+       subRL[16] = kl;
+       /* kl4 */
+       subRL[17] = kr;
+
+       /* rotation left shift 15+30+15+17+17 bit */
+       ROLDQ(kl, kr, 17);
+
+       /* k13 */
+       subRL[18] = kl;
+       /* k14 */
+       subRL[19] = kr;
+
+       /* rotation left shift 15+30+15+17+17+17 bit */
+       ROLDQ(kl, kr, 17);
+
+       /* k17 */
+       subRL[22] = kl;
+       /* k18 */
+       subRL[23] = kr;
+
+       /* generate KA */
+       kl = subRL[0];
+       kr = subRL[1];
+       CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww);
+       kr ^= ww;
+       CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl);
+
+       /* current status == (kll, klr, w0, w1) */
+       CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr);
+       kr ^= ww;
+       CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww);
+       kl ^= ww;
+
+       /* generate KA dependent subkeys */
+       /* k1, k2 */
+       subRL[2] = kl;
+       subRL[3] = kr;
+       ROLDQ(kl, kr, 15);
+       /* k5,k6 */
+       subRL[6] = kl;
+       subRL[7] = kr;
+       ROLDQ(kl, kr, 15);
+       /* kl1, kl2 */
+       subRL[8] = kl;
+       subRL[9] = kr;
+       ROLDQ(kl, kr, 15);
+       /* k9 */
+       subRL[12] = kl;
+       ROLDQ(kl, kr, 15);
+       /* k11, k12 */
+       subRL[14] = kl;
+       subRL[15] = kr;
+       ROLDQ(kl, kr, 34);
+       /* k15, k16 */
+       subRL[20] = kl;
+       subRL[21] = kr;
+       ROLDQ(kl, kr, 17);
+       /* kw3, kw4 */
+       subRL[24] = kl;
+       subRL[25] = kr;
+
+       camellia_setup_tail(subkey, subRL, 24);
+}
+
+static void camellia_setup256(const unsigned char *key, u64 *subkey)
+{
+       u64 kl, kr;                     /* left half of key */
+       u64 krl, krr;                   /* right half of key */
+       u64 ww;                         /* temporary variables */
+       u64 subRL[34];
+
+       /**
+        *  key = (kl || kr || krl || krr) (|| is concatenation)
+        */
+       kl = get_unaligned_be64(key);
+       kr = get_unaligned_be64(key + 8);
+       krl = get_unaligned_be64(key + 16);
+       krr = get_unaligned_be64(key + 24);
+
+       /* generate KL dependent subkeys */
+       /* kw1 */
+       subRL[0] = kl;
+       /* kw2 */
+       subRL[1] = kr;
+       ROLDQ(kl, kr, 45);
+       /* k9 */
+       subRL[12] = kl;
+       /* k10 */
+       subRL[13] = kr;
+       ROLDQ(kl, kr, 15);
+       /* kl3 */
+       subRL[16] = kl;
+       /* kl4 */
+       subRL[17] = kr;
+       ROLDQ(kl, kr, 17);
+       /* k17 */
+       subRL[22] = kl;
+       /* k18 */
+       subRL[23] = kr;
+       ROLDQ(kl, kr, 34);
+       /* k23 */
+       subRL[30] = kl;
+       /* k24 */
+       subRL[31] = kr;
+
+       /* generate KR dependent subkeys */
+       ROLDQ(krl, krr, 15);
+       /* k3 */
+       subRL[4] = krl;
+       /* k4 */
+       subRL[5] = krr;
+       ROLDQ(krl, krr, 15);
+       /* kl1 */
+       subRL[8] = krl;
+       /* kl2 */
+       subRL[9] = krr;
+       ROLDQ(krl, krr, 30);
+       /* k13 */
+       subRL[18] = krl;
+       /* k14 */
+       subRL[19] = krr;
+       ROLDQ(krl, krr, 34);
+       /* k19 */
+       subRL[26] = krl;
+       /* k20 */
+       subRL[27] = krr;
+       ROLDQ(krl, krr, 34);
+
+       /* generate KA */
+       kl = subRL[0] ^ krl;
+       kr = subRL[1] ^ krr;
+
+       CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww);
+       kr ^= ww;
+       CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl);
+       kl ^= krl;
+       CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr);
+       kr ^= ww ^ krr;
+       CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww);
+       kl ^= ww;
+
+       /* generate KB */
+       krl ^= kl;
+       krr ^= kr;
+       CAMELLIA_F(krl, CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, ww);
+       krr ^= ww;
+       CAMELLIA_F(krr, CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, ww);
+       krl ^= ww;
+
+       /* generate KA dependent subkeys */
+       ROLDQ(kl, kr, 15);
+       /* k5 */
+       subRL[6] = kl;
+       /* k6 */
+       subRL[7] = kr;
+       ROLDQ(kl, kr, 30);
+       /* k11 */
+       subRL[14] = kl;
+       /* k12 */
+       subRL[15] = kr;
+       /* rotation left shift 32bit */
+       ROLDQ(kl, kr, 32);
+       /* kl5 */
+       subRL[24] = kl;
+       /* kl6 */
+       subRL[25] = kr;
+       /* rotation left shift 17 from k11,k12 -> k21,k22 */
+       ROLDQ(kl, kr, 17);
+       /* k21 */
+       subRL[28] = kl;
+       /* k22 */
+       subRL[29] = kr;
+
+       /* generate KB dependent subkeys */
+       /* k1 */
+       subRL[2] = krl;
+       /* k2 */
+       subRL[3] = krr;
+       ROLDQ(krl, krr, 30);
+       /* k7 */
+       subRL[10] = krl;
+       /* k8 */
+       subRL[11] = krr;
+       ROLDQ(krl, krr, 30);
+       /* k15 */
+       subRL[20] = krl;
+       /* k16 */
+       subRL[21] = krr;
+       ROLDQ(krl, krr, 51);
+       /* kw3 */
+       subRL[32] = krl;
+       /* kw4 */
+       subRL[33] = krr;
+
+       camellia_setup_tail(subkey, subRL, 32);
+}
+
+static void camellia_setup192(const unsigned char *key, u64 *subkey)
+{
+       unsigned char kk[32];
+       u64 krl, krr;
+
+       memcpy(kk, key, 24);
+       memcpy((unsigned char *)&krl, key+16, 8);
+       krr = ~krl;
+       memcpy(kk+24, (unsigned char *)&krr, 8);
+       camellia_setup256(kk, subkey);
+}
+
+static int __camellia_setkey(struct camellia_ctx *cctx,
+                            const unsigned char *key,
+                            unsigned int key_len, u32 *flags)
+{
+       if (key_len != 16 && key_len != 24 && key_len != 32) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       cctx->key_length = key_len;
+
+       switch (key_len) {
+       case 16:
+               camellia_setup128(key, cctx->key_table);
+               break;
+       case 24:
+               camellia_setup192(key, cctx->key_table);
+               break;
+       case 32:
+               camellia_setup256(key, cctx->key_table);
+               break;
+       }
+
+       return 0;
+}
+
+static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+                          unsigned int key_len)
+{
+       return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len,
+                                &tfm->crt_flags);
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+                    void (*fn)(struct camellia_ctx *, u8 *, const u8 *),
+                    void (*fn_2way)(struct camellia_ctx *, u8 *, const u8 *))
+{
+       struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       unsigned int nbytes;
+       int err;
+
+       err = blkcipher_walk_virt(desc, walk);
+
+       while ((nbytes = walk->nbytes)) {
+               u8 *wsrc = walk->src.virt.addr;
+               u8 *wdst = walk->dst.virt.addr;
+
+               /* Process two block batch */
+               if (nbytes >= bsize * 2) {
+                       do {
+                               fn_2way(ctx, wdst, wsrc);
+
+                               wsrc += bsize * 2;
+                               wdst += bsize * 2;
+                               nbytes -= bsize * 2;
+                       } while (nbytes >= bsize * 2);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+
+               /* Handle leftovers */
+               do {
+                       fn(ctx, wdst, wsrc);
+
+                       wsrc += bsize;
+                       wdst += bsize;
+                       nbytes -= bsize;
+               } while (nbytes >= bsize);
+
+done:
+               err = blkcipher_walk_done(desc, walk, nbytes);
+       }
+
+       return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, camellia_enc_blk, camellia_enc_blk_2way);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, camellia_dec_blk, camellia_dec_blk_2way);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 *iv = (u128 *)walk->iv;
+
+       do {
+               u128_xor(dst, src, iv);
+               camellia_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
+               iv = dst;
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+       u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
+       return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while ((nbytes = walk.nbytes)) {
+               nbytes = __cbc_encrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 ivs[2 - 1];
+       u128 last_iv;
+
+       /* Start of the last block. */
+       src += nbytes / bsize - 1;
+       dst += nbytes / bsize - 1;
+
+       last_iv = *src;
+
+       /* Process two block batch */
+       if (nbytes >= bsize * 2) {
+               do {
+                       nbytes -= bsize * (2 - 1);
+                       src -= 2 - 1;
+                       dst -= 2 - 1;
+
+                       ivs[0] = src[0];
+
+                       camellia_dec_blk_2way(ctx, (u8 *)dst, (u8 *)src);
+
+                       u128_xor(dst + 1, dst + 1, ivs + 0);
+
+                       nbytes -= bsize;
+                       if (nbytes < bsize)
+                               goto done;
+
+                       u128_xor(dst, dst, src - 1);
+                       src -= 1;
+                       dst -= 1;
+               } while (nbytes >= bsize * 2);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       for (;;) {
+               camellia_dec_blk(ctx, (u8 *)dst, (u8 *)src);
+
+               nbytes -= bsize;
+               if (nbytes < bsize)
+                       break;
+
+               u128_xor(dst, dst, src - 1);
+               src -= 1;
+               dst -= 1;
+       }
+
+done:
+       u128_xor(dst, dst, (u128 *)walk->iv);
+       *(u128 *)walk->iv = last_iv;
+
+       return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while ((nbytes = walk.nbytes)) {
+               nbytes = __cbc_decrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static inline void u128_to_be128(be128 *dst, const u128 *src)
+{
+       dst->a = cpu_to_be64(src->a);
+       dst->b = cpu_to_be64(src->b);
+}
+
+static inline void be128_to_u128(u128 *dst, const be128 *src)
+{
+       dst->a = be64_to_cpu(src->a);
+       dst->b = be64_to_cpu(src->b);
+}
+
+static inline void u128_inc(u128 *i)
+{
+       i->b++;
+       if (!i->b)
+               i->a++;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+                           struct blkcipher_walk *walk)
+{
+       struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       u8 keystream[CAMELLIA_BLOCK_SIZE];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+       u128 ctrblk;
+
+       memcpy(keystream, src, nbytes);
+       camellia_enc_blk_xor(ctx, keystream, walk->iv);
+       memcpy(dst, keystream, nbytes);
+
+       be128_to_u128(&ctrblk, (be128 *)walk->iv);
+       u128_inc(&ctrblk);
+       u128_to_be128((be128 *)walk->iv, &ctrblk);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+                               struct blkcipher_walk *walk)
+{
+       struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 ctrblk;
+       be128 ctrblocks[2];
+
+       be128_to_u128(&ctrblk, (be128 *)walk->iv);
+
+       /* Process two block batch */
+       if (nbytes >= bsize * 2) {
+               do {
+                       if (dst != src) {
+                               dst[0] = src[0];
+                               dst[1] = src[1];
+                       }
+
+                       /* create ctrblks for parallel encrypt */
+                       u128_to_be128(&ctrblocks[0], &ctrblk);
+                       u128_inc(&ctrblk);
+                       u128_to_be128(&ctrblocks[1], &ctrblk);
+                       u128_inc(&ctrblk);
+
+                       camellia_enc_blk_xor_2way(ctx, (u8 *)dst,
+                                                (u8 *)ctrblocks);
+
+                       src += 2;
+                       dst += 2;
+                       nbytes -= bsize * 2;
+               } while (nbytes >= bsize * 2);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       do {
+               if (dst != src)
+                       *dst = *src;
+
+               u128_to_be128(&ctrblocks[0], &ctrblk);
+               u128_inc(&ctrblk);
+
+               camellia_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks);
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+done:
+       u128_to_be128((be128 *)walk->iv, &ctrblk);
+       return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, CAMELLIA_BLOCK_SIZE);
+
+       while ((nbytes = walk.nbytes) >= CAMELLIA_BLOCK_SIZE) {
+               nbytes = __ctr_crypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       if (walk.nbytes) {
+               ctr_crypt_final(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       struct camellia_ctx *ctx = priv;
+       int i;
+
+       while (nbytes >= 2 * bsize) {
+               camellia_enc_blk_2way(ctx, srcdst, srcdst);
+               srcdst += bsize * 2;
+               nbytes -= bsize * 2;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               camellia_enc_blk(ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       struct camellia_ctx *ctx = priv;
+       int i;
+
+       while (nbytes >= 2 * bsize) {
+               camellia_dec_blk_2way(ctx, srcdst, srcdst);
+               srcdst += bsize * 2;
+               nbytes -= bsize * 2;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               camellia_dec_blk(ctx, srcdst, srcdst);
+}
+
+struct camellia_lrw_ctx {
+       struct lrw_table_ctx lrw_table;
+       struct camellia_ctx camellia_ctx;
+};
+
+static int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       err = __camellia_setkey(&ctx->camellia_ctx, key,
+                               keylen - CAMELLIA_BLOCK_SIZE,
+                               &tfm->crt_flags);
+       if (err)
+               return err;
+
+       return lrw_init_table(&ctx->lrw_table,
+                             key + keylen - CAMELLIA_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[2 * 4];
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &ctx->camellia_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+
+       return lrw_crypt(desc, dst, src, nbytes, &req);
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[2 * 4];
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &ctx->camellia_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+
+       return lrw_crypt(desc, dst, src, nbytes, &req);
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       lrw_free_table(&ctx->lrw_table);
+}
+
+struct camellia_xts_ctx {
+       struct camellia_ctx tweak_ctx;
+       struct camellia_ctx crypt_ctx;
+};
+
+static int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct camellia_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int err;
+
+       /* key consists of keys of equal size concatenated, therefore
+        * the length must be even
+        */
+       if (keylen % 2) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       /* first half of xts-key is for crypt */
+       err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+       if (err)
+               return err;
+
+       /* second half of xts-key is for tweak */
+       return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+                               flags);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[2 * 4];
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
+               .crypt_ctx = &ctx->crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+
+       return xts_crypt(desc, dst, src, nbytes, &req);
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[2 * 4];
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
+               .crypt_ctx = &ctx->crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+
+       return xts_crypt(desc, dst, src, nbytes, &req);
+}
+
+static struct crypto_alg camellia_algs[6] = { {
+       .cra_name               = "camellia",
+       .cra_driver_name        = "camellia-asm",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[0].cra_list),
+       .cra_u                  = {
+               .cipher = {
+                       .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE,
+                       .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE,
+                       .cia_setkey      = camellia_setkey,
+                       .cia_encrypt     = camellia_encrypt,
+                       .cia_decrypt     = camellia_decrypt
+               }
+       }
+}, {
+       .cra_name               = "ecb(camellia)",
+       .cra_driver_name        = "ecb-camellia-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[1].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(camellia)",
+       .cra_driver_name        = "cbc-camellia-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[2].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(camellia)",
+       .cra_driver_name        = "ctr-camellia-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[3].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "lrw(camellia)",
+       .cra_driver_name        = "lrw-camellia-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[4].cra_list),
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE +
+                                               CAMELLIA_BLOCK_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE +
+                                               CAMELLIA_BLOCK_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = lrw_camellia_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "xts(camellia)",
+       .cra_driver_name        = "xts-camellia-asm",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(camellia_algs[5].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE * 2,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE * 2,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = xts_camellia_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+} };
+
+static bool is_blacklisted_cpu(void)
+{
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return false;
+
+       if (boot_cpu_data.x86 == 0x0f) {
+               /*
+                * On Pentium 4, camellia-asm is slower than original assembler
+                * implementation because excessive uses of 64bit rotate and
+                * left-shifts (which are really slow on P4) needed to store and
+                * handle 128bit block in two 64bit registers.
+                */
+               return true;
+       }
+
+       return false;
+}
+
+static int force;
+module_param(force, int, 0);
+MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
+
+int __init init(void)
+{
+       if (!force && is_blacklisted_cpu()) {
+               printk(KERN_INFO
+                       "camellia-x86_64: performance on this CPU "
+                       "would be suboptimal: disabling "
+                       "camellia-x86_64.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
+}
+
+void __exit fini(void)
+{
+       crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized");
+MODULE_ALIAS("camellia");
+MODULE_ALIAS("camellia-asm");
index 4e37677..c00053d 100644 (file)
        pand x0,                x4; \
        pxor x2,                x4;
 
-#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
-       movdqa x2,              t3; \
-       movdqa x0,              t1; \
-       unpcklps x3,            t3; \
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
        movdqa x0,              t2; \
-       unpcklps x1,            t1; \
-       unpckhps x1,            t2; \
-       movdqa t3,              x1; \
-       unpckhps x3,            x2; \
-       movdqa t1,              x0; \
-       movhlps t1,             x1; \
-       movdqa t2,              t1; \
-       movlhps t3,             x0; \
-       movlhps x2,             t1; \
-       movhlps t2,             x2; \
-       movdqa x2,              x3; \
-       movdqa t1,              x2;
+       punpckldq x1,           x0; \
+       punpckhdq x1,           t2; \
+       movdqa x2,              t1; \
+       punpckhdq x3,           x2; \
+       punpckldq x3,           t1; \
+       movdqa x0,              x1; \
+       punpcklqdq t1,          x0; \
+       punpckhqdq t1,          x1; \
+       movdqa t2,              x3; \
+       punpcklqdq x2,          t2; \
+       punpckhqdq x2,          x3; \
+       movdqa t2,              x2;
 
 #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
        movdqu (0*4*4)(in),     x0; \
index 7f24a15..3ee1ff0 100644 (file)
        get_key(i, 1, RK1); \
        SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
 
-#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
-       movdqa x2,              t3; \
-       movdqa x0,              t1; \
-       unpcklps x3,            t3; \
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
        movdqa x0,              t2; \
-       unpcklps x1,            t1; \
-       unpckhps x1,            t2; \
-       movdqa t3,              x1; \
-       unpckhps x3,            x2; \
-       movdqa t1,              x0; \
-       movhlps t1,             x1; \
-       movdqa t2,              t1; \
-       movlhps t3,             x0; \
-       movlhps x2,             t1; \
-       movhlps t2,             x2; \
-       movdqa x2,              x3; \
-       movdqa t1,              x2;
+       punpckldq x1,           x0; \
+       punpckhdq x1,           t2; \
+       movdqa x2,              t1; \
+       punpckhdq x3,           x2; \
+       punpckldq x3,           t1; \
+       movdqa x0,              x1; \
+       punpcklqdq t1,          x0; \
+       punpckhqdq t1,          x1; \
+       movdqa t2,              x3; \
+       punpcklqdq x2,          t2; \
+       punpckhqdq x2,          x3; \
+       movdqa t2,              x2;
 
 #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
        movdqu (0*4*4)(in),     x0; \
index 7955a9b..4b21be8 100644 (file)
@@ -145,28 +145,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ecb_crypt(desc, &walk, false);
 }
 
-static struct crypto_alg blk_ecb_alg = {
-       .cra_name               = "__ecb-serpent-sse2",
-       .cra_driver_name        = "__driver-ecb-serpent-sse2",
-       .cra_priority           = 0,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct serpent_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
-                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
-                       .setkey         = serpent_setkey,
-                       .encrypt        = ecb_encrypt,
-                       .decrypt        = ecb_decrypt,
-               },
-       },
-};
-
 static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
                                  struct blkcipher_walk *walk)
 {
@@ -295,28 +273,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_cbc_alg = {
-       .cra_name               = "__cbc-serpent-sse2",
-       .cra_driver_name        = "__driver-cbc-serpent-sse2",
-       .cra_priority           = 0,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct serpent_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
-                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
-                       .setkey         = serpent_setkey,
-                       .encrypt        = cbc_encrypt,
-                       .decrypt        = cbc_decrypt,
-               },
-       },
-};
-
 static inline void u128_to_be128(be128 *dst, const u128 *src)
 {
        dst->a = cpu_to_be64(src->a);
@@ -439,29 +395,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_ctr_alg = {
-       .cra_name               = "__ctr-serpent-sse2",
-       .cra_driver_name        = "__driver-ctr-serpent-sse2",
-       .cra_priority           = 0,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = 1,
-       .cra_ctxsize            = sizeof(struct serpent_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ctr_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
-                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
-                       .ivsize         = SERPENT_BLOCK_SIZE,
-                       .setkey         = serpent_setkey,
-                       .encrypt        = ctr_crypt,
-                       .decrypt        = ctr_crypt,
-               },
-       },
-};
-
 struct crypt_priv {
        struct serpent_ctx *ctx;
        bool fpu_enabled;
@@ -580,32 +513,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm)
        lrw_free_table(&ctx->lrw_table);
 }
 
-static struct crypto_alg blk_lrw_alg = {
-       .cra_name               = "__lrw-serpent-sse2",
-       .cra_driver_name        = "__driver-lrw-serpent-sse2",
-       .cra_priority           = 0,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct serpent_lrw_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_lrw_alg.cra_list),
-       .cra_exit               = lrw_exit_tfm,
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
-                                         SERPENT_BLOCK_SIZE,
-                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
-                                         SERPENT_BLOCK_SIZE,
-                       .ivsize         = SERPENT_BLOCK_SIZE,
-                       .setkey         = lrw_serpent_setkey,
-                       .encrypt        = lrw_encrypt,
-                       .decrypt        = lrw_decrypt,
-               },
-       },
-};
-
 struct serpent_xts_ctx {
        struct serpent_ctx tweak_ctx;
        struct serpent_ctx crypt_ctx;
@@ -689,29 +596,6 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ret;
 }
 
-static struct crypto_alg blk_xts_alg = {
-       .cra_name               = "__xts-serpent-sse2",
-       .cra_driver_name        = "__driver-xts-serpent-sse2",
-       .cra_priority           = 0,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct serpent_xts_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_xts_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
-                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
-                       .ivsize         = SERPENT_BLOCK_SIZE,
-                       .setkey         = xts_serpent_setkey,
-                       .encrypt        = xts_encrypt,
-                       .decrypt        = xts_decrypt,
-               },
-       },
-};
-
 static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
                        unsigned int key_len)
 {
@@ -792,28 +676,133 @@ static void ablk_exit(struct crypto_tfm *tfm)
        cryptd_free_ablkcipher(ctx->cryptd_tfm);
 }
 
-static void ablk_init_common(struct crypto_tfm *tfm,
-                            struct cryptd_ablkcipher *cryptd_tfm)
+static int ablk_init(struct crypto_tfm *tfm)
 {
        struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct cryptd_ablkcipher *cryptd_tfm;
+       char drv_name[CRYPTO_MAX_ALG_NAME];
+
+       snprintf(drv_name, sizeof(drv_name), "__driver-%s",
+                                       crypto_tfm_alg_driver_name(tfm));
+
+       cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
 
        ctx->cryptd_tfm = cryptd_tfm;
        tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
                crypto_ablkcipher_reqsize(&cryptd_tfm->base);
-}
-
-static int ablk_ecb_init(struct crypto_tfm *tfm)
-{
-       struct cryptd_ablkcipher *cryptd_tfm;
 
-       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0);
-       if (IS_ERR(cryptd_tfm))
-               return PTR_ERR(cryptd_tfm);
-       ablk_init_common(tfm, cryptd_tfm);
        return 0;
 }
 
-static struct crypto_alg ablk_ecb_alg = {
+static struct crypto_alg serpent_algs[10] = { {
+       .cra_name               = "__ecb-serpent-sse2",
+       .cra_driver_name        = "__driver-ecb-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[0].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-serpent-sse2",
+       .cra_driver_name        = "__driver-cbc-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[1].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-serpent-sse2",
+       .cra_driver_name        = "__driver-ctr-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[2].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "__lrw-serpent-sse2",
+       .cra_driver_name        = "__driver-lrw-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[3].cra_list),
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = lrw_serpent_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__xts-serpent-sse2",
+       .cra_driver_name        = "__driver-xts-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[4].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = xts_serpent_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+}, {
        .cra_name               = "ecb(serpent)",
        .cra_driver_name        = "ecb-serpent-sse2",
        .cra_priority           = 400,
@@ -823,8 +812,8 @@ static struct crypto_alg ablk_ecb_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
-       .cra_init               = ablk_ecb_init,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[5].cra_list),
+       .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
                .ablkcipher = {
@@ -835,20 +824,7 @@ static struct crypto_alg ablk_ecb_alg = {
                        .decrypt        = ablk_decrypt,
                },
        },
-};
-
-static int ablk_cbc_init(struct crypto_tfm *tfm)
-{
-       struct cryptd_ablkcipher *cryptd_tfm;
-
-       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0);
-       if (IS_ERR(cryptd_tfm))
-               return PTR_ERR(cryptd_tfm);
-       ablk_init_common(tfm, cryptd_tfm);
-       return 0;
-}
-
-static struct crypto_alg ablk_cbc_alg = {
+}, {
        .cra_name               = "cbc(serpent)",
        .cra_driver_name        = "cbc-serpent-sse2",
        .cra_priority           = 400,
@@ -858,8 +834,8 @@ static struct crypto_alg ablk_cbc_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
-       .cra_init               = ablk_cbc_init,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[6].cra_list),
+       .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
                .ablkcipher = {
@@ -871,20 +847,7 @@ static struct crypto_alg ablk_cbc_alg = {
                        .decrypt        = ablk_decrypt,
                },
        },
-};
-
-static int ablk_ctr_init(struct crypto_tfm *tfm)
-{
-       struct cryptd_ablkcipher *cryptd_tfm;
-
-       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0);
-       if (IS_ERR(cryptd_tfm))
-               return PTR_ERR(cryptd_tfm);
-       ablk_init_common(tfm, cryptd_tfm);
-       return 0;
-}
-
-static struct crypto_alg ablk_ctr_alg = {
+}, {
        .cra_name               = "ctr(serpent)",
        .cra_driver_name        = "ctr-serpent-sse2",
        .cra_priority           = 400,
@@ -894,8 +857,8 @@ static struct crypto_alg ablk_ctr_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
-       .cra_init               = ablk_ctr_init,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[7].cra_list),
+       .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
                .ablkcipher = {
@@ -908,20 +871,7 @@ static struct crypto_alg ablk_ctr_alg = {
                        .geniv          = "chainiv",
                },
        },
-};
-
-static int ablk_lrw_init(struct crypto_tfm *tfm)
-{
-       struct cryptd_ablkcipher *cryptd_tfm;
-
-       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0);
-       if (IS_ERR(cryptd_tfm))
-               return PTR_ERR(cryptd_tfm);
-       ablk_init_common(tfm, cryptd_tfm);
-       return 0;
-}
-
-static struct crypto_alg ablk_lrw_alg = {
+}, {
        .cra_name               = "lrw(serpent)",
        .cra_driver_name        = "lrw-serpent-sse2",
        .cra_priority           = 400,
@@ -931,8 +881,8 @@ static struct crypto_alg ablk_lrw_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
-       .cra_init               = ablk_lrw_init,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[8].cra_list),
+       .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
                .ablkcipher = {
@@ -946,20 +896,7 @@ static struct crypto_alg ablk_lrw_alg = {
                        .decrypt        = ablk_decrypt,
                },
        },
-};
-
-static int ablk_xts_init(struct crypto_tfm *tfm)
-{
-       struct cryptd_ablkcipher *cryptd_tfm;
-
-       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0);
-       if (IS_ERR(cryptd_tfm))
-               return PTR_ERR(cryptd_tfm);
-       ablk_init_common(tfm, cryptd_tfm);
-       return 0;
-}
-
-static struct crypto_alg ablk_xts_alg = {
+}, {
        .cra_name               = "xts(serpent)",
        .cra_driver_name        = "xts-serpent-sse2",
        .cra_priority           = 400,
@@ -969,8 +906,8 @@ static struct crypto_alg ablk_xts_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
-       .cra_init               = ablk_xts_init,
+       .cra_list               = LIST_HEAD_INIT(serpent_algs[9].cra_list),
+       .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
                .ablkcipher = {
@@ -982,84 +919,21 @@ static struct crypto_alg ablk_xts_alg = {
                        .decrypt        = ablk_decrypt,
                },
        },
-};
+} };
 
 static int __init serpent_sse2_init(void)
 {
-       int err;
-
        if (!cpu_has_xmm2) {
                printk(KERN_INFO "SSE2 instructions are not detected.\n");
                return -ENODEV;
        }
 
-       err = crypto_register_alg(&blk_ecb_alg);
-       if (err)
-               goto blk_ecb_err;
-       err = crypto_register_alg(&blk_cbc_alg);
-       if (err)
-               goto blk_cbc_err;
-       err = crypto_register_alg(&blk_ctr_alg);
-       if (err)
-               goto blk_ctr_err;
-       err = crypto_register_alg(&ablk_ecb_alg);
-       if (err)
-               goto ablk_ecb_err;
-       err = crypto_register_alg(&ablk_cbc_alg);
-       if (err)
-               goto ablk_cbc_err;
-       err = crypto_register_alg(&ablk_ctr_alg);
-       if (err)
-               goto ablk_ctr_err;
-       err = crypto_register_alg(&blk_lrw_alg);
-       if (err)
-               goto blk_lrw_err;
-       err = crypto_register_alg(&ablk_lrw_alg);
-       if (err)
-               goto ablk_lrw_err;
-       err = crypto_register_alg(&blk_xts_alg);
-       if (err)
-               goto blk_xts_err;
-       err = crypto_register_alg(&ablk_xts_alg);
-       if (err)
-               goto ablk_xts_err;
-       return err;
-
-       crypto_unregister_alg(&ablk_xts_alg);
-ablk_xts_err:
-       crypto_unregister_alg(&blk_xts_alg);
-blk_xts_err:
-       crypto_unregister_alg(&ablk_lrw_alg);
-ablk_lrw_err:
-       crypto_unregister_alg(&blk_lrw_alg);
-blk_lrw_err:
-       crypto_unregister_alg(&ablk_ctr_alg);
-ablk_ctr_err:
-       crypto_unregister_alg(&ablk_cbc_alg);
-ablk_cbc_err:
-       crypto_unregister_alg(&ablk_ecb_alg);
-ablk_ecb_err:
-       crypto_unregister_alg(&blk_ctr_alg);
-blk_ctr_err:
-       crypto_unregister_alg(&blk_cbc_alg);
-blk_cbc_err:
-       crypto_unregister_alg(&blk_ecb_alg);
-blk_ecb_err:
-       return err;
+       return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
 }
 
 static void __exit serpent_sse2_exit(void)
 {
-       crypto_unregister_alg(&ablk_xts_alg);
-       crypto_unregister_alg(&blk_xts_alg);
-       crypto_unregister_alg(&ablk_lrw_alg);
-       crypto_unregister_alg(&blk_lrw_alg);
-       crypto_unregister_alg(&ablk_ctr_alg);
-       crypto_unregister_alg(&ablk_cbc_alg);
-       crypto_unregister_alg(&ablk_ecb_alg);
-       crypto_unregister_alg(&blk_ctr_alg);
-       crypto_unregister_alg(&blk_cbc_alg);
-       crypto_unregister_alg(&blk_ecb_alg);
+       crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
 }
 
 module_init(serpent_sse2_init);
index dc6b3fb..359ae08 100644 (file)
@@ -68,7 +68,7 @@ static struct crypto_alg alg = {
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       TF_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct twofish_ctx),
-       .cra_alignmask          =       3,
+       .cra_alignmask          =       0,
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
        .cra_u                  =       {
index 7fee8c1..408fc0c 100644 (file)
@@ -25,6 +25,7 @@
  *
  */
 
+#include <asm/processor.h>
 #include <linux/crypto.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -122,28 +123,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ecb_crypt(desc, &walk, twofish_dec_blk, twofish_dec_blk_3way);
 }
 
-static struct crypto_alg blk_ecb_alg = {
-       .cra_name               = "ecb(twofish)",
-       .cra_driver_name        = "ecb-twofish-3way",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = TF_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct twofish_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = TF_MIN_KEY_SIZE,
-                       .max_keysize    = TF_MAX_KEY_SIZE,
-                       .setkey         = twofish_setkey,
-                       .encrypt        = ecb_encrypt,
-                       .decrypt        = ecb_decrypt,
-               },
-       },
-};
-
 static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
                                  struct blkcipher_walk *walk)
 {
@@ -267,29 +246,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_cbc_alg = {
-       .cra_name               = "cbc(twofish)",
-       .cra_driver_name        = "cbc-twofish-3way",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = TF_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct twofish_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = TF_MIN_KEY_SIZE,
-                       .max_keysize    = TF_MAX_KEY_SIZE,
-                       .ivsize         = TF_BLOCK_SIZE,
-                       .setkey         = twofish_setkey,
-                       .encrypt        = cbc_encrypt,
-                       .decrypt        = cbc_decrypt,
-               },
-       },
-};
-
 static inline void u128_to_be128(be128 *dst, const u128 *src)
 {
        dst->a = cpu_to_be64(src->a);
@@ -411,29 +367,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return err;
 }
 
-static struct crypto_alg blk_ctr_alg = {
-       .cra_name               = "ctr(twofish)",
-       .cra_driver_name        = "ctr-twofish-3way",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = 1,
-       .cra_ctxsize            = sizeof(struct twofish_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_ctr_alg.cra_list),
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = TF_MIN_KEY_SIZE,
-                       .max_keysize    = TF_MAX_KEY_SIZE,
-                       .ivsize         = TF_BLOCK_SIZE,
-                       .setkey         = twofish_setkey,
-                       .encrypt        = ctr_crypt,
-                       .decrypt        = ctr_crypt,
-               },
-       },
-};
-
 static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
 {
        const unsigned int bsize = TF_BLOCK_SIZE;
@@ -524,30 +457,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm)
        lrw_free_table(&ctx->lrw_table);
 }
 
-static struct crypto_alg blk_lrw_alg = {
-       .cra_name               = "lrw(twofish)",
-       .cra_driver_name        = "lrw-twofish-3way",
-       .cra_priority           = 300,
-       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = TF_BLOCK_SIZE,
-       .cra_ctxsize            = sizeof(struct twofish_lrw_ctx),
-       .cra_alignmask          = 0,
-       .cra_type               = &crypto_blkcipher_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_lrw_alg.cra_list),
-       .cra_exit               = lrw_exit_tfm,
-       .cra_u = {
-               .blkcipher = {
-                       .min_keysize    = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE,
-                       .max_keysize    = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE,
-                       .ivsize         = TF_BLOCK_SIZE,
-                       .setkey         = lrw_twofish_setkey,
-                       .encrypt        = lrw_encrypt,
-                       .decrypt        = lrw_decrypt,
-               },
-       },
-};
-
 struct twofish_xts_ctx {
        struct twofish_ctx tweak_ctx;
        struct twofish_ctx crypt_ctx;
@@ -614,7 +523,91 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return xts_crypt(desc, dst, src, nbytes, &req);
 }
 
-static struct crypto_alg blk_xts_alg = {
+static struct crypto_alg tf_algs[5] = { {
+       .cra_name               = "ecb(twofish)",
+       .cra_driver_name        = "ecb-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = TF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct twofish_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(tf_algs[0].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE,
+                       .max_keysize    = TF_MAX_KEY_SIZE,
+                       .setkey         = twofish_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(twofish)",
+       .cra_driver_name        = "cbc-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = TF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct twofish_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(tf_algs[1].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE,
+                       .max_keysize    = TF_MAX_KEY_SIZE,
+                       .ivsize         = TF_BLOCK_SIZE,
+                       .setkey         = twofish_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(twofish)",
+       .cra_driver_name        = "ctr-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct twofish_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(tf_algs[2].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE,
+                       .max_keysize    = TF_MAX_KEY_SIZE,
+                       .ivsize         = TF_BLOCK_SIZE,
+                       .setkey         = twofish_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "lrw(twofish)",
+       .cra_driver_name        = "lrw-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = TF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct twofish_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(tf_algs[3].cra_list),
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE,
+                       .max_keysize    = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE,
+                       .ivsize         = TF_BLOCK_SIZE,
+                       .setkey         = lrw_twofish_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
        .cra_name               = "xts(twofish)",
        .cra_driver_name        = "xts-twofish-3way",
        .cra_priority           = 300,
@@ -624,7 +617,7 @@ static struct crypto_alg blk_xts_alg = {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(blk_xts_alg.cra_list),
+       .cra_list               = LIST_HEAD_INIT(tf_algs[4].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE * 2,
@@ -635,50 +628,62 @@ static struct crypto_alg blk_xts_alg = {
                        .decrypt        = xts_decrypt,
                },
        },
-};
+} };
+
+static bool is_blacklisted_cpu(void)
+{
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return false;
+
+       if (boot_cpu_data.x86 == 0x06 &&
+               (boot_cpu_data.x86_model == 0x1c ||
+                boot_cpu_data.x86_model == 0x26 ||
+                boot_cpu_data.x86_model == 0x36)) {
+               /*
+                * On Atom, twofish-3way is slower than original assembler
+                * implementation. Twofish-3way trades off some performance in
+                * storing blocks in 64bit registers to allow three blocks to
+                * be processed parallel. Parallel operation then allows gaining
+                * more performance than was trade off, on out-of-order CPUs.
+                * However Atom does not benefit from this parallellism and
+                * should be blacklisted.
+                */
+               return true;
+       }
+
+       if (boot_cpu_data.x86 == 0x0f) {
+               /*
+                * On Pentium 4, twofish-3way is slower than original assembler
+                * implementation because excessive uses of 64bit rotate and
+                * left-shifts (which are really slow on P4) needed to store and
+                * handle 128bit block in two 64bit registers.
+                */
+               return true;
+       }
+
+       return false;
+}
+
+static int force;
+module_param(force, int, 0);
+MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
 
 int __init init(void)
 {
-       int err;
+       if (!force && is_blacklisted_cpu()) {
+               printk(KERN_INFO
+                       "twofish-x86_64-3way: performance on this CPU "
+                       "would be suboptimal: disabling "
+                       "twofish-x86_64-3way.\n");
+               return -ENODEV;
+       }
 
-       err = crypto_register_alg(&blk_ecb_alg);
-       if (err)
-               goto ecb_err;
-       err = crypto_register_alg(&blk_cbc_alg);
-       if (err)
-               goto cbc_err;
-       err = crypto_register_alg(&blk_ctr_alg);
-       if (err)
-               goto ctr_err;
-       err = crypto_register_alg(&blk_lrw_alg);
-       if (err)
-               goto blk_lrw_err;
-       err = crypto_register_alg(&blk_xts_alg);
-       if (err)
-               goto blk_xts_err;
-
-       return 0;
-
-       crypto_unregister_alg(&blk_xts_alg);
-blk_xts_err:
-       crypto_unregister_alg(&blk_lrw_alg);
-blk_lrw_err:
-       crypto_unregister_alg(&blk_ctr_alg);
-ctr_err:
-       crypto_unregister_alg(&blk_cbc_alg);
-cbc_err:
-       crypto_unregister_alg(&blk_ecb_alg);
-ecb_err:
-       return err;
+       return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs));
 }
 
 void __exit fini(void)
 {
-       crypto_unregister_alg(&blk_xts_alg);
-       crypto_unregister_alg(&blk_lrw_alg);
-       crypto_unregister_alg(&blk_ctr_alg);
-       crypto_unregister_alg(&blk_cbc_alg);
-       crypto_unregister_alg(&blk_ecb_alg);
+       crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs));
 }
 
 module_init(init);
index 39e4909..4c2e59a 100644 (file)
@@ -323,7 +323,6 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        }
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
 
        if (N_MAGIC(ex) == OMAGIC) {
                unsigned long text_addr, map_size;
@@ -519,7 +518,8 @@ out:
 
 static int __init init_aout_binfmt(void)
 {
-       return register_binfmt(&aout_format);
+       register_binfmt(&aout_format);
+       return 0;
 }
 
 static void __exit exit_aout_binfmt(void)
index e6cfe1a..6318edd 100644 (file)
@@ -654,6 +654,24 @@ config CRYPTO_CAMELLIA
          See also:
          <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html>
 
+config CRYPTO_CAMELLIA_X86_64
+       tristate "Camellia cipher algorithm (x86_64)"
+       depends on (X86 || UML_X86) && 64BIT
+       depends on CRYPTO
+       select CRYPTO_ALGAPI
+       select CRYPTO_LRW
+       select CRYPTO_XTS
+       help
+         Camellia cipher algorithm module (x86_64).
+
+         Camellia is a symmetric key block cipher developed jointly
+         at NTT and Mitsubishi Electric Corporation.
+
+         The Camellia specifies three key sizes: 128, 192 and 256 bits.
+
+         See also:
+         <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html>
+
 config CRYPTO_CAST5
        tristate "CAST5 (CAST-128) cipher algorithm"
        select CRYPTO_ALGAPI
index f638063..30f33d6 100644 (file)
@@ -67,7 +67,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
 obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
-obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o
+obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
 obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
index 9d4a9fe..056571b 100644 (file)
@@ -405,6 +405,41 @@ int crypto_unregister_alg(struct crypto_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_alg);
 
+int crypto_register_algs(struct crypto_alg *algs, int count)
+{
+       int i, ret;
+
+       for (i = 0; i < count; i++) {
+               ret = crypto_register_alg(&algs[i]);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       for (--i; i >= 0; --i)
+               crypto_unregister_alg(&algs[i]);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(crypto_register_algs);
+
+int crypto_unregister_algs(struct crypto_alg *algs, int count)
+{
+       int i, ret;
+
+       for (i = 0; i < count; i++) {
+               ret = crypto_unregister_alg(&algs[i]);
+               if (ret)
+                       pr_err("Failed to unregister %s %s: %d\n",
+                              algs[i].cra_driver_name, algs[i].cra_name, ret);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_algs);
+
 int crypto_register_template(struct crypto_template *tmpl)
 {
        struct crypto_template *q;
diff --git a/crypto/camellia.c b/crypto/camellia.c
deleted file mode 100644 (file)
index 64cff46..0000000
+++ /dev/null
@@ -1,1116 +0,0 @@
-/*
- * Copyright (C) 2006
- * NTT (Nippon Telegraph and Telephone 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; 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.
- */
-
-/*
- * Algorithm Specification
- *  http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
- */
-
-/*
- *
- * NOTE --- NOTE --- NOTE --- NOTE
- * This implementation assumes that all memory addresses passed
- * as parameters are four-byte aligned.
- *
- */
-
-#include <linux/crypto.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <asm/unaligned.h>
-
-static const u32 camellia_sp1110[256] = {
-       0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00,
-       0xb3b3b300, 0x27272700, 0xc0c0c000, 0xe5e5e500,
-       0xe4e4e400, 0x85858500, 0x57575700, 0x35353500,
-       0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100,
-       0x23232300, 0xefefef00, 0x6b6b6b00, 0x93939300,
-       0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
-       0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00,
-       0x1d1d1d00, 0x65656500, 0x92929200, 0xbdbdbd00,
-       0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00,
-       0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00,
-       0x3e3e3e00, 0x30303000, 0xdcdcdc00, 0x5f5f5f00,
-       0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
-       0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00,
-       0xd5d5d500, 0x47474700, 0x5d5d5d00, 0x3d3d3d00,
-       0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600,
-       0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00,
-       0x8b8b8b00, 0x0d0d0d00, 0x9a9a9a00, 0x66666600,
-       0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
-       0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000,
-       0xf0f0f000, 0xb1b1b100, 0x84848400, 0x99999900,
-       0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200,
-       0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500,
-       0x6d6d6d00, 0xb7b7b700, 0xa9a9a900, 0x31313100,
-       0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
-       0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100,
-       0xdedede00, 0x1b1b1b00, 0x11111100, 0x1c1c1c00,
-       0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600,
-       0x53535300, 0x18181800, 0xf2f2f200, 0x22222200,
-       0xfefefe00, 0x44444400, 0xcfcfcf00, 0xb2b2b200,
-       0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
-       0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800,
-       0x60606000, 0xfcfcfc00, 0x69696900, 0x50505000,
-       0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00,
-       0xa1a1a100, 0x89898900, 0x62626200, 0x97979700,
-       0x54545400, 0x5b5b5b00, 0x1e1e1e00, 0x95959500,
-       0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
-       0x10101000, 0xc4c4c400, 0x00000000, 0x48484800,
-       0xa3a3a300, 0xf7f7f700, 0x75757500, 0xdbdbdb00,
-       0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00,
-       0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400,
-       0x87878700, 0x5c5c5c00, 0x83838300, 0x02020200,
-       0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
-       0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300,
-       0x9d9d9d00, 0x7f7f7f00, 0xbfbfbf00, 0xe2e2e200,
-       0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600,
-       0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00,
-       0x81818100, 0x96969600, 0x6f6f6f00, 0x4b4b4b00,
-       0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
-       0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00,
-       0x9f9f9f00, 0x6e6e6e00, 0xbcbcbc00, 0x8e8e8e00,
-       0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600,
-       0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900,
-       0x78787800, 0x98989800, 0x06060600, 0x6a6a6a00,
-       0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
-       0xd4d4d400, 0x25252500, 0xababab00, 0x42424200,
-       0x88888800, 0xa2a2a200, 0x8d8d8d00, 0xfafafa00,
-       0x72727200, 0x07070700, 0xb9b9b900, 0x55555500,
-       0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00,
-       0x36363600, 0x49494900, 0x2a2a2a00, 0x68686800,
-       0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
-       0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00,
-       0xbbbbbb00, 0xc9c9c900, 0x43434300, 0xc1c1c100,
-       0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400,
-       0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00,
-};
-
-static const u32 camellia_sp0222[256] = {
-       0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9,
-       0x00676767, 0x004e4e4e, 0x00818181, 0x00cbcbcb,
-       0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a,
-       0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282,
-       0x00464646, 0x00dfdfdf, 0x00d6d6d6, 0x00272727,
-       0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
-       0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c,
-       0x003a3a3a, 0x00cacaca, 0x00252525, 0x007b7b7b,
-       0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f,
-       0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d,
-       0x007c7c7c, 0x00606060, 0x00b9b9b9, 0x00bebebe,
-       0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
-       0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595,
-       0x00ababab, 0x008e8e8e, 0x00bababa, 0x007a7a7a,
-       0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad,
-       0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a,
-       0x00171717, 0x001a1a1a, 0x00353535, 0x00cccccc,
-       0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
-       0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040,
-       0x00e1e1e1, 0x00636363, 0x00090909, 0x00333333,
-       0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585,
-       0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a,
-       0x00dadada, 0x006f6f6f, 0x00535353, 0x00626262,
-       0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
-       0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2,
-       0x00bdbdbd, 0x00363636, 0x00222222, 0x00383838,
-       0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c,
-       0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444,
-       0x00fdfdfd, 0x00888888, 0x009f9f9f, 0x00656565,
-       0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
-       0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151,
-       0x00c0c0c0, 0x00f9f9f9, 0x00d2d2d2, 0x00a0a0a0,
-       0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa,
-       0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f,
-       0x00a8a8a8, 0x00b6b6b6, 0x003c3c3c, 0x002b2b2b,
-       0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
-       0x00202020, 0x00898989, 0x00000000, 0x00909090,
-       0x00474747, 0x00efefef, 0x00eaeaea, 0x00b7b7b7,
-       0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5,
-       0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929,
-       0x000f0f0f, 0x00b8b8b8, 0x00070707, 0x00040404,
-       0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
-       0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7,
-       0x003b3b3b, 0x00fefefe, 0x007f7f7f, 0x00c5c5c5,
-       0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c,
-       0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676,
-       0x00030303, 0x002d2d2d, 0x00dedede, 0x00969696,
-       0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
-       0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919,
-       0x003f3f3f, 0x00dcdcdc, 0x00797979, 0x001d1d1d,
-       0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d,
-       0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2,
-       0x00f0f0f0, 0x00313131, 0x000c0c0c, 0x00d4d4d4,
-       0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
-       0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484,
-       0x00111111, 0x00454545, 0x001b1b1b, 0x00f5f5f5,
-       0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa,
-       0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414,
-       0x006c6c6c, 0x00929292, 0x00545454, 0x00d0d0d0,
-       0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
-       0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6,
-       0x00777777, 0x00939393, 0x00868686, 0x00838383,
-       0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9,
-       0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d,
-};
-
-static const u32 camellia_sp3033[256] = {
-       0x38003838, 0x41004141, 0x16001616, 0x76007676,
-       0xd900d9d9, 0x93009393, 0x60006060, 0xf200f2f2,
-       0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a,
-       0x75007575, 0x06000606, 0x57005757, 0xa000a0a0,
-       0x91009191, 0xf700f7f7, 0xb500b5b5, 0xc900c9c9,
-       0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
-       0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727,
-       0x8e008e8e, 0xb200b2b2, 0x49004949, 0xde00dede,
-       0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7,
-       0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767,
-       0x1f001f1f, 0x18001818, 0x6e006e6e, 0xaf00afaf,
-       0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
-       0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565,
-       0xea00eaea, 0xa300a3a3, 0xae00aeae, 0x9e009e9e,
-       0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b,
-       0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6,
-       0xc500c5c5, 0x86008686, 0x4d004d4d, 0x33003333,
-       0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
-       0x3a003a3a, 0x09000909, 0x95009595, 0x10001010,
-       0x78007878, 0xd800d8d8, 0x42004242, 0xcc00cccc,
-       0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161,
-       0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282,
-       0xb600b6b6, 0xdb00dbdb, 0xd400d4d4, 0x98009898,
-       0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
-       0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0,
-       0x6f006f6f, 0x8d008d8d, 0x88008888, 0x0e000e0e,
-       0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b,
-       0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111,
-       0x7f007f7f, 0x22002222, 0xe700e7e7, 0x59005959,
-       0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
-       0x12001212, 0x04000404, 0x74007474, 0x54005454,
-       0x30003030, 0x7e007e7e, 0xb400b4b4, 0x28002828,
-       0x55005555, 0x68006868, 0x50005050, 0xbe00bebe,
-       0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb,
-       0x2a002a2a, 0xad00adad, 0x0f000f0f, 0xca00caca,
-       0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
-       0x08000808, 0x62006262, 0x00000000, 0x24002424,
-       0xd100d1d1, 0xfb00fbfb, 0xba00baba, 0xed00eded,
-       0x45004545, 0x81008181, 0x73007373, 0x6d006d6d,
-       0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a,
-       0xc300c3c3, 0x2e002e2e, 0xc100c1c1, 0x01000101,
-       0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
-       0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9,
-       0xce00cece, 0xbf00bfbf, 0xdf00dfdf, 0x71007171,
-       0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313,
-       0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d,
-       0xc000c0c0, 0x4b004b4b, 0xb700b7b7, 0xa500a5a5,
-       0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
-       0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646,
-       0xcf00cfcf, 0x37003737, 0x5e005e5e, 0x47004747,
-       0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b,
-       0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac,
-       0x3c003c3c, 0x4c004c4c, 0x03000303, 0x35003535,
-       0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
-       0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121,
-       0x44004444, 0x51005151, 0xc600c6c6, 0x7d007d7d,
-       0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa,
-       0x7c007c7c, 0x77007777, 0x56005656, 0x05000505,
-       0x1b001b1b, 0xa400a4a4, 0x15001515, 0x34003434,
-       0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
-       0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd,
-       0xdd00dddd, 0xe400e4e4, 0xa100a1a1, 0xe000e0e0,
-       0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a,
-       0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f,
-};
-
-static const u32 camellia_sp4404[256] = {
-       0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0,
-       0xe4e400e4, 0x57570057, 0xeaea00ea, 0xaeae00ae,
-       0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5,
-       0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092,
-       0x86860086, 0xafaf00af, 0x7c7c007c, 0x1f1f001f,
-       0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
-       0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d,
-       0xd9d900d9, 0x5a5a005a, 0x51510051, 0x6c6c006c,
-       0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0,
-       0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084,
-       0xdfdf00df, 0xcbcb00cb, 0x34340034, 0x76760076,
-       0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
-       0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011,
-       0x32320032, 0x9c9c009c, 0x53530053, 0xf2f200f2,
-       0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a,
-       0x24240024, 0xe8e800e8, 0x60600060, 0x69690069,
-       0xaaaa00aa, 0xa0a000a0, 0xa1a100a1, 0x62620062,
-       0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
-       0x10100010, 0x00000000, 0xa3a300a3, 0x75750075,
-       0x8a8a008a, 0xe6e600e6, 0x09090009, 0xdddd00dd,
-       0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090,
-       0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf,
-       0x52520052, 0xd8d800d8, 0xc8c800c8, 0xc6c600c6,
-       0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
-       0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc,
-       0x29290029, 0xf9f900f9, 0x2f2f002f, 0xb4b400b4,
-       0x78780078, 0x06060006, 0xe7e700e7, 0x71710071,
-       0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d,
-       0x72720072, 0xb9b900b9, 0xf8f800f8, 0xacac00ac,
-       0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
-       0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043,
-       0x15150015, 0xadad00ad, 0x77770077, 0x80800080,
-       0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5,
-       0x85850085, 0x35350035, 0x0c0c000c, 0x41410041,
-       0xefef00ef, 0x93930093, 0x19190019, 0x21210021,
-       0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
-       0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce,
-       0x30300030, 0x5f5f005f, 0xc5c500c5, 0x1a1a001a,
-       0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d,
-       0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d,
-       0x0d0d000d, 0x66660066, 0xcccc00cc, 0x2d2d002d,
-       0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
-       0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005,
-       0xb7b700b7, 0x31310031, 0x17170017, 0xd7d700d7,
-       0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c,
-       0x0f0f000f, 0x16160016, 0x18180018, 0x22220022,
-       0x44440044, 0xb2b200b2, 0xb5b500b5, 0x91910091,
-       0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
-       0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097,
-       0x5b5b005b, 0x95950095, 0xffff00ff, 0xd2d200d2,
-       0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db,
-       0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094,
-       0x5c5c005c, 0x02020002, 0x4a4a004a, 0x33330033,
-       0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
-       0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b,
-       0x96960096, 0x4b4b004b, 0xbebe00be, 0x2e2e002e,
-       0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e,
-       0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059,
-       0x98980098, 0x6a6a006a, 0x46460046, 0xbaba00ba,
-       0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
-       0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a,
-       0x49490049, 0x68680068, 0x38380038, 0xa4a400a4,
-       0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1,
-       0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e,
-};
-
-
-#define CAMELLIA_MIN_KEY_SIZE        16
-#define CAMELLIA_MAX_KEY_SIZE        32
-#define CAMELLIA_BLOCK_SIZE          16
-#define CAMELLIA_TABLE_BYTE_LEN     272
-
-/*
- * NB: L and R below stand for 'left' and 'right' as in written numbers.
- * That is, in (xxxL,xxxR) pair xxxL holds most significant digits,
- * _not_ least significant ones!
- */
-
-
-/* key constants */
-
-#define CAMELLIA_SIGMA1L (0xA09E667FL)
-#define CAMELLIA_SIGMA1R (0x3BCC908BL)
-#define CAMELLIA_SIGMA2L (0xB67AE858L)
-#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
-#define CAMELLIA_SIGMA3L (0xC6EF372FL)
-#define CAMELLIA_SIGMA3R (0xE94F82BEL)
-#define CAMELLIA_SIGMA4L (0x54FF53A5L)
-#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
-#define CAMELLIA_SIGMA5L (0x10E527FAL)
-#define CAMELLIA_SIGMA5R (0xDE682D1DL)
-#define CAMELLIA_SIGMA6L (0xB05688C2L)
-#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
-
-/*
- *  macros
- */
-#define ROLDQ(ll, lr, rl, rr, w0, w1, bits)            \
-    do {                                               \
-       w0 = ll;                                        \
-       ll = (ll << bits) + (lr >> (32 - bits));        \
-       lr = (lr << bits) + (rl >> (32 - bits));        \
-       rl = (rl << bits) + (rr >> (32 - bits));        \
-       rr = (rr << bits) + (w0 >> (32 - bits));        \
-    } while (0)
-
-#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits)         \
-    do {                                               \
-       w0 = ll;                                        \
-       w1 = lr;                                        \
-       ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \
-       lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \
-       rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \
-       rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \
-    } while (0)
-
-#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1)     \
-    do {                                                       \
-       il = xl ^ kl;                                           \
-       ir = xr ^ kr;                                           \
-       t0 = il >> 16;                                          \
-       t1 = ir >> 16;                                          \
-       yl = camellia_sp1110[(u8)(ir     )]                     \
-          ^ camellia_sp0222[    (t1 >> 8)]                     \
-          ^ camellia_sp3033[(u8)(t1     )]                     \
-          ^ camellia_sp4404[(u8)(ir >> 8)];                    \
-       yr = camellia_sp1110[    (t0 >> 8)]                     \
-          ^ camellia_sp0222[(u8)(t0     )]                     \
-          ^ camellia_sp3033[(u8)(il >> 8)]                     \
-          ^ camellia_sp4404[(u8)(il     )];                    \
-       yl ^= yr;                                               \
-       yr = ror32(yr, 8);                                      \
-       yr ^= yl;                                               \
-    } while (0)
-
-#define SUBKEY_L(INDEX) (subkey[(INDEX)*2])
-#define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
-
-static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
-{
-       u32 dw, tl, tr;
-       u32 kw4l, kw4r;
-       int i;
-
-       /* absorb kw2 to other subkeys */
-       /* round 2 */
-       subL[3] ^= subL[1]; subR[3] ^= subR[1];
-       /* round 4 */
-       subL[5] ^= subL[1]; subR[5] ^= subR[1];
-       /* round 6 */
-       subL[7] ^= subL[1]; subR[7] ^= subR[1];
-       subL[1] ^= subR[1] & ~subR[9];
-       dw = subL[1] & subL[9],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
-       /* round 8 */
-       subL[11] ^= subL[1]; subR[11] ^= subR[1];
-       /* round 10 */
-       subL[13] ^= subL[1]; subR[13] ^= subR[1];
-       /* round 12 */
-       subL[15] ^= subL[1]; subR[15] ^= subR[1];
-       subL[1] ^= subR[1] & ~subR[17];
-       dw = subL[1] & subL[17],
-               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
-       /* round 14 */
-       subL[19] ^= subL[1]; subR[19] ^= subR[1];
-       /* round 16 */
-       subL[21] ^= subL[1]; subR[21] ^= subR[1];
-       /* round 18 */
-       subL[23] ^= subL[1]; subR[23] ^= subR[1];
-       if (max == 24) {
-               /* kw3 */
-               subL[24] ^= subL[1]; subR[24] ^= subR[1];
-
-       /* absorb kw4 to other subkeys */
-               kw4l = subL[25]; kw4r = subR[25];
-       } else {
-               subL[1] ^= subR[1] & ~subR[25];
-               dw = subL[1] & subL[25],
-                       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
-               /* round 20 */
-               subL[27] ^= subL[1]; subR[27] ^= subR[1];
-               /* round 22 */
-               subL[29] ^= subL[1]; subR[29] ^= subR[1];
-               /* round 24 */
-               subL[31] ^= subL[1]; subR[31] ^= subR[1];
-               /* kw3 */
-               subL[32] ^= subL[1]; subR[32] ^= subR[1];
-
-       /* absorb kw4 to other subkeys */
-               kw4l = subL[33]; kw4r = subR[33];
-               /* round 23 */
-               subL[30] ^= kw4l; subR[30] ^= kw4r;
-               /* round 21 */
-               subL[28] ^= kw4l; subR[28] ^= kw4r;
-               /* round 19 */
-               subL[26] ^= kw4l; subR[26] ^= kw4r;
-               kw4l ^= kw4r & ~subR[24];
-               dw = kw4l & subL[24],
-                       kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
-       }
-       /* round 17 */
-       subL[22] ^= kw4l; subR[22] ^= kw4r;
-       /* round 15 */
-       subL[20] ^= kw4l; subR[20] ^= kw4r;
-       /* round 13 */
-       subL[18] ^= kw4l; subR[18] ^= kw4r;
-       kw4l ^= kw4r & ~subR[16];
-       dw = kw4l & subL[16],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
-       /* round 11 */
-       subL[14] ^= kw4l; subR[14] ^= kw4r;
-       /* round 9 */
-       subL[12] ^= kw4l; subR[12] ^= kw4r;
-       /* round 7 */
-       subL[10] ^= kw4l; subR[10] ^= kw4r;
-       kw4l ^= kw4r & ~subR[8];
-       dw = kw4l & subL[8],
-               kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
-       /* round 5 */
-       subL[6] ^= kw4l; subR[6] ^= kw4r;
-       /* round 3 */
-       subL[4] ^= kw4l; subR[4] ^= kw4r;
-       /* round 1 */
-       subL[2] ^= kw4l; subR[2] ^= kw4r;
-       /* kw1 */
-       subL[0] ^= kw4l; subR[0] ^= kw4r;
-
-       /* key XOR is end of F-function */
-       SUBKEY_L(0) = subL[0] ^ subL[2];/* kw1 */
-       SUBKEY_R(0) = subR[0] ^ subR[2];
-       SUBKEY_L(2) = subL[3];       /* round 1 */
-       SUBKEY_R(2) = subR[3];
-       SUBKEY_L(3) = subL[2] ^ subL[4]; /* round 2 */
-       SUBKEY_R(3) = subR[2] ^ subR[4];
-       SUBKEY_L(4) = subL[3] ^ subL[5]; /* round 3 */
-       SUBKEY_R(4) = subR[3] ^ subR[5];
-       SUBKEY_L(5) = subL[4] ^ subL[6]; /* round 4 */
-       SUBKEY_R(5) = subR[4] ^ subR[6];
-       SUBKEY_L(6) = subL[5] ^ subL[7]; /* round 5 */
-       SUBKEY_R(6) = subR[5] ^ subR[7];
-       tl = subL[10] ^ (subR[10] & ~subR[8]);
-       dw = tl & subL[8],  /* FL(kl1) */
-               tr = subR[10] ^ rol32(dw, 1);
-       SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
-       SUBKEY_R(7) = subR[6] ^ tr;
-       SUBKEY_L(8) = subL[8];       /* FL(kl1) */
-       SUBKEY_R(8) = subR[8];
-       SUBKEY_L(9) = subL[9];       /* FLinv(kl2) */
-       SUBKEY_R(9) = subR[9];
-       tl = subL[7] ^ (subR[7] & ~subR[9]);
-       dw = tl & subL[9],  /* FLinv(kl2) */
-               tr = subR[7] ^ rol32(dw, 1);
-       SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
-       SUBKEY_R(10) = tr ^ subR[11];
-       SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
-       SUBKEY_R(11) = subR[10] ^ subR[12];
-       SUBKEY_L(12) = subL[11] ^ subL[13]; /* round 9 */
-       SUBKEY_R(12) = subR[11] ^ subR[13];
-       SUBKEY_L(13) = subL[12] ^ subL[14]; /* round 10 */
-       SUBKEY_R(13) = subR[12] ^ subR[14];
-       SUBKEY_L(14) = subL[13] ^ subL[15]; /* round 11 */
-       SUBKEY_R(14) = subR[13] ^ subR[15];
-       tl = subL[18] ^ (subR[18] & ~subR[16]);
-       dw = tl & subL[16], /* FL(kl3) */
-               tr = subR[18] ^ rol32(dw, 1);
-       SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
-       SUBKEY_R(15) = subR[14] ^ tr;
-       SUBKEY_L(16) = subL[16];     /* FL(kl3) */
-       SUBKEY_R(16) = subR[16];
-       SUBKEY_L(17) = subL[17];     /* FLinv(kl4) */
-       SUBKEY_R(17) = subR[17];
-       tl = subL[15] ^ (subR[15] & ~subR[17]);
-       dw = tl & subL[17], /* FLinv(kl4) */
-               tr = subR[15] ^ rol32(dw, 1);
-       SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
-       SUBKEY_R(18) = tr ^ subR[19];
-       SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
-       SUBKEY_R(19) = subR[18] ^ subR[20];
-       SUBKEY_L(20) = subL[19] ^ subL[21]; /* round 15 */
-       SUBKEY_R(20) = subR[19] ^ subR[21];
-       SUBKEY_L(21) = subL[20] ^ subL[22]; /* round 16 */
-       SUBKEY_R(21) = subR[20] ^ subR[22];
-       SUBKEY_L(22) = subL[21] ^ subL[23]; /* round 17 */
-       SUBKEY_R(22) = subR[21] ^ subR[23];
-       if (max == 24) {
-               SUBKEY_L(23) = subL[22];     /* round 18 */
-               SUBKEY_R(23) = subR[22];
-               SUBKEY_L(24) = subL[24] ^ subL[23]; /* kw3 */
-               SUBKEY_R(24) = subR[24] ^ subR[23];
-       } else {
-               tl = subL[26] ^ (subR[26] & ~subR[24]);
-               dw = tl & subL[24], /* FL(kl5) */
-                       tr = subR[26] ^ rol32(dw, 1);
-               SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
-               SUBKEY_R(23) = subR[22] ^ tr;
-               SUBKEY_L(24) = subL[24];     /* FL(kl5) */
-               SUBKEY_R(24) = subR[24];
-               SUBKEY_L(25) = subL[25];     /* FLinv(kl6) */
-               SUBKEY_R(25) = subR[25];
-               tl = subL[23] ^ (subR[23] & ~subR[25]);
-               dw = tl & subL[25], /* FLinv(kl6) */
-                       tr = subR[23] ^ rol32(dw, 1);
-               SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
-               SUBKEY_R(26) = tr ^ subR[27];
-               SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
-               SUBKEY_R(27) = subR[26] ^ subR[28];
-               SUBKEY_L(28) = subL[27] ^ subL[29]; /* round 21 */
-               SUBKEY_R(28) = subR[27] ^ subR[29];
-               SUBKEY_L(29) = subL[28] ^ subL[30]; /* round 22 */
-               SUBKEY_R(29) = subR[28] ^ subR[30];
-               SUBKEY_L(30) = subL[29] ^ subL[31]; /* round 23 */
-               SUBKEY_R(30) = subR[29] ^ subR[31];
-               SUBKEY_L(31) = subL[30];     /* round 24 */
-               SUBKEY_R(31) = subR[30];
-               SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */
-               SUBKEY_R(32) = subR[32] ^ subR[31];
-       }
-
-       /* apply the inverse of the last half of P-function */
-       i = 2;
-       do {
-               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */
-               SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
-               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */
-               SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
-               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */
-               SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
-               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */
-               SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
-               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 8);/* round 5 */
-               SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
-               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */
-               SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
-               i += 8;
-       } while (i < max);
-}
-
-static void camellia_setup128(const unsigned char *key, u32 *subkey)
-{
-       u32 kll, klr, krl, krr;
-       u32 il, ir, t0, t1, w0, w1;
-       u32 subL[26];
-       u32 subR[26];
-
-       /**
-        *  k == kll || klr || krl || krr (|| is concatenation)
-        */
-       kll = get_unaligned_be32(key);
-       klr = get_unaligned_be32(key + 4);
-       krl = get_unaligned_be32(key + 8);
-       krr = get_unaligned_be32(key + 12);
-
-       /* generate KL dependent subkeys */
-       /* kw1 */
-       subL[0] = kll; subR[0] = klr;
-       /* kw2 */
-       subL[1] = krl; subR[1] = krr;
-       /* rotation left shift 15bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k3 */
-       subL[4] = kll; subR[4] = klr;
-       /* k4 */
-       subL[5] = krl; subR[5] = krr;
-       /* rotation left shift 15+30bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
-       /* k7 */
-       subL[10] = kll; subR[10] = klr;
-       /* k8 */
-       subL[11] = krl; subR[11] = krr;
-       /* rotation left shift 15+30+15bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k10 */
-       subL[13] = krl; subR[13] = krr;
-       /* rotation left shift 15+30+15+17 bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
-       /* kl3 */
-       subL[16] = kll; subR[16] = klr;
-       /* kl4 */
-       subL[17] = krl; subR[17] = krr;
-       /* rotation left shift 15+30+15+17+17 bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
-       /* k13 */
-       subL[18] = kll; subR[18] = klr;
-       /* k14 */
-       subL[19] = krl; subR[19] = krr;
-       /* rotation left shift 15+30+15+17+17+17 bit */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
-       /* k17 */
-       subL[22] = kll; subR[22] = klr;
-       /* k18 */
-       subL[23] = krl; subR[23] = krr;
-
-       /* generate KA */
-       kll = subL[0]; klr = subR[0];
-       krl = subL[1]; krr = subR[1];
-       CAMELLIA_F(kll, klr,
-                  CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
-                  w0, w1, il, ir, t0, t1);
-       krl ^= w0; krr ^= w1;
-       CAMELLIA_F(krl, krr,
-                  CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
-                  kll, klr, il, ir, t0, t1);
-       /* current status == (kll, klr, w0, w1) */
-       CAMELLIA_F(kll, klr,
-                  CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
-                  krl, krr, il, ir, t0, t1);
-       krl ^= w0; krr ^= w1;
-       CAMELLIA_F(krl, krr,
-                  CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
-                  w0, w1, il, ir, t0, t1);
-       kll ^= w0; klr ^= w1;
-
-       /* generate KA dependent subkeys */
-       /* k1, k2 */
-       subL[2] = kll; subR[2] = klr;
-       subL[3] = krl; subR[3] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k5,k6 */
-       subL[6] = kll; subR[6] = klr;
-       subL[7] = krl; subR[7] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* kl1, kl2 */
-       subL[8] = kll; subR[8] = klr;
-       subL[9] = krl; subR[9] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k9 */
-       subL[12] = kll; subR[12] = klr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k11, k12 */
-       subL[14] = kll; subR[14] = klr;
-       subL[15] = krl; subR[15] = krr;
-       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
-       /* k15, k16 */
-       subL[20] = kll; subR[20] = klr;
-       subL[21] = krl; subR[21] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
-       /* kw3, kw4 */
-       subL[24] = kll; subR[24] = klr;
-       subL[25] = krl; subR[25] = krr;
-
-       camellia_setup_tail(subkey, subL, subR, 24);
-}
-
-static void camellia_setup256(const unsigned char *key, u32 *subkey)
-{
-       u32 kll, klr, krl, krr;        /* left half of key */
-       u32 krll, krlr, krrl, krrr;    /* right half of key */
-       u32 il, ir, t0, t1, w0, w1;    /* temporary variables */
-       u32 subL[34];
-       u32 subR[34];
-
-       /**
-        *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
-        *  (|| is concatenation)
-        */
-       kll = get_unaligned_be32(key);
-       klr = get_unaligned_be32(key + 4);
-       krl = get_unaligned_be32(key + 8);
-       krr = get_unaligned_be32(key + 12);
-       krll = get_unaligned_be32(key + 16);
-       krlr = get_unaligned_be32(key + 20);
-       krrl = get_unaligned_be32(key + 24);
-       krrr = get_unaligned_be32(key + 28);
-
-       /* generate KL dependent subkeys */
-       /* kw1 */
-       subL[0] = kll; subR[0] = klr;
-       /* kw2 */
-       subL[1] = krl; subR[1] = krr;
-       ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
-       /* k9 */
-       subL[12] = kll; subR[12] = klr;
-       /* k10 */
-       subL[13] = krl; subR[13] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* kl3 */
-       subL[16] = kll; subR[16] = klr;
-       /* kl4 */
-       subL[17] = krl; subR[17] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
-       /* k17 */
-       subL[22] = kll; subR[22] = klr;
-       /* k18 */
-       subL[23] = krl; subR[23] = krr;
-       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
-       /* k23 */
-       subL[30] = kll; subR[30] = klr;
-       /* k24 */
-       subL[31] = krl; subR[31] = krr;
-
-       /* generate KR dependent subkeys */
-       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
-       /* k3 */
-       subL[4] = krll; subR[4] = krlr;
-       /* k4 */
-       subL[5] = krrl; subR[5] = krrr;
-       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
-       /* kl1 */
-       subL[8] = krll; subR[8] = krlr;
-       /* kl2 */
-       subL[9] = krrl; subR[9] = krrr;
-       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
-       /* k13 */
-       subL[18] = krll; subR[18] = krlr;
-       /* k14 */
-       subL[19] = krrl; subR[19] = krrr;
-       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
-       /* k19 */
-       subL[26] = krll; subR[26] = krlr;
-       /* k20 */
-       subL[27] = krrl; subR[27] = krrr;
-       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
-
-       /* generate KA */
-       kll = subL[0] ^ krll; klr = subR[0] ^ krlr;
-       krl = subL[1] ^ krrl; krr = subR[1] ^ krrr;
-       CAMELLIA_F(kll, klr,
-                  CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
-                  w0, w1, il, ir, t0, t1);
-       krl ^= w0; krr ^= w1;
-       CAMELLIA_F(krl, krr,
-                  CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
-                  kll, klr, il, ir, t0, t1);
-       kll ^= krll; klr ^= krlr;
-       CAMELLIA_F(kll, klr,
-                  CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
-                  krl, krr, il, ir, t0, t1);
-       krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
-       CAMELLIA_F(krl, krr,
-                  CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
-                  w0, w1, il, ir, t0, t1);
-       kll ^= w0; klr ^= w1;
-
-       /* generate KB */
-       krll ^= kll; krlr ^= klr;
-       krrl ^= krl; krrr ^= krr;
-       CAMELLIA_F(krll, krlr,
-                  CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
-                  w0, w1, il, ir, t0, t1);
-       krrl ^= w0; krrr ^= w1;
-       CAMELLIA_F(krrl, krrr,
-                  CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
-                  w0, w1, il, ir, t0, t1);
-       krll ^= w0; krlr ^= w1;
-
-       /* generate KA dependent subkeys */
-       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
-       /* k5 */
-       subL[6] = kll; subR[6] = klr;
-       /* k6 */
-       subL[7] = krl; subR[7] = krr;
-       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
-       /* k11 */
-       subL[14] = kll; subR[14] = klr;
-       /* k12 */
-       subL[15] = krl; subR[15] = krr;
-       /* rotation left shift 32bit */
-       /* kl5 */
-       subL[24] = klr; subR[24] = krl;
-       /* kl6 */
-       subL[25] = krr; subR[25] = kll;
-       /* rotation left shift 49 from k11,k12 -> k21,k22 */
-       ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
-       /* k21 */
-       subL[28] = kll; subR[28] = klr;
-       /* k22 */
-       subL[29] = krl; subR[29] = krr;
-
-       /* generate KB dependent subkeys */
-       /* k1 */
-       subL[2] = krll; subR[2] = krlr;
-       /* k2 */
-       subL[3] = krrl; subR[3] = krrr;
-       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
-       /* k7 */
-       subL[10] = krll; subR[10] = krlr;
-       /* k8 */
-       subL[11] = krrl; subR[11] = krrr;
-       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
-       /* k15 */
-       subL[20] = krll; subR[20] = krlr;
-       /* k16 */
-       subL[21] = krrl; subR[21] = krrr;
-       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
-       /* kw3 */
-       subL[32] = krll; subR[32] = krlr;
-       /* kw4 */
-       subL[33] = krrl; subR[33] = krrr;
-
-       camellia_setup_tail(subkey, subL, subR, 32);
-}
-
-static void camellia_setup192(const unsigned char *key, u32 *subkey)
-{
-       unsigned char kk[32];
-       u32 krll, krlr, krrl, krrr;
-
-       memcpy(kk, key, 24);
-       memcpy((unsigned char *)&krll, key+16, 4);
-       memcpy((unsigned char *)&krlr, key+20, 4);
-       krrl = ~krll;
-       krrr = ~krlr;
-       memcpy(kk+24, (unsigned char *)&krrl, 4);
-       memcpy(kk+28, (unsigned char *)&krrr, 4);
-       camellia_setup256(kk, subkey);
-}
-
-
-/*
- * Encrypt/decrypt
- */
-#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \
-    do {                                                               \
-       t0 = kll;                                                       \
-       t2 = krr;                                                       \
-       t0 &= ll;                                                       \
-       t2 |= rr;                                                       \
-       rl ^= t2;                                                       \
-       lr ^= rol32(t0, 1);                                             \
-       t3 = krl;                                                       \
-       t1 = klr;                                                       \
-       t3 &= rl;                                                       \
-       t1 |= lr;                                                       \
-       ll ^= t1;                                                       \
-       rr ^= rol32(t3, 1);                                             \
-    } while (0)
-
-#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)               \
-    do {                                                               \
-       ir =  camellia_sp1110[(u8)xr];                                  \
-       il =  camellia_sp1110[    (xl >> 24)];                          \
-       ir ^= camellia_sp0222[    (xr >> 24)];                          \
-       il ^= camellia_sp0222[(u8)(xl >> 16)];                          \
-       ir ^= camellia_sp3033[(u8)(xr >> 16)];                          \
-       il ^= camellia_sp3033[(u8)(xl >> 8)];                           \
-       ir ^= camellia_sp4404[(u8)(xr >> 8)];                           \
-       il ^= camellia_sp4404[(u8)xl];                                  \
-       il ^= kl;                                                       \
-       ir ^= il ^ kr;                                                  \
-       yl ^= ir;                                                       \
-       yr ^= ror32(il, 8) ^ ir;                                                \
-    } while (0)
-
-/* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
-static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max)
-{
-       u32 il, ir, t0, t1;            /* temporary variables */
-
-       /* pre whitening but absorb kw2 */
-       io[0] ^= SUBKEY_L(0);
-       io[1] ^= SUBKEY_R(0);
-
-       /* main iteration */
-#define ROUNDS(i) do { \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 2), SUBKEY_R(i + 2), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 3), SUBKEY_R(i + 3), \
-                        io[0], io[1], il, ir); \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 4), SUBKEY_R(i + 4), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 5), SUBKEY_R(i + 5), \
-                        io[0], io[1], il, ir); \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 6), SUBKEY_R(i + 6), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 7), SUBKEY_R(i + 7), \
-                        io[0], io[1], il, ir); \
-} while (0)
-#define FLS(i) do { \
-       CAMELLIA_FLS(io[0], io[1], io[2], io[3], \
-                    SUBKEY_L(i + 0), SUBKEY_R(i + 0), \
-                    SUBKEY_L(i + 1), SUBKEY_R(i + 1), \
-                    t0, t1, il, ir); \
-} while (0)
-
-       ROUNDS(0);
-       FLS(8);
-       ROUNDS(8);
-       FLS(16);
-       ROUNDS(16);
-       if (max == 32) {
-               FLS(24);
-               ROUNDS(24);
-       }
-
-#undef ROUNDS
-#undef FLS
-
-       /* post whitening but kw4 */
-       io[2] ^= SUBKEY_L(max);
-       io[3] ^= SUBKEY_R(max);
-       /* NB: io[0],[1] should be swapped with [2],[3] by caller! */
-}
-
-static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i)
-{
-       u32 il, ir, t0, t1;            /* temporary variables */
-
-       /* pre whitening but absorb kw2 */
-       io[0] ^= SUBKEY_L(i);
-       io[1] ^= SUBKEY_R(i);
-
-       /* main iteration */
-#define ROUNDS(i) do { \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 7), SUBKEY_R(i + 7), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 6), SUBKEY_R(i + 6), \
-                        io[0], io[1], il, ir); \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 5), SUBKEY_R(i + 5), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 4), SUBKEY_R(i + 4), \
-                        io[0], io[1], il, ir); \
-       CAMELLIA_ROUNDSM(io[0], io[1], \
-                        SUBKEY_L(i + 3), SUBKEY_R(i + 3), \
-                        io[2], io[3], il, ir); \
-       CAMELLIA_ROUNDSM(io[2], io[3], \
-                        SUBKEY_L(i + 2), SUBKEY_R(i + 2), \
-                        io[0], io[1], il, ir); \
-} while (0)
-#define FLS(i) do { \
-       CAMELLIA_FLS(io[0], io[1], io[2], io[3], \
-                    SUBKEY_L(i + 1), SUBKEY_R(i + 1), \
-                    SUBKEY_L(i + 0), SUBKEY_R(i + 0), \
-                    t0, t1, il, ir); \
-} while (0)
-
-       if (i == 32) {
-               ROUNDS(24);
-               FLS(24);
-       }
-       ROUNDS(16);
-       FLS(16);
-       ROUNDS(8);
-       FLS(8);
-       ROUNDS(0);
-
-#undef ROUNDS
-#undef FLS
-
-       /* post whitening but kw4 */
-       io[2] ^= SUBKEY_L(0);
-       io[3] ^= SUBKEY_R(0);
-       /* NB: 0,1 should be swapped with 2,3 by caller! */
-}
-
-
-struct camellia_ctx {
-       int key_length;
-       u32 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u32)];
-};
-
-static int
-camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-                unsigned int key_len)
-{
-       struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
-       const unsigned char *key = (const unsigned char *)in_key;
-       u32 *flags = &tfm->crt_flags;
-
-       if (key_len != 16 && key_len != 24 && key_len != 32) {
-               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-               return -EINVAL;
-       }
-
-       cctx->key_length = key_len;
-
-       switch (key_len) {
-       case 16:
-               camellia_setup128(key, cctx->key_table);
-               break;
-       case 24:
-               camellia_setup192(key, cctx->key_table);
-               break;
-       case 32:
-               camellia_setup256(key, cctx->key_table);
-               break;
-       }
-
-       return 0;
-}
-
-static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-{
-       const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
-       const __be32 *src = (const __be32 *)in;
-       __be32 *dst = (__be32 *)out;
-
-       u32 tmp[4];
-
-       tmp[0] = be32_to_cpu(src[0]);
-       tmp[1] = be32_to_cpu(src[1]);
-       tmp[2] = be32_to_cpu(src[2]);
-       tmp[3] = be32_to_cpu(src[3]);
-
-       camellia_do_encrypt(cctx->key_table, tmp,
-               cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */
-       );
-
-       /* do_encrypt returns 0,1 swapped with 2,3 */
-       dst[0] = cpu_to_be32(tmp[2]);
-       dst[1] = cpu_to_be32(tmp[3]);
-       dst[2] = cpu_to_be32(tmp[0]);
-       dst[3] = cpu_to_be32(tmp[1]);
-}
-
-static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-{
-       const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
-       const __be32 *src = (const __be32 *)in;
-       __be32 *dst = (__be32 *)out;
-
-       u32 tmp[4];
-
-       tmp[0] = be32_to_cpu(src[0]);
-       tmp[1] = be32_to_cpu(src[1]);
-       tmp[2] = be32_to_cpu(src[2]);
-       tmp[3] = be32_to_cpu(src[3]);
-
-       camellia_do_decrypt(cctx->key_table, tmp,
-               cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */
-       );
-
-       /* do_decrypt returns 0,1 swapped with 2,3 */
-       dst[0] = cpu_to_be32(tmp[2]);
-       dst[1] = cpu_to_be32(tmp[3]);
-       dst[2] = cpu_to_be32(tmp[0]);
-       dst[3] = cpu_to_be32(tmp[1]);
-}
-
-static struct crypto_alg camellia_alg = {
-       .cra_name               =       "camellia",
-       .cra_driver_name        =       "camellia-generic",
-       .cra_priority           =       100,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       CAMELLIA_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct camellia_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(camellia_alg.cra_list),
-       .cra_u                  =       {
-               .cipher = {
-                       .cia_min_keysize        =       CAMELLIA_MIN_KEY_SIZE,
-                       .cia_max_keysize        =       CAMELLIA_MAX_KEY_SIZE,
-                       .cia_setkey             =       camellia_set_key,
-                       .cia_encrypt            =       camellia_encrypt,
-                       .cia_decrypt            =       camellia_decrypt
-               }
-       }
-};
-
-static int __init camellia_init(void)
-{
-       return crypto_register_alg(&camellia_alg);
-}
-
-static void __exit camellia_fini(void)
-{
-       crypto_unregister_alg(&camellia_alg);
-}
-
-module_init(camellia_init);
-module_exit(camellia_fini);
-
-MODULE_DESCRIPTION("Camellia Cipher Algorithm");
-MODULE_LICENSE("GPL");
diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c
new file mode 100644 (file)
index 0000000..f7aaaaf
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (C) 2006
+ * NTT (Nippon Telegraph and Telephone 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; 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.
+ */
+
+/*
+ * Algorithm Specification
+ *  http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html
+ */
+
+/*
+ *
+ * NOTE --- NOTE --- NOTE --- NOTE
+ * This implementation assumes that all memory addresses passed
+ * as parameters are four-byte aligned.
+ *
+ */
+
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
+
+static const u32 camellia_sp1110[256] = {
+       0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00,
+       0xb3b3b300, 0x27272700, 0xc0c0c000, 0xe5e5e500,
+       0xe4e4e400, 0x85858500, 0x57575700, 0x35353500,
+       0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100,
+       0x23232300, 0xefefef00, 0x6b6b6b00, 0x93939300,
+       0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
+       0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00,
+       0x1d1d1d00, 0x65656500, 0x92929200, 0xbdbdbd00,
+       0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00,
+       0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00,
+       0x3e3e3e00, 0x30303000, 0xdcdcdc00, 0x5f5f5f00,
+       0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
+       0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00,
+       0xd5d5d500, 0x47474700, 0x5d5d5d00, 0x3d3d3d00,
+       0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600,
+       0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00,
+       0x8b8b8b00, 0x0d0d0d00, 0x9a9a9a00, 0x66666600,
+       0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
+       0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000,
+       0xf0f0f000, 0xb1b1b100, 0x84848400, 0x99999900,
+       0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200,
+       0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500,
+       0x6d6d6d00, 0xb7b7b700, 0xa9a9a900, 0x31313100,
+       0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
+       0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100,
+       0xdedede00, 0x1b1b1b00, 0x11111100, 0x1c1c1c00,
+       0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600,
+       0x53535300, 0x18181800, 0xf2f2f200, 0x22222200,
+       0xfefefe00, 0x44444400, 0xcfcfcf00, 0xb2b2b200,
+       0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
+       0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800,
+       0x60606000, 0xfcfcfc00, 0x69696900, 0x50505000,
+       0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00,
+       0xa1a1a100, 0x89898900, 0x62626200, 0x97979700,
+       0x54545400, 0x5b5b5b00, 0x1e1e1e00, 0x95959500,
+       0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
+       0x10101000, 0xc4c4c400, 0x00000000, 0x48484800,
+       0xa3a3a300, 0xf7f7f700, 0x75757500, 0xdbdbdb00,
+       0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00,
+       0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400,
+       0x87878700, 0x5c5c5c00, 0x83838300, 0x02020200,
+       0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
+       0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300,
+       0x9d9d9d00, 0x7f7f7f00, 0xbfbfbf00, 0xe2e2e200,
+       0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600,
+       0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00,
+       0x81818100, 0x96969600, 0x6f6f6f00, 0x4b4b4b00,
+       0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
+       0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00,
+       0x9f9f9f00, 0x6e6e6e00, 0xbcbcbc00, 0x8e8e8e00,
+       0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600,
+       0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900,
+       0x78787800, 0x98989800, 0x06060600, 0x6a6a6a00,
+       0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
+       0xd4d4d400, 0x25252500, 0xababab00, 0x42424200,
+       0x88888800, 0xa2a2a200, 0x8d8d8d00, 0xfafafa00,
+       0x72727200, 0x07070700, 0xb9b9b900, 0x55555500,
+       0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00,
+       0x36363600, 0x49494900, 0x2a2a2a00, 0x68686800,
+       0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
+       0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00,
+       0xbbbbbb00, 0xc9c9c900, 0x43434300, 0xc1c1c100,
+       0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400,
+       0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00,
+};
+
+static const u32 camellia_sp0222[256] = {
+       0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9,
+       0x00676767, 0x004e4e4e, 0x00818181, 0x00cbcbcb,
+       0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a,
+       0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282,
+       0x00464646, 0x00dfdfdf, 0x00d6d6d6, 0x00272727,
+       0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
+       0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c,
+       0x003a3a3a, 0x00cacaca, 0x00252525, 0x007b7b7b,
+       0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f,
+       0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d,
+       0x007c7c7c, 0x00606060, 0x00b9b9b9, 0x00bebebe,
+       0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
+       0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595,
+       0x00ababab, 0x008e8e8e, 0x00bababa, 0x007a7a7a,
+       0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad,
+       0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a,
+       0x00171717, 0x001a1a1a, 0x00353535, 0x00cccccc,
+       0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
+       0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040,
+       0x00e1e1e1, 0x00636363, 0x00090909, 0x00333333,
+       0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585,
+       0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a,
+       0x00dadada, 0x006f6f6f, 0x00535353, 0x00626262,
+       0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
+       0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2,
+       0x00bdbdbd, 0x00363636, 0x00222222, 0x00383838,
+       0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c,
+       0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444,
+       0x00fdfdfd, 0x00888888, 0x009f9f9f, 0x00656565,
+       0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
+       0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151,
+       0x00c0c0c0, 0x00f9f9f9, 0x00d2d2d2, 0x00a0a0a0,
+       0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa,
+       0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f,
+       0x00a8a8a8, 0x00b6b6b6, 0x003c3c3c, 0x002b2b2b,
+       0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
+       0x00202020, 0x00898989, 0x00000000, 0x00909090,
+       0x00474747, 0x00efefef, 0x00eaeaea, 0x00b7b7b7,
+       0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5,
+       0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929,
+       0x000f0f0f, 0x00b8b8b8, 0x00070707, 0x00040404,
+       0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
+       0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7,
+       0x003b3b3b, 0x00fefefe, 0x007f7f7f, 0x00c5c5c5,
+       0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c,
+       0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676,
+       0x00030303, 0x002d2d2d, 0x00dedede, 0x00969696,
+       0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
+       0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919,
+       0x003f3f3f, 0x00dcdcdc, 0x00797979, 0x001d1d1d,
+       0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d,
+       0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2,
+       0x00f0f0f0, 0x00313131, 0x000c0c0c, 0x00d4d4d4,
+       0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
+       0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484,
+       0x00111111, 0x00454545, 0x001b1b1b, 0x00f5f5f5,
+       0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa,
+       0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414,
+       0x006c6c6c, 0x00929292, 0x00545454, 0x00d0d0d0,
+       0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
+       0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6,
+       0x00777777, 0x00939393, 0x00868686, 0x00838383,
+       0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9,
+       0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d,
+};
+
+static const u32 camellia_sp3033[256] = {
+       0x38003838, 0x41004141, 0x16001616, 0x76007676,
+       0xd900d9d9, 0x93009393, 0x60006060, 0xf200f2f2,
+       0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a,
+       0x75007575, 0x06000606, 0x57005757, 0xa000a0a0,
+       0x91009191, 0xf700f7f7, 0xb500b5b5, 0xc900c9c9,
+       0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
+       0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727,
+       0x8e008e8e, 0xb200b2b2, 0x49004949, 0xde00dede,
+       0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7,
+       0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767,
+       0x1f001f1f, 0x18001818, 0x6e006e6e, 0xaf00afaf,
+       0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
+       0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565,
+       0xea00eaea, 0xa300a3a3, 0xae00aeae, 0x9e009e9e,
+       0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b,
+       0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6,
+       0xc500c5c5, 0x86008686, 0x4d004d4d, 0x33003333,
+       0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
+       0x3a003a3a, 0x09000909, 0x95009595, 0x10001010,
+       0x78007878, 0xd800d8d8, 0x42004242, 0xcc00cccc,
+       0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161,
+       0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282,
+       0xb600b6b6, 0xdb00dbdb, 0xd400d4d4, 0x98009898,
+       0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
+       0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0,
+       0x6f006f6f, 0x8d008d8d, 0x88008888, 0x0e000e0e,
+       0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b,
+       0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111,
+       0x7f007f7f, 0x22002222, 0xe700e7e7, 0x59005959,
+       0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
+       0x12001212, 0x04000404, 0x74007474, 0x54005454,
+       0x30003030, 0x7e007e7e, 0xb400b4b4, 0x28002828,
+       0x55005555, 0x68006868, 0x50005050, 0xbe00bebe,
+       0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb,
+       0x2a002a2a, 0xad00adad, 0x0f000f0f, 0xca00caca,
+       0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
+       0x08000808, 0x62006262, 0x00000000, 0x24002424,
+       0xd100d1d1, 0xfb00fbfb, 0xba00baba, 0xed00eded,
+       0x45004545, 0x81008181, 0x73007373, 0x6d006d6d,
+       0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a,
+       0xc300c3c3, 0x2e002e2e, 0xc100c1c1, 0x01000101,
+       0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
+       0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9,
+       0xce00cece, 0xbf00bfbf, 0xdf00dfdf, 0x71007171,
+       0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313,
+       0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d,
+       0xc000c0c0, 0x4b004b4b, 0xb700b7b7, 0xa500a5a5,
+       0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
+       0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646,
+       0xcf00cfcf, 0x37003737, 0x5e005e5e, 0x47004747,
+       0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b,
+       0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac,
+       0x3c003c3c, 0x4c004c4c, 0x03000303, 0x35003535,
+       0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
+       0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121,
+       0x44004444, 0x51005151, 0xc600c6c6, 0x7d007d7d,
+       0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa,
+       0x7c007c7c, 0x77007777, 0x56005656, 0x05000505,
+       0x1b001b1b, 0xa400a4a4, 0x15001515, 0x34003434,
+       0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
+       0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd,
+       0xdd00dddd, 0xe400e4e4, 0xa100a1a1, 0xe000e0e0,
+       0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a,
+       0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f,
+};
+
+static const u32 camellia_sp4404[256] = {
+       0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0,
+       0xe4e400e4, 0x57570057, 0xeaea00ea, 0xaeae00ae,
+       0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5,
+       0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092,
+       0x86860086, 0xafaf00af, 0x7c7c007c, 0x1f1f001f,
+       0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
+       0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d,
+       0xd9d900d9, 0x5a5a005a, 0x51510051, 0x6c6c006c,
+       0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0,
+       0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084,
+       0xdfdf00df, 0xcbcb00cb, 0x34340034, 0x76760076,
+       0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
+       0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011,
+       0x32320032, 0x9c9c009c, 0x53530053, 0xf2f200f2,
+       0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a,
+       0x24240024, 0xe8e800e8, 0x60600060, 0x69690069,
+       0xaaaa00aa, 0xa0a000a0, 0xa1a100a1, 0x62620062,
+       0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
+       0x10100010, 0x00000000, 0xa3a300a3, 0x75750075,
+       0x8a8a008a, 0xe6e600e6, 0x09090009, 0xdddd00dd,
+       0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090,
+       0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf,
+       0x52520052, 0xd8d800d8, 0xc8c800c8, 0xc6c600c6,
+       0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
+       0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc,
+       0x29290029, 0xf9f900f9, 0x2f2f002f, 0xb4b400b4,
+       0x78780078, 0x06060006, 0xe7e700e7, 0x71710071,
+       0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d,
+       0x72720072, 0xb9b900b9, 0xf8f800f8, 0xacac00ac,
+       0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
+       0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043,
+       0x15150015, 0xadad00ad, 0x77770077, 0x80800080,
+       0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5,
+       0x85850085, 0x35350035, 0x0c0c000c, 0x41410041,
+       0xefef00ef, 0x93930093, 0x19190019, 0x21210021,
+       0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
+       0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce,
+       0x30300030, 0x5f5f005f, 0xc5c500c5, 0x1a1a001a,
+       0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d,
+       0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d,
+       0x0d0d000d, 0x66660066, 0xcccc00cc, 0x2d2d002d,
+       0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
+       0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005,
+       0xb7b700b7, 0x31310031, 0x17170017, 0xd7d700d7,
+       0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c,
+       0x0f0f000f, 0x16160016, 0x18180018, 0x22220022,
+       0x44440044, 0xb2b200b2, 0xb5b500b5, 0x91910091,
+       0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
+       0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097,
+       0x5b5b005b, 0x95950095, 0xffff00ff, 0xd2d200d2,
+       0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db,
+       0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094,
+       0x5c5c005c, 0x02020002, 0x4a4a004a, 0x33330033,
+       0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
+       0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b,
+       0x96960096, 0x4b4b004b, 0xbebe00be, 0x2e2e002e,
+       0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e,
+       0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059,
+       0x98980098, 0x6a6a006a, 0x46460046, 0xbaba00ba,
+       0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
+       0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a,
+       0x49490049, 0x68680068, 0x38380038, 0xa4a400a4,
+       0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1,
+       0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e,
+};
+
+
+#define CAMELLIA_MIN_KEY_SIZE        16
+#define CAMELLIA_MAX_KEY_SIZE        32
+#define CAMELLIA_BLOCK_SIZE          16
+#define CAMELLIA_TABLE_BYTE_LEN     272
+
+/*
+ * NB: L and R below stand for 'left' and 'right' as in written numbers.
+ * That is, in (xxxL,xxxR) pair xxxL holds most significant digits,
+ * _not_ least significant ones!
+ */
+
+
+/* key constants */
+
+#define CAMELLIA_SIGMA1L (0xA09E667FL)
+#define CAMELLIA_SIGMA1R (0x3BCC908BL)
+#define CAMELLIA_SIGMA2L (0xB67AE858L)
+#define CAMELLIA_SIGMA2R (0x4CAA73B2L)
+#define CAMELLIA_SIGMA3L (0xC6EF372FL)
+#define CAMELLIA_SIGMA3R (0xE94F82BEL)
+#define CAMELLIA_SIGMA4L (0x54FF53A5L)
+#define CAMELLIA_SIGMA4R (0xF1D36F1CL)
+#define CAMELLIA_SIGMA5L (0x10E527FAL)
+#define CAMELLIA_SIGMA5R (0xDE682D1DL)
+#define CAMELLIA_SIGMA6L (0xB05688C2L)
+#define CAMELLIA_SIGMA6R (0xB3E6C1FDL)
+
+/*
+ *  macros
+ */
+#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) ({         \
+       w0 = ll;                                        \
+       ll = (ll << bits) + (lr >> (32 - bits));        \
+       lr = (lr << bits) + (rl >> (32 - bits));        \
+       rl = (rl << bits) + (rr >> (32 - bits));        \
+       rr = (rr << bits) + (w0 >> (32 - bits));        \
+})
+
+#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) ({      \
+       w0 = ll;                                        \
+       w1 = lr;                                        \
+       ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \
+       lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \
+       rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \
+       rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \
+})
+
+#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) ({  \
+       il = xl ^ kl;                                           \
+       ir = xr ^ kr;                                           \
+       t0 = il >> 16;                                          \
+       t1 = ir >> 16;                                          \
+       yl = camellia_sp1110[(u8)(ir)]                          \
+          ^ camellia_sp0222[(u8)(t1 >> 8)]                     \
+          ^ camellia_sp3033[(u8)(t1)]                          \
+          ^ camellia_sp4404[(u8)(ir >> 8)];                    \
+       yr = camellia_sp1110[(u8)(t0 >> 8)]                     \
+          ^ camellia_sp0222[(u8)(t0)]                          \
+          ^ camellia_sp3033[(u8)(il >> 8)]                     \
+          ^ camellia_sp4404[(u8)(il)];                         \
+       yl ^= yr;                                               \
+       yr = ror32(yr, 8);                                      \
+       yr ^= yl;                                               \
+})
+
+#define SUBKEY_L(INDEX) (subkey[(INDEX)*2])
+#define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1])
+
+static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
+{
+       u32 dw, tl, tr;
+       u32 kw4l, kw4r;
+
+       /* absorb kw2 to other subkeys */
+       /* round 2 */
+       subL[3] ^= subL[1]; subR[3] ^= subR[1];
+       /* round 4 */
+       subL[5] ^= subL[1]; subR[5] ^= subR[1];
+       /* round 6 */
+       subL[7] ^= subL[1]; subR[7] ^= subR[1];
+       subL[1] ^= subR[1] & ~subR[9];
+       dw = subL[1] & subL[9],
+               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
+       /* round 8 */
+       subL[11] ^= subL[1]; subR[11] ^= subR[1];
+       /* round 10 */
+       subL[13] ^= subL[1]; subR[13] ^= subR[1];
+       /* round 12 */
+       subL[15] ^= subL[1]; subR[15] ^= subR[1];
+       subL[1] ^= subR[1] & ~subR[17];
+       dw = subL[1] & subL[17],
+               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
+       /* round 14 */
+       subL[19] ^= subL[1]; subR[19] ^= subR[1];
+       /* round 16 */
+       subL[21] ^= subL[1]; subR[21] ^= subR[1];
+       /* round 18 */
+       subL[23] ^= subL[1]; subR[23] ^= subR[1];
+       if (max == 24) {
+               /* kw3 */
+               subL[24] ^= subL[1]; subR[24] ^= subR[1];
+
+       /* absorb kw4 to other subkeys */
+               kw4l = subL[25]; kw4r = subR[25];
+       } else {
+               subL[1] ^= subR[1] & ~subR[25];
+               dw = subL[1] & subL[25],
+                       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
+               /* round 20 */
+               subL[27] ^= subL[1]; subR[27] ^= subR[1];
+               /* round 22 */
+               subL[29] ^= subL[1]; subR[29] ^= subR[1];
+               /* round 24 */
+               subL[31] ^= subL[1]; subR[31] ^= subR[1];
+               /* kw3 */
+               subL[32] ^= subL[1]; subR[32] ^= subR[1];
+
+       /* absorb kw4 to other subkeys */
+               kw4l = subL[33]; kw4r = subR[33];
+               /* round 23 */
+               subL[30] ^= kw4l; subR[30] ^= kw4r;
+               /* round 21 */
+               subL[28] ^= kw4l; subR[28] ^= kw4r;
+               /* round 19 */
+               subL[26] ^= kw4l; subR[26] ^= kw4r;
+               kw4l ^= kw4r & ~subR[24];
+               dw = kw4l & subL[24],
+                       kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
+       }
+       /* round 17 */
+       subL[22] ^= kw4l; subR[22] ^= kw4r;
+       /* round 15 */
+       subL[20] ^= kw4l; subR[20] ^= kw4r;
+       /* round 13 */
+       subL[18] ^= kw4l; subR[18] ^= kw4r;
+       kw4l ^= kw4r & ~subR[16];
+       dw = kw4l & subL[16],
+               kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
+       /* round 11 */
+       subL[14] ^= kw4l; subR[14] ^= kw4r;
+       /* round 9 */
+       subL[12] ^= kw4l; subR[12] ^= kw4r;
+       /* round 7 */
+       subL[10] ^= kw4l; subR[10] ^= kw4r;
+       kw4l ^= kw4r & ~subR[8];
+       dw = kw4l & subL[8],
+               kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
+       /* round 5 */
+       subL[6] ^= kw4l; subR[6] ^= kw4r;
+       /* round 3 */
+       subL[4] ^= kw4l; subR[4] ^= kw4r;
+       /* round 1 */
+       subL[2] ^= kw4l; subR[2] ^= kw4r;
+       /* kw1 */
+       subL[0] ^= kw4l; subR[0] ^= kw4r;
+
+       /* key XOR is end of F-function */
+       SUBKEY_L(0) = subL[0] ^ subL[2];/* kw1 */
+       SUBKEY_R(0) = subR[0] ^ subR[2];
+       SUBKEY_L(2) = subL[3];       /* round 1 */
+       SUBKEY_R(2) = subR[3];
+       SUBKEY_L(3) = subL[2] ^ subL[4]; /* round 2 */
+       SUBKEY_R(3) = subR[2] ^ subR[4];
+       SUBKEY_L(4) = subL[3] ^ subL[5]; /* round 3 */
+       SUBKEY_R(4) = subR[3] ^ subR[5];
+       SUBKEY_L(5) = subL[4] ^ subL[6]; /* round 4 */
+       SUBKEY_R(5) = subR[4] ^ subR[6];
+       SUBKEY_L(6) = subL[5] ^ subL[7]; /* round 5 */
+       SUBKEY_R(6) = subR[5] ^ subR[7];
+       tl = subL[10] ^ (subR[10] & ~subR[8]);
+       dw = tl & subL[8],  /* FL(kl1) */
+               tr = subR[10] ^ rol32(dw, 1);
+       SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
+       SUBKEY_R(7) = subR[6] ^ tr;
+       SUBKEY_L(8) = subL[8];       /* FL(kl1) */
+       SUBKEY_R(8) = subR[8];
+       SUBKEY_L(9) = subL[9];       /* FLinv(kl2) */
+       SUBKEY_R(9) = subR[9];
+       tl = subL[7] ^ (subR[7] & ~subR[9]);
+       dw = tl & subL[9],  /* FLinv(kl2) */
+               tr = subR[7] ^ rol32(dw, 1);
+       SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
+       SUBKEY_R(10) = tr ^ subR[11];
+       SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
+       SUBKEY_R(11) = subR[10] ^ subR[12];
+       SUBKEY_L(12) = subL[11] ^ subL[13]; /* round 9 */
+       SUBKEY_R(12) = subR[11] ^ subR[13];
+       SUBKEY_L(13) = subL[12] ^ subL[14]; /* round 10 */
+       SUBKEY_R(13) = subR[12] ^ subR[14];
+       SUBKEY_L(14) = subL[13] ^ subL[15]; /* round 11 */
+       SUBKEY_R(14) = subR[13] ^ subR[15];
+       tl = subL[18] ^ (subR[18] & ~subR[16]);
+       dw = tl & subL[16], /* FL(kl3) */
+               tr = subR[18] ^ rol32(dw, 1);
+       SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
+       SUBKEY_R(15) = subR[14] ^ tr;
+       SUBKEY_L(16) = subL[16];     /* FL(kl3) */
+       SUBKEY_R(16) = subR[16];
+       SUBKEY_L(17) = subL[17];     /* FLinv(kl4) */
+       SUBKEY_R(17) = subR[17];
+       tl = subL[15] ^ (subR[15] & ~subR[17]);
+       dw = tl & subL[17], /* FLinv(kl4) */
+               tr = subR[15] ^ rol32(dw, 1);
+       SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
+       SUBKEY_R(18) = tr ^ subR[19];
+       SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
+       SUBKEY_R(19) = subR[18] ^ subR[20];
+       SUBKEY_L(20) = subL[19] ^ subL[21]; /* round 15 */
+       SUBKEY_R(20) = subR[19] ^ subR[21];
+       SUBKEY_L(21) = subL[20] ^ subL[22]; /* round 16 */
+       SUBKEY_R(21) = subR[20] ^ subR[22];
+       SUBKEY_L(22) = subL[21] ^ subL[23]; /* round 17 */
+       SUBKEY_R(22) = subR[21] ^ subR[23];
+       if (max == 24) {
+               SUBKEY_L(23) = subL[22];     /* round 18 */
+               SUBKEY_R(23) = subR[22];
+               SUBKEY_L(24) = subL[24] ^ subL[23]; /* kw3 */
+               SUBKEY_R(24) = subR[24] ^ subR[23];
+       } else {
+               tl = subL[26] ^ (subR[26] & ~subR[24]);
+               dw = tl & subL[24], /* FL(kl5) */
+                       tr = subR[26] ^ rol32(dw, 1);
+               SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
+               SUBKEY_R(23) = subR[22] ^ tr;
+               SUBKEY_L(24) = subL[24];     /* FL(kl5) */
+               SUBKEY_R(24) = subR[24];
+               SUBKEY_L(25) = subL[25];     /* FLinv(kl6) */
+               SUBKEY_R(25) = subR[25];
+               tl = subL[23] ^ (subR[23] & ~subR[25]);
+               dw = tl & subL[25], /* FLinv(kl6) */
+                       tr = subR[23] ^ rol32(dw, 1);
+               SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
+               SUBKEY_R(26) = tr ^ subR[27];
+               SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
+               SUBKEY_R(27) = subR[26] ^ subR[28];
+               SUBKEY_L(28) = subL[27] ^ subL[29]; /* round 21 */
+               SUBKEY_R(28) = subR[27] ^ subR[29];
+               SUBKEY_L(29) = subL[28] ^ subL[30]; /* round 22 */
+               SUBKEY_R(29) = subR[28] ^ subR[30];
+               SUBKEY_L(30) = subL[29] ^ subL[31]; /* round 23 */
+               SUBKEY_R(30) = subR[29] ^ subR[31];
+               SUBKEY_L(31) = subL[30];     /* round 24 */
+               SUBKEY_R(31) = subR[30];
+               SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */
+               SUBKEY_R(32) = subR[32] ^ subR[31];
+       }
+}
+
+static void camellia_setup128(const unsigned char *key, u32 *subkey)
+{
+       u32 kll, klr, krl, krr;
+       u32 il, ir, t0, t1, w0, w1;
+       u32 subL[26];
+       u32 subR[26];
+
+       /**
+        *  k == kll || klr || krl || krr (|| is concatenation)
+        */
+       kll = get_unaligned_be32(key);
+       klr = get_unaligned_be32(key + 4);
+       krl = get_unaligned_be32(key + 8);
+       krr = get_unaligned_be32(key + 12);
+
+       /* generate KL dependent subkeys */
+       /* kw1 */
+       subL[0] = kll; subR[0] = klr;
+       /* kw2 */
+       subL[1] = krl; subR[1] = krr;
+       /* rotation left shift 15bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k3 */
+       subL[4] = kll; subR[4] = klr;
+       /* k4 */
+       subL[5] = krl; subR[5] = krr;
+       /* rotation left shift 15+30bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+       /* k7 */
+       subL[10] = kll; subR[10] = klr;
+       /* k8 */
+       subL[11] = krl; subR[11] = krr;
+       /* rotation left shift 15+30+15bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k10 */
+       subL[13] = krl; subR[13] = krr;
+       /* rotation left shift 15+30+15+17 bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       /* kl3 */
+       subL[16] = kll; subR[16] = klr;
+       /* kl4 */
+       subL[17] = krl; subR[17] = krr;
+       /* rotation left shift 15+30+15+17+17 bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       /* k13 */
+       subL[18] = kll; subR[18] = klr;
+       /* k14 */
+       subL[19] = krl; subR[19] = krr;
+       /* rotation left shift 15+30+15+17+17+17 bit */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       /* k17 */
+       subL[22] = kll; subR[22] = klr;
+       /* k18 */
+       subL[23] = krl; subR[23] = krr;
+
+       /* generate KA */
+       kll = subL[0]; klr = subR[0];
+       krl = subL[1]; krr = subR[1];
+       CAMELLIA_F(kll, klr,
+                  CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+                  w0, w1, il, ir, t0, t1);
+       krl ^= w0; krr ^= w1;
+       CAMELLIA_F(krl, krr,
+                  CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+                  kll, klr, il, ir, t0, t1);
+       /* current status == (kll, klr, w0, w1) */
+       CAMELLIA_F(kll, klr,
+                  CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+                  krl, krr, il, ir, t0, t1);
+       krl ^= w0; krr ^= w1;
+       CAMELLIA_F(krl, krr,
+                  CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+                  w0, w1, il, ir, t0, t1);
+       kll ^= w0; klr ^= w1;
+
+       /* generate KA dependent subkeys */
+       /* k1, k2 */
+       subL[2] = kll; subR[2] = klr;
+       subL[3] = krl; subR[3] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k5,k6 */
+       subL[6] = kll; subR[6] = klr;
+       subL[7] = krl; subR[7] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* kl1, kl2 */
+       subL[8] = kll; subR[8] = klr;
+       subL[9] = krl; subR[9] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k9 */
+       subL[12] = kll; subR[12] = klr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k11, k12 */
+       subL[14] = kll; subR[14] = klr;
+       subL[15] = krl; subR[15] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+       /* k15, k16 */
+       subL[20] = kll; subR[20] = klr;
+       subL[21] = krl; subR[21] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       /* kw3, kw4 */
+       subL[24] = kll; subR[24] = klr;
+       subL[25] = krl; subR[25] = krr;
+
+       camellia_setup_tail(subkey, subL, subR, 24);
+}
+
+static void camellia_setup256(const unsigned char *key, u32 *subkey)
+{
+       u32 kll, klr, krl, krr;        /* left half of key */
+       u32 krll, krlr, krrl, krrr;    /* right half of key */
+       u32 il, ir, t0, t1, w0, w1;    /* temporary variables */
+       u32 subL[34];
+       u32 subR[34];
+
+       /**
+        *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
+        *  (|| is concatenation)
+        */
+       kll = get_unaligned_be32(key);
+       klr = get_unaligned_be32(key + 4);
+       krl = get_unaligned_be32(key + 8);
+       krr = get_unaligned_be32(key + 12);
+       krll = get_unaligned_be32(key + 16);
+       krlr = get_unaligned_be32(key + 20);
+       krrl = get_unaligned_be32(key + 24);
+       krrr = get_unaligned_be32(key + 28);
+
+       /* generate KL dependent subkeys */
+       /* kw1 */
+       subL[0] = kll; subR[0] = klr;
+       /* kw2 */
+       subL[1] = krl; subR[1] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 45);
+       /* k9 */
+       subL[12] = kll; subR[12] = klr;
+       /* k10 */
+       subL[13] = krl; subR[13] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* kl3 */
+       subL[16] = kll; subR[16] = klr;
+       /* kl4 */
+       subL[17] = krl; subR[17] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 17);
+       /* k17 */
+       subL[22] = kll; subR[22] = klr;
+       /* k18 */
+       subL[23] = krl; subR[23] = krr;
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 34);
+       /* k23 */
+       subL[30] = kll; subR[30] = klr;
+       /* k24 */
+       subL[31] = krl; subR[31] = krr;
+
+       /* generate KR dependent subkeys */
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+       /* k3 */
+       subL[4] = krll; subR[4] = krlr;
+       /* k4 */
+       subL[5] = krrl; subR[5] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 15);
+       /* kl1 */
+       subL[8] = krll; subR[8] = krlr;
+       /* kl2 */
+       subL[9] = krrl; subR[9] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       /* k13 */
+       subL[18] = krll; subR[18] = krlr;
+       /* k14 */
+       subL[19] = krrl; subR[19] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+       /* k19 */
+       subL[26] = krll; subR[26] = krlr;
+       /* k20 */
+       subL[27] = krrl; subR[27] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 34);
+
+       /* generate KA */
+       kll = subL[0] ^ krll; klr = subR[0] ^ krlr;
+       krl = subL[1] ^ krrl; krr = subR[1] ^ krrr;
+       CAMELLIA_F(kll, klr,
+                  CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R,
+                  w0, w1, il, ir, t0, t1);
+       krl ^= w0; krr ^= w1;
+       CAMELLIA_F(krl, krr,
+                  CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R,
+                  kll, klr, il, ir, t0, t1);
+       kll ^= krll; klr ^= krlr;
+       CAMELLIA_F(kll, klr,
+                  CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R,
+                  krl, krr, il, ir, t0, t1);
+       krl ^= w0 ^ krrl; krr ^= w1 ^ krrr;
+       CAMELLIA_F(krl, krr,
+                  CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R,
+                  w0, w1, il, ir, t0, t1);
+       kll ^= w0; klr ^= w1;
+
+       /* generate KB */
+       krll ^= kll; krlr ^= klr;
+       krrl ^= krl; krrr ^= krr;
+       CAMELLIA_F(krll, krlr,
+                  CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R,
+                  w0, w1, il, ir, t0, t1);
+       krrl ^= w0; krrr ^= w1;
+       CAMELLIA_F(krrl, krrr,
+                  CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R,
+                  w0, w1, il, ir, t0, t1);
+       krll ^= w0; krlr ^= w1;
+
+       /* generate KA dependent subkeys */
+       ROLDQ(kll, klr, krl, krr, w0, w1, 15);
+       /* k5 */
+       subL[6] = kll; subR[6] = klr;
+       /* k6 */
+       subL[7] = krl; subR[7] = krr;
+       ROLDQ(kll, klr, krl, krr, w0, w1, 30);
+       /* k11 */
+       subL[14] = kll; subR[14] = klr;
+       /* k12 */
+       subL[15] = krl; subR[15] = krr;
+       /* rotation left shift 32bit */
+       /* kl5 */
+       subL[24] = klr; subR[24] = krl;
+       /* kl6 */
+       subL[25] = krr; subR[25] = kll;
+       /* rotation left shift 49 from k11,k12 -> k21,k22 */
+       ROLDQo32(kll, klr, krl, krr, w0, w1, 49);
+       /* k21 */
+       subL[28] = kll; subR[28] = klr;
+       /* k22 */
+       subL[29] = krl; subR[29] = krr;
+
+       /* generate KB dependent subkeys */
+       /* k1 */
+       subL[2] = krll; subR[2] = krlr;
+       /* k2 */
+       subL[3] = krrl; subR[3] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       /* k7 */
+       subL[10] = krll; subR[10] = krlr;
+       /* k8 */
+       subL[11] = krrl; subR[11] = krrr;
+       ROLDQ(krll, krlr, krrl, krrr, w0, w1, 30);
+       /* k15 */
+       subL[20] = krll; subR[20] = krlr;
+       /* k16 */
+       subL[21] = krrl; subR[21] = krrr;
+       ROLDQo32(krll, krlr, krrl, krrr, w0, w1, 51);
+       /* kw3 */
+       subL[32] = krll; subR[32] = krlr;
+       /* kw4 */
+       subL[33] = krrl; subR[33] = krrr;
+
+       camellia_setup_tail(subkey, subL, subR, 32);
+}
+
+static void camellia_setup192(const unsigned char *key, u32 *subkey)
+{
+       unsigned char kk[32];
+       u32 krll, krlr, krrl, krrr;
+
+       memcpy(kk, key, 24);
+       memcpy((unsigned char *)&krll, key+16, 4);
+       memcpy((unsigned char *)&krlr, key+20, 4);
+       krrl = ~krll;
+       krrr = ~krlr;
+       memcpy(kk+24, (unsigned char *)&krrl, 4);
+       memcpy(kk+28, (unsigned char *)&krrr, 4);
+       camellia_setup256(kk, subkey);
+}
+
+
+/*
+ * Encrypt/decrypt
+ */
+#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) ({ \
+       t0 = kll;                                                       \
+       t2 = krr;                                                       \
+       t0 &= ll;                                                       \
+       t2 |= rr;                                                       \
+       rl ^= t2;                                                       \
+       lr ^= rol32(t0, 1);                                             \
+       t3 = krl;                                                       \
+       t1 = klr;                                                       \
+       t3 &= rl;                                                       \
+       t1 |= lr;                                                       \
+       ll ^= t1;                                                       \
+       rr ^= rol32(t3, 1);                                             \
+})
+
+#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) ({            \
+       yl ^= kl;                                                       \
+       yr ^= kr;                                                       \
+       ir =  camellia_sp1110[(u8)xr];                                  \
+       il =  camellia_sp1110[(u8)(xl >> 24)];                          \
+       ir ^= camellia_sp0222[(u8)(xr >> 24)];                          \
+       il ^= camellia_sp0222[(u8)(xl >> 16)];                          \
+       ir ^= camellia_sp3033[(u8)(xr >> 16)];                          \
+       il ^= camellia_sp3033[(u8)(xl >> 8)];                           \
+       ir ^= camellia_sp4404[(u8)(xr >> 8)];                           \
+       il ^= camellia_sp4404[(u8)xl];                                  \
+       ir ^= il;                                                       \
+       yl ^= ir;                                                       \
+       yr ^= ror32(il, 8) ^ ir;                                        \
+})
+
+/* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
+static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max)
+{
+       u32 il, ir, t0, t1;            /* temporary variables */
+
+       /* pre whitening but absorb kw2 */
+       io[0] ^= SUBKEY_L(0);
+       io[1] ^= SUBKEY_R(0);
+
+       /* main iteration */
+#define ROUNDS(i) ({ \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 2), SUBKEY_R(i + 2), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 3), SUBKEY_R(i + 3), \
+                        io[0], io[1], il, ir); \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 4), SUBKEY_R(i + 4), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 5), SUBKEY_R(i + 5), \
+                        io[0], io[1], il, ir); \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 6), SUBKEY_R(i + 6), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 7), SUBKEY_R(i + 7), \
+                        io[0], io[1], il, ir); \
+})
+#define FLS(i) ({ \
+       CAMELLIA_FLS(io[0], io[1], io[2], io[3], \
+                    SUBKEY_L(i + 0), SUBKEY_R(i + 0), \
+                    SUBKEY_L(i + 1), SUBKEY_R(i + 1), \
+                    t0, t1, il, ir); \
+})
+
+       ROUNDS(0);
+       FLS(8);
+       ROUNDS(8);
+       FLS(16);
+       ROUNDS(16);
+       if (max == 32) {
+               FLS(24);
+               ROUNDS(24);
+       }
+
+#undef ROUNDS
+#undef FLS
+
+       /* post whitening but kw4 */
+       io[2] ^= SUBKEY_L(max);
+       io[3] ^= SUBKEY_R(max);
+       /* NB: io[0],[1] should be swapped with [2],[3] by caller! */
+}
+
+static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i)
+{
+       u32 il, ir, t0, t1;            /* temporary variables */
+
+       /* pre whitening but absorb kw2 */
+       io[0] ^= SUBKEY_L(i);
+       io[1] ^= SUBKEY_R(i);
+
+       /* main iteration */
+#define ROUNDS(i) ({ \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 7), SUBKEY_R(i + 7), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 6), SUBKEY_R(i + 6), \
+                        io[0], io[1], il, ir); \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 5), SUBKEY_R(i + 5), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 4), SUBKEY_R(i + 4), \
+                        io[0], io[1], il, ir); \
+       CAMELLIA_ROUNDSM(io[0], io[1], \
+                        SUBKEY_L(i + 3), SUBKEY_R(i + 3), \
+                        io[2], io[3], il, ir); \
+       CAMELLIA_ROUNDSM(io[2], io[3], \
+                        SUBKEY_L(i + 2), SUBKEY_R(i + 2), \
+                        io[0], io[1], il, ir); \
+})
+#define FLS(i) ({ \
+       CAMELLIA_FLS(io[0], io[1], io[2], io[3], \
+                    SUBKEY_L(i + 1), SUBKEY_R(i + 1), \
+                    SUBKEY_L(i + 0), SUBKEY_R(i + 0), \
+                    t0, t1, il, ir); \
+})
+
+       if (i == 32) {
+               ROUNDS(24);
+               FLS(24);
+       }
+       ROUNDS(16);
+       FLS(16);
+       ROUNDS(8);
+       FLS(8);
+       ROUNDS(0);
+
+#undef ROUNDS
+#undef FLS
+
+       /* post whitening but kw4 */
+       io[2] ^= SUBKEY_L(0);
+       io[3] ^= SUBKEY_R(0);
+       /* NB: 0,1 should be swapped with 2,3 by caller! */
+}
+
+
+struct camellia_ctx {
+       int key_length;
+       u32 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u32)];
+};
+
+static int
+camellia_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+                unsigned int key_len)
+{
+       struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+       const unsigned char *key = (const unsigned char *)in_key;
+       u32 *flags = &tfm->crt_flags;
+
+       if (key_len != 16 && key_len != 24 && key_len != 32) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       cctx->key_length = key_len;
+
+       switch (key_len) {
+       case 16:
+               camellia_setup128(key, cctx->key_table);
+               break;
+       case 24:
+               camellia_setup192(key, cctx->key_table);
+               break;
+       case 32:
+               camellia_setup256(key, cctx->key_table);
+               break;
+       }
+
+       return 0;
+}
+
+static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+       const __be32 *src = (const __be32 *)in;
+       __be32 *dst = (__be32 *)out;
+       unsigned int max;
+
+       u32 tmp[4];
+
+       tmp[0] = be32_to_cpu(src[0]);
+       tmp[1] = be32_to_cpu(src[1]);
+       tmp[2] = be32_to_cpu(src[2]);
+       tmp[3] = be32_to_cpu(src[3]);
+
+       if (cctx->key_length == 16)
+               max = 24;
+       else
+               max = 32; /* for key lengths of 24 and 32 */
+
+       camellia_do_encrypt(cctx->key_table, tmp, max);
+
+       /* do_encrypt returns 0,1 swapped with 2,3 */
+       dst[0] = cpu_to_be32(tmp[2]);
+       dst[1] = cpu_to_be32(tmp[3]);
+       dst[2] = cpu_to_be32(tmp[0]);
+       dst[3] = cpu_to_be32(tmp[1]);
+}
+
+static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm);
+       const __be32 *src = (const __be32 *)in;
+       __be32 *dst = (__be32 *)out;
+       unsigned int max;
+
+       u32 tmp[4];
+
+       tmp[0] = be32_to_cpu(src[0]);
+       tmp[1] = be32_to_cpu(src[1]);
+       tmp[2] = be32_to_cpu(src[2]);
+       tmp[3] = be32_to_cpu(src[3]);
+
+       if (cctx->key_length == 16)
+               max = 24;
+       else
+               max = 32; /* for key lengths of 24 and 32 */
+
+       camellia_do_decrypt(cctx->key_table, tmp, max);
+
+       /* do_decrypt returns 0,1 swapped with 2,3 */
+       dst[0] = cpu_to_be32(tmp[2]);
+       dst[1] = cpu_to_be32(tmp[3]);
+       dst[2] = cpu_to_be32(tmp[0]);
+       dst[3] = cpu_to_be32(tmp[1]);
+}
+
+static struct crypto_alg camellia_alg = {
+       .cra_name               =       "camellia",
+       .cra_driver_name        =       "camellia-generic",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct camellia_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(camellia_alg.cra_list),
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       CAMELLIA_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       CAMELLIA_MAX_KEY_SIZE,
+                       .cia_setkey             =       camellia_set_key,
+                       .cia_encrypt            =       camellia_encrypt,
+                       .cia_decrypt            =       camellia_decrypt
+               }
+       }
+};
+
+static int __init camellia_init(void)
+{
+       return crypto_register_alg(&camellia_alg);
+}
+
+static void __exit camellia_fini(void)
+{
+       crypto_unregister_alg(&camellia_alg);
+}
+
+module_init(camellia_init);
+module_exit(camellia_fini);
+
+MODULE_DESCRIPTION("Camellia Cipher Algorithm");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("camellia");
index b6ac138..f76e42b 100644 (file)
@@ -304,7 +304,7 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
                          struct nlattr **attrs)
 {
-       int exact;
+       int exact = 0;
        const char *name;
        struct crypto_alg *alg;
        struct crypto_user_alg *p = nlmsg_data(nlh);
index 7736a9f..8f147bf 100644 (file)
@@ -1297,6 +1297,18 @@ static int do_test(int m)
                                speed_template_16_24_32);
                test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0,
                                speed_template_16_24_32);
+               test_cipher_speed("ctr(camellia)", ENCRYPT, sec, NULL, 0,
+                               speed_template_16_24_32);
+               test_cipher_speed("ctr(camellia)", DECRYPT, sec, NULL, 0,
+                               speed_template_16_24_32);
+               test_cipher_speed("lrw(camellia)", ENCRYPT, sec, NULL, 0,
+                               speed_template_32_40_48);
+               test_cipher_speed("lrw(camellia)", DECRYPT, sec, NULL, 0,
+                               speed_template_32_40_48);
+               test_cipher_speed("xts(camellia)", ENCRYPT, sec, NULL, 0,
+                               speed_template_32_48_64);
+               test_cipher_speed("xts(camellia)", DECRYPT, sec, NULL, 0,
+                               speed_template_32_48_64);
                break;
 
        case 206:
index bb54b88..5674878 100644 (file)
@@ -1845,6 +1845,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "ctr(camellia)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = camellia_ctr_enc_tv_template,
+                                       .count = CAMELLIA_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = camellia_ctr_dec_tv_template,
+                                       .count = CAMELLIA_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "ctr(serpent)",
                .test = alg_test_skcipher,
@@ -2296,6 +2311,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "lrw(camellia)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = camellia_lrw_enc_tv_template,
+                                       .count = CAMELLIA_LRW_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = camellia_lrw_dec_tv_template,
+                                       .count = CAMELLIA_LRW_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "lrw(serpent)",
                .test = alg_test_skcipher,
@@ -2633,6 +2663,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "xts(camellia)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = camellia_xts_enc_tv_template,
+                                       .count = CAMELLIA_XTS_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = camellia_xts_dec_tv_template,
+                                       .count = CAMELLIA_XTS_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "xts(serpent)",
                .test = alg_test_skcipher,
index 43e84d3..36e5a8e 100644 (file)
@@ -11332,10 +11332,16 @@ static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = {
 /*
  * CAMELLIA test vectors.
  */
-#define CAMELLIA_ENC_TEST_VECTORS 3
-#define CAMELLIA_DEC_TEST_VECTORS 3
-#define CAMELLIA_CBC_ENC_TEST_VECTORS 2
-#define CAMELLIA_CBC_DEC_TEST_VECTORS 2
+#define CAMELLIA_ENC_TEST_VECTORS 4
+#define CAMELLIA_DEC_TEST_VECTORS 4
+#define CAMELLIA_CBC_ENC_TEST_VECTORS 3
+#define CAMELLIA_CBC_DEC_TEST_VECTORS 3
+#define CAMELLIA_CTR_ENC_TEST_VECTORS 2
+#define CAMELLIA_CTR_DEC_TEST_VECTORS 2
+#define CAMELLIA_LRW_ENC_TEST_VECTORS 8
+#define CAMELLIA_LRW_DEC_TEST_VECTORS 8
+#define CAMELLIA_XTS_ENC_TEST_VECTORS 5
+#define CAMELLIA_XTS_DEC_TEST_VECTORS 5
 
 static struct cipher_testvec camellia_enc_tv_template[] = {
        {
@@ -11372,6 +11378,27 @@ static struct cipher_testvec camellia_enc_tv_template[] = {
                          "\x20\xef\x7c\x91\x9e\x3a\x75\x09",
                .rlen   = 16,
        },
+       { /* Generated with Crypto++ */
+               .key    = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C"
+                         "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D"
+                         "\x4A\x27\x04\xE1\x27\x04\xE1\xBE"
+                         "\x9B\x78\xBE\x9B\x78\x55\x32\x0F",
+               .klen   = 32,
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .ilen   = 48,
+               .result = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA"
+                         "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7"
+                         "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04"
+                         "\xB3\xC2\xB9\x03\xAA\x91\x56\x29"
+                         "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9"
+                         "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A",
+               .rlen   = 48,
+       },
 };
 
 static struct cipher_testvec camellia_dec_tv_template[] = {
@@ -11409,6 +11436,27 @@ static struct cipher_testvec camellia_dec_tv_template[] = {
                          "\xfe\xdc\xba\x98\x76\x54\x32\x10",
                .rlen   = 16,
        },
+       { /* Generated with Crypto++ */
+               .key    = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C"
+                         "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D"
+                         "\x4A\x27\x04\xE1\x27\x04\xE1\xBE"
+                         "\x9B\x78\xBE\x9B\x78\x55\x32\x0F",
+               .klen   = 32,
+               .input  = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA"
+                         "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7"
+                         "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04"
+                         "\xB3\xC2\xB9\x03\xAA\x91\x56\x29"
+                         "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9"
+                         "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A",
+               .ilen   = 48,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .rlen   = 48,
+       },
 };
 
 static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
@@ -11440,6 +11488,29 @@ static struct cipher_testvec camellia_cbc_enc_tv_template[] = {
                          "\x15\x78\xe0\x5e\xf2\xcb\x87\x16",
                .rlen   = 32,
        },
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .ilen   = 48,
+               .result = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77"
+                         "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40"
+                         "\x88\x39\xE3\xFD\x94\x4B\x25\x58"
+                         "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B"
+                         "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27"
+                         "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01",
+               .rlen   = 48,
+       },
 };
 
 static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
@@ -11471,6 +11542,1310 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = {
                          "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
                .rlen   = 32,
        },
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77"
+                         "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40"
+                         "\x88\x39\xE3\xFD\x94\x4B\x25\x58"
+                         "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B"
+                         "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27"
+                         "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01",
+               .ilen   = 48,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .rlen   = 48,
+       },
+};
+
+static struct cipher_testvec camellia_ctr_enc_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .ilen   = 48,
+               .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11"
+                         "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE"
+                         "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4"
+                         "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6"
+                         "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85"
+                         "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C",
+               .rlen   = 48,
+       },
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D",
+               .ilen   = 51,
+               .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11"
+                         "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE"
+                         "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4"
+                         "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6"
+                         "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85"
+                         "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C"
+                         "\x1E\x43\xEF",
+               .rlen   = 51,
+       },
+};
+
+static struct cipher_testvec camellia_ctr_dec_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11"
+                         "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE"
+                         "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4"
+                         "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6"
+                         "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85"
+                         "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C",
+               .ilen   = 48,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48",
+               .rlen   = 48,
+       },
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11"
+                         "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE"
+                         "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4"
+                         "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6"
+                         "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85"
+                         "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C"
+                         "\x1E\x43\xEF",
+               .ilen   = 51,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D",
+               .rlen   = 51,
+       },
+
+};
+
+static struct cipher_testvec camellia_lrw_enc_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
+       {
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31"
+                         "\x97\xcc\x72\xbe\x99\x17\xeb\x3e",
+               .rlen   = 16,
+       }, {
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x73\x09\xb7\x50\xb6\x77\x30\x50"
+                         "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a",
+               .rlen   = 16,
+       }, {
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x90\xae\x83\xe0\x22\xb9\x60\x91"
+                         "\xfa\xa9\xb7\x98\xe3\xed\x87\x01",
+               .rlen   = 16,
+       }, {
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0"
+                         "\xd8\x83\xef\xd9\x07\x16\x5f\x35",
+               .rlen   = 16,
+       }, {
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e"
+                         "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9"
+                         "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d",
+               .rlen   = 16,
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x04\xab\x28\x37\x31\x7a\x26\xab"
+                         "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .ilen   = 512,
+               .result = "\x90\x69\x8e\xf2\x14\x86\x59\xf9"
+                         "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96"
+                         "\x67\x76\xac\x2c\xd2\x63\x18\x93"
+                         "\x13\xf8\xf1\xf6\x71\x77\xb3\xee"
+                         "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f"
+                         "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06"
+                         "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1"
+                         "\x62\xdd\x78\x81\xea\x1d\xef\x04"
+                         "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1"
+                         "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2"
+                         "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0"
+                         "\x40\x41\x69\xaa\x71\xc0\x37\xec"
+                         "\x39\xf3\xf2\xec\x82\xc3\x88\x79"
+                         "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80"
+                         "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c"
+                         "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1"
+                         "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12"
+                         "\x6f\x75\xc7\x80\x99\x50\x84\xcf"
+                         "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e"
+                         "\xb9\xb3\xde\x7a\x93\x14\x12\xa2"
+                         "\xf7\x43\xb3\x9d\x1a\x87\x65\x91"
+                         "\x42\x08\x40\x82\x06\x1c\x2d\x55"
+                         "\x6e\x48\xd5\x74\x07\x6e\x9d\x80"
+                         "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74"
+                         "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c"
+                         "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9"
+                         "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83"
+                         "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b"
+                         "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0"
+                         "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1"
+                         "\xed\x14\xa9\x57\x19\x63\x40\x04"
+                         "\x24\xeb\x6e\x19\xd1\x3d\x70\x78"
+                         "\xeb\xda\x55\x70\x2c\x4f\x41\x5b"
+                         "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3"
+                         "\x21\xec\xd7\xd2\x55\x32\x7c\x2e"
+                         "\x3c\x48\x8e\xb4\x85\x35\x47\xfe"
+                         "\xe2\x88\x79\x98\x6a\xc9\x8d\xff"
+                         "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd"
+                         "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99"
+                         "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75"
+                         "\x23\x52\x76\xc3\x50\x6e\x66\xf8"
+                         "\xa2\xe2\xce\xba\x40\x21\x3f\xc9"
+                         "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf"
+                         "\xd3\xdf\x57\x59\x83\xb8\xe1\x85"
+                         "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f"
+                         "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a"
+                         "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76"
+                         "\x2f\x1c\x1a\x30\xed\x95\x2a\x44"
+                         "\x35\xa5\x83\x04\x84\x01\x99\x56"
+                         "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd"
+                         "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c"
+                         "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d"
+                         "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77"
+                         "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b"
+                         "\x30\xed\x1a\x50\x19\xef\xc4\x2c"
+                         "\x02\xd9\xc5\xd3\x11\x33\x37\xe5"
+                         "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d"
+                         "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96"
+                         "\x91\xc3\x94\x24\xa5\x12\xa2\x37"
+                         "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe"
+                         "\x79\x92\x3e\xe6\x1b\x49\x57\x5d"
+                         "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1"
+                         "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9"
+                         "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec camellia_lrw_dec_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
+       /* same as enc vectors with input and result reversed */
+       {
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31"
+                         "\x97\xcc\x72\xbe\x99\x17\xeb\x3e",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\x73\x09\xb7\x50\xb6\x77\x30\x50"
+                         "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x90\xae\x83\xe0\x22\xb9\x60\x91"
+                         "\xfa\xa9\xb7\x98\xe3\xed\x87\x01",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0"
+                         "\xd8\x83\xef\xd9\x07\x16\x5f\x35",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e"
+                         "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9"
+                         "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x04\xab\x28\x37\x31\x7a\x26\xab"
+                         "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x90\x69\x8e\xf2\x14\x86\x59\xf9"
+                         "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96"
+                         "\x67\x76\xac\x2c\xd2\x63\x18\x93"
+                         "\x13\xf8\xf1\xf6\x71\x77\xb3\xee"
+                         "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f"
+                         "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06"
+                         "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1"
+                         "\x62\xdd\x78\x81\xea\x1d\xef\x04"
+                         "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1"
+                         "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2"
+                         "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0"
+                         "\x40\x41\x69\xaa\x71\xc0\x37\xec"
+                         "\x39\xf3\xf2\xec\x82\xc3\x88\x79"
+                         "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80"
+                         "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c"
+                         "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1"
+                         "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12"
+                         "\x6f\x75\xc7\x80\x99\x50\x84\xcf"
+                         "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e"
+                         "\xb9\xb3\xde\x7a\x93\x14\x12\xa2"
+                         "\xf7\x43\xb3\x9d\x1a\x87\x65\x91"
+                         "\x42\x08\x40\x82\x06\x1c\x2d\x55"
+                         "\x6e\x48\xd5\x74\x07\x6e\x9d\x80"
+                         "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74"
+                         "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c"
+                         "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9"
+                         "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83"
+                         "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b"
+                         "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0"
+                         "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1"
+                         "\xed\x14\xa9\x57\x19\x63\x40\x04"
+                         "\x24\xeb\x6e\x19\xd1\x3d\x70\x78"
+                         "\xeb\xda\x55\x70\x2c\x4f\x41\x5b"
+                         "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3"
+                         "\x21\xec\xd7\xd2\x55\x32\x7c\x2e"
+                         "\x3c\x48\x8e\xb4\x85\x35\x47\xfe"
+                         "\xe2\x88\x79\x98\x6a\xc9\x8d\xff"
+                         "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd"
+                         "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99"
+                         "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75"
+                         "\x23\x52\x76\xc3\x50\x6e\x66\xf8"
+                         "\xa2\xe2\xce\xba\x40\x21\x3f\xc9"
+                         "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf"
+                         "\xd3\xdf\x57\x59\x83\xb8\xe1\x85"
+                         "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f"
+                         "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a"
+                         "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76"
+                         "\x2f\x1c\x1a\x30\xed\x95\x2a\x44"
+                         "\x35\xa5\x83\x04\x84\x01\x99\x56"
+                         "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd"
+                         "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c"
+                         "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d"
+                         "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77"
+                         "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b"
+                         "\x30\xed\x1a\x50\x19\xef\xc4\x2c"
+                         "\x02\xd9\xc5\xd3\x11\x33\x37\xe5"
+                         "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d"
+                         "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96"
+                         "\x91\xc3\x94\x24\xa5\x12\xa2\x37"
+                         "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe"
+                         "\x79\x92\x3e\xe6\x1b\x49\x57\x5d"
+                         "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1"
+                         "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9"
+                         "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95",
+               .ilen   = 512,
+               .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec camellia_xts_enc_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 32,
+               .result = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41"
+                         "\xdc\xca\xfa\x09\xba\x74\xb9\x05"
+                         "\x78\xba\xa4\xf8\x67\x4d\x7e\xad"
+                         "\x20\x18\xf5\x0c\x41\x16\x2a\x61",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86"
+                         "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f"
+                         "\xb5\x37\x06\xff\xbd\xd4\x91\x70"
+                         "\x80\x1f\xb2\x39\x10\x89\x44\xf5",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e"
+                         "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7"
+                         "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a"
+                         "\x35\x3c\x6b\xb5\x61\x1c\x79\x38",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33"
+                         "\x60\xc3\xe9\x47\x90\xb7\x50\x57"
+                         "\xa3\xad\x81\x2f\xf5\x22\x96\x02"
+                         "\xaa\x7f\xea\xac\x29\x78\xca\x2a"
+                         "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73"
+                         "\x09\x66\xad\x72\x0e\x4d\x5d\x77"
+                         "\xbc\xb8\x76\x80\x37\x59\xa9\x01"
+                         "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d"
+                         "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01"
+                         "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8"
+                         "\x08\xda\x76\x00\x65\xcf\x7b\x31"
+                         "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e"
+                         "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5"
+                         "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04"
+                         "\xfb\x54\xdd\x29\x27\xc2\x65\x17"
+                         "\x36\x88\xb0\x85\x8d\x73\x7e\x4b"
+                         "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4"
+                         "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f"
+                         "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3"
+                         "\x6c\xee\xac\xdc\x45\x58\xca\x5b"
+                         "\x70\x0e\x6a\x12\x86\x82\x79\x9f"
+                         "\x16\xd4\x9d\x67\xcd\x70\x65\x26"
+                         "\x21\x72\x1e\xa1\x94\x8a\x83\x0c"
+                         "\x92\x42\x58\x5e\xa2\xc5\x31\xf3"
+                         "\x7b\xd1\x31\xd4\x15\x80\x31\x61"
+                         "\x5c\x53\x10\xdd\xea\xc8\x83\x5c"
+                         "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05"
+                         "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5"
+                         "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9"
+                         "\x16\x31\xb2\x47\x91\x67\xaa\x28"
+                         "\x2c\x29\x85\xa3\xf7\xf2\x24\x93"
+                         "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc"
+                         "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec"
+                         "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e"
+                         "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66"
+                         "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7"
+                         "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d"
+                         "\xf8\x89\xcd\x20\x27\x84\x5d\x5c"
+                         "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3"
+                         "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7"
+                         "\x3f\x43\xcc\x86\x71\x34\x6a\xd9"
+                         "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe"
+                         "\x18\x41\xdc\x9e\x2e\x75\x20\x3e"
+                         "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c"
+                         "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71"
+                         "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e"
+                         "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9"
+                         "\x34\xb8\x27\x74\x08\xda\xf2\x4a"
+                         "\x23\x5b\x9f\x55\x3a\x57\x82\x52"
+                         "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc"
+                         "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49"
+                         "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2"
+                         "\x96\x0b\x35\x84\x05\x0d\xd6\x2a"
+                         "\xea\x5a\xbf\x69\xde\xee\x4f\x8f"
+                         "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8"
+                         "\x96\xef\x0f\x0e\xec\xc7\xa6\x74"
+                         "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15"
+                         "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1"
+                         "\x5b\xb6\x71\xda\xb0\x0c\xba\x26"
+                         "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d"
+                         "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33"
+                         "\xcc\x06\xdb\xe7\x82\x29\x63\xd1"
+                         "\x52\x84\x4f\xee\x27\xe8\x02\xd4"
+                         "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28"
+                         "\x9a\x7f\x6e\x57\x55\xb8\x07\x88"
+                         "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b"
+                         "\xf1\x74\xac\x96\x05\x7b\x32\xca"
+                         "\xd1\x4e\xf1\x58\x29\x16\x24\x6c"
+                         "\xf2\xb3\xe4\x88\x84\xac\x4d\xee"
+                         "\x97\x07\x82\xf0\x07\x12\x38\x0a"
+                         "\x67\x62\xaf\xfd\x85\x9f\x0a\x55"
+                         "\xa5\x20\xc5\x60\xe4\x68\x53\xa4"
+                         "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c"
+                         "\x1c\x01\x4f\x55\xa9\x13\xeb\x25"
+                         "\x21\x87\xbc\xd3\xe7\x67\x4f\x38"
+                         "\xa8\x14\x25\x71\xe9\x2e\x4c\x21"
+                         "\x41\x82\x0c\x45\x39\x35\xa8\x75"
+                         "\x03\x29\x01\x84\x8c\xab\x48\xbe"
+                         "\x11\x56\x22\x67\xb7\x67\x1a\x09"
+                         "\xa1\x72\x25\x41\x3c\x39\x65\x80"
+                         "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d"
+                         "\xdd\x16\x8b\x63\x70\x4e\xc5\x17"
+                         "\x21\xe0\x84\x51\x4b\x6f\x05\x52"
+                         "\xe3\x63\x34\xfa\xa4\xaf\x33\x20"
+                         "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76"
+                         "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b"
+                         "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0"
+                         "\xb8\x8a\x13\x88\x71\xf4\x11\xa5"
+                         "\xe9\xa9\x10\x33\xe0\xbe\x49\x89"
+                         "\x41\x22\xf5\x9d\x80\x3e\x3b\x76"
+                         "\x01\x16\x50\x6e\x7c\x6a\x81\xe9"
+                         "\x13\x2c\xde\xb2\x5f\x79\xba\xb2"
+                         "\xb1\x75\xae\xd2\x07\x98\x4b\x69"
+                         "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98"
+                         "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a"
+                         "\x0d\x23\xb1\x79\x25\x13\x4b\xe5"
+                         "\xaf\x93\x20\x5c\x7f\x06\x7a\x34"
+                         "\x0b\x78\xe3\x67\x26\xe0\xad\x95"
+                         "\xc5\x4e\x26\x22\xcf\x73\x77\x62"
+                         "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9"
+                         "\xef\x38\x52\x18\x0e\x29\x7e\xef"
+                         "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2"
+                         "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d"
+                         "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe"
+                         "\x96\xcd\x41\x10\x78\x4e\x0c\xc9"
+                         "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab"
+                         "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa"
+                         "\x9d\x70\xbe\x4c\xa8\x98\x89\x01"
+                         "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa"
+                         "\x89\xf5\x14\x79\x18\x8f\x3b\x0d"
+                         "\x21\x17\xf8\x59\x15\x24\x64\x22"
+                         "\x57\x48\x80\xd5\x3d\x92\x30\x07"
+                         "\xd9\xa1\x4a\x23\x16\x43\x48\x0e"
+                         "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa"
+                         "\x49\xbc\x7e\x68\x6e\xa8\x46\x95"
+                         "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d"
+                         "\x6b\x84\xf3\x00\xba\x52\x05\x02"
+                         "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3"
+                         "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d"
+                         "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0"
+                         "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66"
+                         "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89"
+                         "\xf5\x21\x0f\x02\x48\x83\x74\xbf"
+                         "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b"
+                         "\xb1\x02\x0a\x5c\x79\x19\x3b\x75"
+                         "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e"
+                         "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec camellia_xts_dec_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+       /* same as enc vectors with input and result reversed */
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41"
+                         "\xdc\xca\xfa\x09\xba\x74\xb9\x05"
+                         "\x78\xba\xa4\xf8\x67\x4d\x7e\xad"
+                         "\x20\x18\xf5\x0c\x41\x16\x2a\x61",
+               .ilen   = 32,
+               .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86"
+                         "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f"
+                         "\xb5\x37\x06\xff\xbd\xd4\x91\x70"
+                         "\x80\x1f\xb2\x39\x10\x89\x44\xf5",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e"
+                         "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7"
+                         "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a"
+                         "\x35\x3c\x6b\xb5\x61\x1c\x79\x38",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33"
+                         "\x60\xc3\xe9\x47\x90\xb7\x50\x57"
+                         "\xa3\xad\x81\x2f\xf5\x22\x96\x02"
+                         "\xaa\x7f\xea\xac\x29\x78\xca\x2a"
+                         "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73"
+                         "\x09\x66\xad\x72\x0e\x4d\x5d\x77"
+                         "\xbc\xb8\x76\x80\x37\x59\xa9\x01"
+                         "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d"
+                         "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01"
+                         "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8"
+                         "\x08\xda\x76\x00\x65\xcf\x7b\x31"
+                         "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e"
+                         "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5"
+                         "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04"
+                         "\xfb\x54\xdd\x29\x27\xc2\x65\x17"
+                         "\x36\x88\xb0\x85\x8d\x73\x7e\x4b"
+                         "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4"
+                         "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f"
+                         "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3"
+                         "\x6c\xee\xac\xdc\x45\x58\xca\x5b"
+                         "\x70\x0e\x6a\x12\x86\x82\x79\x9f"
+                         "\x16\xd4\x9d\x67\xcd\x70\x65\x26"
+                         "\x21\x72\x1e\xa1\x94\x8a\x83\x0c"
+                         "\x92\x42\x58\x5e\xa2\xc5\x31\xf3"
+                         "\x7b\xd1\x31\xd4\x15\x80\x31\x61"
+                         "\x5c\x53\x10\xdd\xea\xc8\x83\x5c"
+                         "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05"
+                         "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5"
+                         "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9"
+                         "\x16\x31\xb2\x47\x91\x67\xaa\x28"
+                         "\x2c\x29\x85\xa3\xf7\xf2\x24\x93"
+                         "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc"
+                         "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec"
+                         "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e"
+                         "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66"
+                         "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7"
+                         "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d"
+                         "\xf8\x89\xcd\x20\x27\x84\x5d\x5c"
+                         "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3"
+                         "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7"
+                         "\x3f\x43\xcc\x86\x71\x34\x6a\xd9"
+                         "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe"
+                         "\x18\x41\xdc\x9e\x2e\x75\x20\x3e"
+                         "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c"
+                         "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71"
+                         "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e"
+                         "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9"
+                         "\x34\xb8\x27\x74\x08\xda\xf2\x4a"
+                         "\x23\x5b\x9f\x55\x3a\x57\x82\x52"
+                         "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc"
+                         "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49"
+                         "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2"
+                         "\x96\x0b\x35\x84\x05\x0d\xd6\x2a"
+                         "\xea\x5a\xbf\x69\xde\xee\x4f\x8f"
+                         "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8"
+                         "\x96\xef\x0f\x0e\xec\xc7\xa6\x74"
+                         "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15"
+                         "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1"
+                         "\x5b\xb6\x71\xda\xb0\x0c\xba\x26"
+                         "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d"
+                         "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33"
+                         "\xcc\x06\xdb\xe7\x82\x29\x63\xd1"
+                         "\x52\x84\x4f\xee\x27\xe8\x02\xd4"
+                         "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28"
+                         "\x9a\x7f\x6e\x57\x55\xb8\x07\x88"
+                         "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b"
+                         "\xf1\x74\xac\x96\x05\x7b\x32\xca"
+                         "\xd1\x4e\xf1\x58\x29\x16\x24\x6c"
+                         "\xf2\xb3\xe4\x88\x84\xac\x4d\xee"
+                         "\x97\x07\x82\xf0\x07\x12\x38\x0a"
+                         "\x67\x62\xaf\xfd\x85\x9f\x0a\x55"
+                         "\xa5\x20\xc5\x60\xe4\x68\x53\xa4"
+                         "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c"
+                         "\x1c\x01\x4f\x55\xa9\x13\xeb\x25"
+                         "\x21\x87\xbc\xd3\xe7\x67\x4f\x38"
+                         "\xa8\x14\x25\x71\xe9\x2e\x4c\x21"
+                         "\x41\x82\x0c\x45\x39\x35\xa8\x75"
+                         "\x03\x29\x01\x84\x8c\xab\x48\xbe"
+                         "\x11\x56\x22\x67\xb7\x67\x1a\x09"
+                         "\xa1\x72\x25\x41\x3c\x39\x65\x80"
+                         "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d"
+                         "\xdd\x16\x8b\x63\x70\x4e\xc5\x17"
+                         "\x21\xe0\x84\x51\x4b\x6f\x05\x52"
+                         "\xe3\x63\x34\xfa\xa4\xaf\x33\x20"
+                         "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76"
+                         "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b"
+                         "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0"
+                         "\xb8\x8a\x13\x88\x71\xf4\x11\xa5"
+                         "\xe9\xa9\x10\x33\xe0\xbe\x49\x89"
+                         "\x41\x22\xf5\x9d\x80\x3e\x3b\x76"
+                         "\x01\x16\x50\x6e\x7c\x6a\x81\xe9"
+                         "\x13\x2c\xde\xb2\x5f\x79\xba\xb2"
+                         "\xb1\x75\xae\xd2\x07\x98\x4b\x69"
+                         "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98"
+                         "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a"
+                         "\x0d\x23\xb1\x79\x25\x13\x4b\xe5"
+                         "\xaf\x93\x20\x5c\x7f\x06\x7a\x34"
+                         "\x0b\x78\xe3\x67\x26\xe0\xad\x95"
+                         "\xc5\x4e\x26\x22\xcf\x73\x77\x62"
+                         "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9"
+                         "\xef\x38\x52\x18\x0e\x29\x7e\xef"
+                         "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2"
+                         "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d"
+                         "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe"
+                         "\x96\xcd\x41\x10\x78\x4e\x0c\xc9"
+                         "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab"
+                         "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa"
+                         "\x9d\x70\xbe\x4c\xa8\x98\x89\x01"
+                         "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa"
+                         "\x89\xf5\x14\x79\x18\x8f\x3b\x0d"
+                         "\x21\x17\xf8\x59\x15\x24\x64\x22"
+                         "\x57\x48\x80\xd5\x3d\x92\x30\x07"
+                         "\xd9\xa1\x4a\x23\x16\x43\x48\x0e"
+                         "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa"
+                         "\x49\xbc\x7e\x68\x6e\xa8\x46\x95"
+                         "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d"
+                         "\x6b\x84\xf3\x00\xba\x52\x05\x02"
+                         "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3"
+                         "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d"
+                         "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0"
+                         "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66"
+                         "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89"
+                         "\xf5\x21\x0f\x02\x48\x83\x74\xbf"
+                         "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b"
+                         "\xb1\x02\x0a\x5c\x79\x19\x3b\x75"
+                         "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e"
+                         "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       },
 };
 
 /*
index 60e4f77..3ec3896 100644 (file)
@@ -123,36 +123,6 @@ void driver_remove_file(struct device_driver *drv,
 }
 EXPORT_SYMBOL_GPL(driver_remove_file);
 
-/**
- * driver_add_kobj - add a kobject below the specified driver
- * @drv: requesting device driver
- * @kobj: kobject to add below this driver
- * @fmt: format string that names the kobject
- *
- * You really don't want to do this, this is only here due to one looney
- * iseries driver, go poke those developers if you are annoyed about
- * this...
- */
-int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
-                   const char *fmt, ...)
-{
-       va_list args;
-       char *name;
-       int ret;
-
-       va_start(args, fmt);
-       name = kvasprintf(GFP_KERNEL, fmt, args);
-       va_end(args);
-
-       if (!name)
-               return -ENOMEM;
-
-       ret = kobject_add(kobj, &drv->p->kobj, "%s", name);
-       kfree(name);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(driver_add_kobj);
-
 static int driver_add_groups(struct device_driver *drv,
                             const struct attribute_group **groups)
 {
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
deleted file mode 100644 (file)
index 9a5b2a2..0000000
+++ /dev/null
@@ -1,809 +0,0 @@
-/* -*- linux-c -*-
- * viodasd.c
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM 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; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This routine provides access to disk space (termed "DASD" in historical
- * IBM terms) owned and managed by an OS/400 partition running on the
- * same box as this Linux partition.
- *
- * All disk operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) "viod: " fmt
-
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/mutex.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/scatterlist.h>
-
-#include <asm/uaccess.h>
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-MODULE_DESCRIPTION("iSeries Virtual DASD");
-MODULE_AUTHOR("Dave Boutcher");
-MODULE_LICENSE("GPL");
-
-/*
- * We only support 7 partitions per physical disk....so with minor
- * numbers 0-255 we get a maximum of 32 disks.
- */
-#define VIOD_GENHD_NAME                "iseries/vd"
-
-#define VIOD_VERS              "1.64"
-
-enum {
-       PARTITION_SHIFT = 3,
-       MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
-       MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name)
-};
-
-static DEFINE_MUTEX(viodasd_mutex);
-static DEFINE_SPINLOCK(viodasd_spinlock);
-
-#define VIOMAXREQ              16
-
-#define DEVICE_NO(cell)        ((struct viodasd_device *)(cell) - &viodasd_devices[0])
-
-struct viodasd_waitevent {
-       struct completion       com;
-       int                     rc;
-       u16                     sub_result;
-       int                     max_disk;       /* open */
-};
-
-static const struct vio_error_entry viodasd_err_table[] = {
-       { 0x0201, EINVAL, "Invalid Range" },
-       { 0x0202, EINVAL, "Invalid Token" },
-       { 0x0203, EIO, "DMA Error" },
-       { 0x0204, EIO, "Use Error" },
-       { 0x0205, EIO, "Release Error" },
-       { 0x0206, EINVAL, "Invalid Disk" },
-       { 0x0207, EBUSY, "Can't Lock" },
-       { 0x0208, EIO, "Already Locked" },
-       { 0x0209, EIO, "Already Unlocked" },
-       { 0x020A, EIO, "Invalid Arg" },
-       { 0x020B, EIO, "Bad IFS File" },
-       { 0x020C, EROFS, "Read Only Device" },
-       { 0x02FF, EIO, "Internal Error" },
-       { 0x0000, 0, NULL },
-};
-
-/*
- * Figure out the biggest I/O request (in sectors) we can accept
- */
-#define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
-
-/*
- * Number of disk I/O requests we've sent to OS/400
- */
-static int num_req_outstanding;
-
-/*
- * This is our internal structure for keeping track of disk devices
- */
-struct viodasd_device {
-       u16             cylinders;
-       u16             tracks;
-       u16             sectors;
-       u16             bytes_per_sector;
-       u64             size;
-       int             read_only;
-       spinlock_t      q_lock;
-       struct gendisk  *disk;
-       struct device   *dev;
-} viodasd_devices[MAX_DISKNO];
-
-/*
- * External open entry point.
- */
-static int viodasd_open(struct block_device *bdev, fmode_t mode)
-{
-       struct viodasd_device *d = bdev->bd_disk->private_data;
-       HvLpEvent_Rc hvrc;
-       struct viodasd_waitevent we;
-       u16 flags = 0;
-
-       if (d->read_only) {
-               if (mode & FMODE_WRITE)
-                       return -EROFS;
-               flags = vioblockflags_ro;
-       }
-
-       init_completion(&we.com);
-
-       /* Send the open event to OS/400 */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)&we, VIOVERSION << 16,
-                       ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("HV open failed %d\n", (int)hvrc);
-               return -EIO;
-       }
-
-       wait_for_completion(&we.com);
-
-       /* Check the return code */
-       if (we.rc != 0) {
-               const struct vio_error_entry *err =
-                       vio_lookup_rc(viodasd_err_table, we.sub_result);
-
-               pr_warning("bad rc opening disk: %d:0x%04x (%s)\n",
-                          (int)we.rc, we.sub_result, err->msg);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
-       int ret;
-
-       mutex_lock(&viodasd_mutex);
-       ret = viodasd_open(bdev, mode);
-       mutex_unlock(&viodasd_mutex);
-
-       return ret;
-}
-
-
-/*
- * External release entry point.
- */
-static int viodasd_release(struct gendisk *disk, fmode_t mode)
-{
-       struct viodasd_device *d = disk->private_data;
-       HvLpEvent_Rc hvrc;
-
-       mutex_lock(&viodasd_mutex);
-       /* Send the event to OS/400.  We DON'T expect a response */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockclose,
-                       HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       0, VIOVERSION << 16,
-                       ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
-                       0, 0, 0);
-       if (hvrc != 0)
-               pr_warning("HV close call failed %d\n", (int)hvrc);
-
-       mutex_unlock(&viodasd_mutex);
-
-       return 0;
-}
-
-
-/* External ioctl entry point.
- */
-static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-       struct gendisk *disk = bdev->bd_disk;
-       struct viodasd_device *d = disk->private_data;
-
-       geo->sectors = d->sectors ? d->sectors : 32;
-       geo->heads = d->tracks ? d->tracks  : 64;
-       geo->cylinders = d->cylinders ? d->cylinders :
-               get_capacity(disk) / (geo->sectors * geo->heads);
-
-       return 0;
-}
-
-/*
- * Our file operations table
- */
-static const struct block_device_operations viodasd_fops = {
-       .owner = THIS_MODULE,
-       .open = viodasd_unlocked_open,
-       .release = viodasd_release,
-       .getgeo = viodasd_getgeo,
-};
-
-/*
- * End a request
- */
-static void viodasd_end_request(struct request *req, int error,
-               int num_sectors)
-{
-       __blk_end_request(req, error, num_sectors << 9);
-}
-
-/*
- * Send an actual I/O request to OS/400
- */
-static int send_request(struct request *req)
-{
-       u64 start;
-       int direction;
-       int nsg;
-       u16 viocmd;
-       HvLpEvent_Rc hvrc;
-       struct vioblocklpevent *bevent;
-       struct HvLpEvent *hev;
-       struct scatterlist sg[VIOMAXBLOCKDMA];
-       int sgindex;
-       struct viodasd_device *d;
-       unsigned long flags;
-
-       start = (u64)blk_rq_pos(req) << 9;
-
-       if (rq_data_dir(req) == READ) {
-               direction = DMA_FROM_DEVICE;
-               viocmd = viomajorsubtype_blockio | vioblockread;
-       } else {
-               direction = DMA_TO_DEVICE;
-               viocmd = viomajorsubtype_blockio | vioblockwrite;
-       }
-
-        d = req->rq_disk->private_data;
-
-       /* Now build the scatter-gather list */
-       sg_init_table(sg, VIOMAXBLOCKDMA);
-       nsg = blk_rq_map_sg(req->q, req, sg);
-       nsg = dma_map_sg(d->dev, sg, nsg, direction);
-
-       spin_lock_irqsave(&viodasd_spinlock, flags);
-       num_req_outstanding++;
-
-       /* This optimization handles a single DMA block */
-       if (nsg == 1)
-               hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                               HvLpEvent_Type_VirtualIo, viocmd,
-                               HvLpEvent_AckInd_DoAck,
-                               HvLpEvent_AckType_ImmediateAck,
-                               viopath_sourceinst(viopath_hostLp),
-                               viopath_targetinst(viopath_hostLp),
-                               (u64)(unsigned long)req, VIOVERSION << 16,
-                               ((u64)DEVICE_NO(d) << 48), start,
-                               ((u64)sg_dma_address(&sg[0])) << 32,
-                               sg_dma_len(&sg[0]));
-       else {
-               bevent = (struct vioblocklpevent *)
-                       vio_get_event_buffer(viomajorsubtype_blockio);
-               if (bevent == NULL) {
-                       pr_warning("error allocating disk event buffer\n");
-                       goto error_ret;
-               }
-
-               /*
-                * Now build up the actual request.  Note that we store
-                * the pointer to the request in the correlation
-                * token so we can match the response up later
-                */
-               memset(bevent, 0, sizeof(struct vioblocklpevent));
-               hev = &bevent->event;
-               hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK |
-                       HV_LP_EVENT_INT;
-               hev->xType = HvLpEvent_Type_VirtualIo;
-               hev->xSubtype = viocmd;
-               hev->xSourceLp = HvLpConfig_getLpIndex();
-               hev->xTargetLp = viopath_hostLp;
-               hev->xSizeMinus1 =
-                       offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
-                       (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
-               hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
-               hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp);
-               hev->xCorrelationToken = (u64)req;
-               bevent->version = VIOVERSION;
-               bevent->disk = DEVICE_NO(d);
-               bevent->u.rw_data.offset = start;
-
-               /*
-                * Copy just the dma information from the sg list
-                * into the request
-                */
-               for (sgindex = 0; sgindex < nsg; sgindex++) {
-                       bevent->u.rw_data.dma_info[sgindex].token =
-                               sg_dma_address(&sg[sgindex]);
-                       bevent->u.rw_data.dma_info[sgindex].len =
-                               sg_dma_len(&sg[sgindex]);
-               }
-
-               /* Send the request */
-               hvrc = HvCallEvent_signalLpEvent(&bevent->event);
-               vio_free_event_buffer(viomajorsubtype_blockio, bevent);
-       }
-
-       if (hvrc != HvLpEvent_Rc_Good) {
-               pr_warning("error sending disk event to OS/400 (rc %d)\n",
-                          (int)hvrc);
-               goto error_ret;
-       }
-       spin_unlock_irqrestore(&viodasd_spinlock, flags);
-       return 0;
-
-error_ret:
-       num_req_outstanding--;
-       spin_unlock_irqrestore(&viodasd_spinlock, flags);
-       dma_unmap_sg(d->dev, sg, nsg, direction);
-       return -1;
-}
-
-/*
- * This is the external request processing routine
- */
-static void do_viodasd_request(struct request_queue *q)
-{
-       struct request *req;
-
-       /*
-        * If we already have the maximum number of requests
-        * outstanding to OS/400 just bail out. We'll come
-        * back later.
-        */
-       while (num_req_outstanding < VIOMAXREQ) {
-               req = blk_fetch_request(q);
-               if (req == NULL)
-                       return;
-               /* check that request contains a valid command */
-               if (req->cmd_type != REQ_TYPE_FS) {
-                       viodasd_end_request(req, -EIO, blk_rq_sectors(req));
-                       continue;
-               }
-               /* Try sending the request */
-               if (send_request(req) != 0)
-                       viodasd_end_request(req, -EIO, blk_rq_sectors(req));
-       }
-}
-
-/*
- * Probe a single disk and fill in the viodasd_device structure
- * for it.
- */
-static int probe_disk(struct viodasd_device *d)
-{
-       HvLpEvent_Rc hvrc;
-       struct viodasd_waitevent we;
-       int dev_no = DEVICE_NO(d);
-       struct gendisk *g;
-       struct request_queue *q;
-       u16 flags = 0;
-
-retry:
-       init_completion(&we.com);
-
-       /* Send the open event to OS/400 */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)&we, VIOVERSION << 16,
-                       ((u64)dev_no << 48) | ((u64)flags<< 32),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("bad rc on HV open %d\n", (int)hvrc);
-               return 0;
-       }
-
-       wait_for_completion(&we.com);
-
-       if (we.rc != 0) {
-               if (flags != 0)
-                       return 0;
-               /* try again with read only flag set */
-               flags = vioblockflags_ro;
-               goto retry;
-       }
-       if (we.max_disk > (MAX_DISKNO - 1)) {
-               printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"),
-                           MAX_DISKNO, we.max_disk + 1);
-       }
-
-       /* Send the close event to OS/400.  We DON'T expect a response */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_blockio | vioblockclose,
-                       HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       0, VIOVERSION << 16,
-                       ((u64)dev_no << 48) | ((u64)flags << 32),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc);
-               return 0;
-       }
-
-       if (d->dev == NULL) {
-               /* this is when we reprobe for new disks */
-               if (vio_create_viodasd(dev_no) == NULL) {
-                       pr_warning("cannot allocate virtual device for disk %d\n",
-                                  dev_no);
-                       return 0;
-               }
-               /*
-                * The vio_create_viodasd will have recursed into this
-                * routine with d->dev set to the new vio device and
-                * will finish the setup of the disk below.
-                */
-               return 1;
-       }
-
-       /* create the request queue for the disk */
-       spin_lock_init(&d->q_lock);
-       q = blk_init_queue(do_viodasd_request, &d->q_lock);
-       if (q == NULL) {
-               pr_warning("cannot allocate queue for disk %d\n", dev_no);
-               return 0;
-       }
-       g = alloc_disk(1 << PARTITION_SHIFT);
-       if (g == NULL) {
-               pr_warning("cannot allocate disk structure for disk %d\n",
-                          dev_no);
-               blk_cleanup_queue(q);
-               return 0;
-       }
-
-       d->disk = g;
-       blk_queue_max_segments(q, VIOMAXBLOCKDMA);
-       blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS);
-       g->major = VIODASD_MAJOR;
-       g->first_minor = dev_no << PARTITION_SHIFT;
-       if (dev_no >= 26)
-               snprintf(g->disk_name, sizeof(g->disk_name),
-                               VIOD_GENHD_NAME "%c%c",
-                               'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26));
-       else
-               snprintf(g->disk_name, sizeof(g->disk_name),
-                               VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
-       g->fops = &viodasd_fops;
-       g->queue = q;
-       g->private_data = d;
-       g->driverfs_dev = d->dev;
-       set_capacity(g, d->size >> 9);
-
-       pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n",
-               dev_no, (unsigned long)(d->size >> 9),
-               (unsigned long)(d->size >> 20),
-               (int)d->cylinders, (int)d->tracks,
-               (int)d->sectors, (int)d->bytes_per_sector,
-               d->read_only ? " (RO)" : "");
-
-       /* register us in the global list */
-       add_disk(g);
-       return 1;
-}
-
-/* returns the total number of scatterlist elements converted */
-static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
-               struct scatterlist *sg, int *total_len)
-{
-       int i, numsg;
-       const struct rw_data *rw_data = &bevent->u.rw_data;
-       static const int offset =
-               offsetof(struct vioblocklpevent, u.rw_data.dma_info);
-       static const int element_size = sizeof(rw_data->dma_info[0]);
-
-       numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size;
-       if (numsg > VIOMAXBLOCKDMA)
-               numsg = VIOMAXBLOCKDMA;
-
-       *total_len = 0;
-       sg_init_table(sg, VIOMAXBLOCKDMA);
-       for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
-               sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
-               sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
-               *total_len += rw_data->dma_info[i].len;
-       }
-       return i;
-}
-
-/*
- * Restart all queues, starting with the one _after_ the disk given,
- * thus reducing the chance of starvation of higher numbered disks.
- */
-static void viodasd_restart_all_queues_starting_from(int first_index)
-{
-       int i;
-
-       for (i = first_index + 1; i < MAX_DISKNO; ++i)
-               if (viodasd_devices[i].disk)
-                       blk_run_queue(viodasd_devices[i].disk->queue);
-       for (i = 0; i <= first_index; ++i)
-               if (viodasd_devices[i].disk)
-                       blk_run_queue(viodasd_devices[i].disk->queue);
-}
-
-/*
- * For read and write requests, decrement the number of outstanding requests,
- * Free the DMA buffers we allocated.
- */
-static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
-{
-       int num_sg, num_sect, pci_direction, total_len;
-       struct request *req;
-       struct scatterlist sg[VIOMAXBLOCKDMA];
-       struct HvLpEvent *event = &bevent->event;
-       unsigned long irq_flags;
-       struct viodasd_device *d;
-       int error;
-       spinlock_t *qlock;
-
-       num_sg = block_event_to_scatterlist(bevent, sg, &total_len);
-       num_sect = total_len >> 9;
-       if (event->xSubtype == (viomajorsubtype_blockio | vioblockread))
-               pci_direction = DMA_FROM_DEVICE;
-       else
-               pci_direction = DMA_TO_DEVICE;
-       req = (struct request *)bevent->event.xCorrelationToken;
-       d = req->rq_disk->private_data;
-
-       dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
-
-       /*
-        * Since this is running in interrupt mode, we need to make sure
-        * we're not stepping on any global I/O operations
-        */
-       spin_lock_irqsave(&viodasd_spinlock, irq_flags);
-       num_req_outstanding--;
-       spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
-
-       error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
-       if (error) {
-               const struct vio_error_entry *err;
-               err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
-               pr_warning("read/write error %d:0x%04x (%s)\n",
-                          event->xRc, bevent->sub_result, err->msg);
-               num_sect = blk_rq_sectors(req);
-       }
-       qlock = req->q->queue_lock;
-       spin_lock_irqsave(qlock, irq_flags);
-       viodasd_end_request(req, error, num_sect);
-       spin_unlock_irqrestore(qlock, irq_flags);
-
-       /* Finally, try to get more requests off of this device's queue */
-       viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
-
-       return 0;
-}
-
-/* This routine handles incoming block LP events */
-static void handle_block_event(struct HvLpEvent *event)
-{
-       struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
-       struct viodasd_waitevent *pwe;
-
-       if (event == NULL)
-               /* Notification that a partition went away! */
-               return;
-       /* First, we should NEVER get an int here...only acks */
-       if (hvlpevent_is_int(event)) {
-               pr_warning("Yikes! got an int in viodasd event handler!\n");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-
-       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-       case vioblockopen:
-               /*
-                * Handle a response to an open request.  We get all the
-                * disk information in the response, so update it.  The
-                * correlation token contains a pointer to a waitevent
-                * structure that has a completion in it.  update the
-                * return code in the waitevent structure and post the
-                * completion to wake up the guy who sent the request
-                */
-               pwe = (struct viodasd_waitevent *)event->xCorrelationToken;
-               pwe->rc = event->xRc;
-               pwe->sub_result = bevent->sub_result;
-               if (event->xRc == HvLpEvent_Rc_Good) {
-                       const struct open_data *data = &bevent->u.open_data;
-                       struct viodasd_device *device =
-                               &viodasd_devices[bevent->disk];
-                       device->read_only =
-                               bevent->flags & vioblockflags_ro;
-                       device->size = data->disk_size;
-                       device->cylinders = data->cylinders;
-                       device->tracks = data->tracks;
-                       device->sectors = data->sectors;
-                       device->bytes_per_sector = data->bytes_per_sector;
-                       pwe->max_disk = data->max_disk;
-               }
-               complete(&pwe->com);
-               break;
-       case vioblockclose:
-               break;
-       case vioblockread:
-       case vioblockwrite:
-               viodasd_handle_read_write(bevent);
-               break;
-
-       default:
-               pr_warning("invalid subtype!");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-/*
- * Get the driver to reprobe for more disks.
- */
-static ssize_t probe_disks(struct device_driver *drv, const char *buf,
-               size_t count)
-{
-       struct viodasd_device *d;
-
-       for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
-               if (d->disk == NULL)
-                       probe_disk(d);
-       }
-       return count;
-}
-static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
-
-static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-       struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
-
-       d->dev = &vdev->dev;
-       if (!probe_disk(d))
-               return -ENODEV;
-       return 0;
-}
-
-static int viodasd_remove(struct vio_dev *vdev)
-{
-       struct viodasd_device *d;
-
-       d = &viodasd_devices[vdev->unit_address];
-       if (d->disk) {
-               del_gendisk(d->disk);
-               blk_cleanup_queue(d->disk->queue);
-               put_disk(d->disk);
-               d->disk = NULL;
-       }
-       d->dev = NULL;
-       return 0;
-}
-
-/**
- * viodasd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viodasd_device_table[] __devinitdata = {
-       { "block", "IBM,iSeries-viodasd" },
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viodasd_device_table);
-
-static struct vio_driver viodasd_driver = {
-       .id_table = viodasd_device_table,
-       .probe = viodasd_probe,
-       .remove = viodasd_remove,
-       .driver = {
-               .name = "viodasd",
-               .owner = THIS_MODULE,
-       }
-};
-
-static int need_delete_probe;
-
-/*
- * Initialize the whole device driver.  Handle module and non-module
- * versions
- */
-static int __init viodasd_init(void)
-{
-       int rc;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
-               rc = -ENODEV;
-               goto early_fail;
-       }
-
-       /* Try to open to our host lp */
-       if (viopath_hostLp == HvLpIndexInvalid)
-               vio_set_hostlp();
-
-       if (viopath_hostLp == HvLpIndexInvalid) {
-               pr_warning("invalid hosting partition\n");
-               rc = -EIO;
-               goto early_fail;
-       }
-
-       pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp);
-
-        /* register the block device */
-       rc =  register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-       if (rc) {
-               pr_warning("Unable to get major number %d for %s\n",
-                          VIODASD_MAJOR, VIOD_GENHD_NAME);
-               goto early_fail;
-       }
-       /* Actually open the path to the hosting partition */
-       rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
-                               VIOMAXREQ + 2);
-       if (rc) {
-               pr_warning("error opening path to host partition %d\n",
-                          viopath_hostLp);
-               goto unregister_blk;
-       }
-
-       /* Initialize our request handler */
-       vio_setHandler(viomajorsubtype_blockio, handle_block_event);
-
-       rc = vio_register_driver(&viodasd_driver);
-       if (rc) {
-               pr_warning("vio_register_driver failed\n");
-               goto unset_handler;
-       }
-
-       /*
-        * If this call fails, it just means that we cannot dynamically
-        * add virtual disks, but the driver will still work fine for
-        * all existing disk, so ignore the failure.
-        */
-       if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe))
-               need_delete_probe = 1;
-
-       return 0;
-
-unset_handler:
-       vio_clearHandler(viomajorsubtype_blockio);
-       viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
-unregister_blk:
-       unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-early_fail:
-       return rc;
-}
-module_init(viodasd_init);
-
-void __exit viodasd_exit(void)
-{
-       if (need_delete_probe)
-               driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
-       vio_unregister_driver(&viodasd_driver);
-       vio_clearHandler(viomajorsubtype_blockio);
-       viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
-       unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-}
-module_exit(viodasd_exit);
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
deleted file mode 100644 (file)
index 7878da8..0000000
+++ /dev/null
@@ -1,739 +0,0 @@
-/* -*- linux-c -*-
- *  drivers/cdrom/viocd.c
- *
- *  iSeries Virtual CD Rom
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM 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; either version 2 of the
- * License, or (at your option) anyu later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This routine provides access to CD ROM drives owned and managed by an
- * OS/400 partition running on the same box as this Linux partition.
- *
- * All operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/cdrom.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-#include <linux/scatterlist.h>
-
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-#define VIOCD_DEVICE                   "iseries/vcd"
-
-#define VIOCD_VERS "1.06"
-
-/*
- * Should probably make this a module parameter....sigh
- */
-#define VIOCD_MAX_CD   HVMAXARCHITECTEDVIRTUALCDROMS
-
-static DEFINE_MUTEX(viocd_mutex);
-static const struct vio_error_entry viocd_err_table[] = {
-       {0x0201, EINVAL, "Invalid Range"},
-       {0x0202, EINVAL, "Invalid Token"},
-       {0x0203, EIO, "DMA Error"},
-       {0x0204, EIO, "Use Error"},
-       {0x0205, EIO, "Release Error"},
-       {0x0206, EINVAL, "Invalid CD"},
-       {0x020C, EROFS, "Read Only Device"},
-       {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"},
-       {0x020E, EIO, "Optical System Error (Varied Off?)"},
-       {0x02FF, EIO, "Internal Error"},
-       {0x3010, EIO, "Changed Volume"},
-       {0xC100, EIO, "Optical System Error"},
-       {0x0000, 0, NULL},
-};
-
-/*
- * This is the structure we use to exchange info between driver and interrupt
- * handler
- */
-struct viocd_waitevent {
-       struct completion       com;
-       int                     rc;
-       u16                     sub_result;
-       int                     changed;
-};
-
-/* this is a lookup table for the true capabilities of a device */
-struct capability_entry {
-       char    *type;
-       int     capability;
-};
-
-static struct capability_entry capability_table[] __initdata = {
-       { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-       { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-       { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-       { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
-       { "6321", CDC_LOCK },
-       { "632B", 0 },
-       { NULL  , CDC_LOCK },
-};
-
-/* These are our internal structures for keeping track of devices */
-static int viocd_numdev;
-
-struct disk_info {
-       struct gendisk                  *viocd_disk;
-       struct cdrom_device_info        viocd_info;
-       struct device                   *dev;
-       const char                      *rsrcname;
-       const char                      *type;
-       const char                      *model;
-};
-static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
-
-#define DEVICE_NR(di)  ((di) - &viocd_diskinfo[0])
-
-static spinlock_t viocd_reqlock;
-
-#define MAX_CD_REQ     1
-
-/* procfs support */
-static int proc_viocd_show(struct seq_file *m, void *v)
-{
-       int i;
-
-       for (i = 0; i < viocd_numdev; i++) {
-               seq_printf(m, "viocd device %d is iSeries resource %10.10s"
-                               "type %4.4s, model %3.3s\n",
-                               i, viocd_diskinfo[i].rsrcname,
-                               viocd_diskinfo[i].type,
-                               viocd_diskinfo[i].model);
-       }
-       return 0;
-}
-
-static int proc_viocd_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_viocd_show, NULL);
-}
-
-static const struct file_operations proc_viocd_operations = {
-       .owner          = THIS_MODULE,
-       .open           = proc_viocd_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int viocd_blk_open(struct block_device *bdev, fmode_t mode)
-{
-       struct disk_info *di = bdev->bd_disk->private_data;
-       int ret;
-
-       mutex_lock(&viocd_mutex);
-       ret = cdrom_open(&di->viocd_info, bdev, mode);
-       mutex_unlock(&viocd_mutex);
-
-       return ret;
-}
-
-static int viocd_blk_release(struct gendisk *disk, fmode_t mode)
-{
-       struct disk_info *di = disk->private_data;
-       mutex_lock(&viocd_mutex);
-       cdrom_release(&di->viocd_info, mode);
-       mutex_unlock(&viocd_mutex);
-       return 0;
-}
-
-static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode,
-               unsigned cmd, unsigned long arg)
-{
-       struct disk_info *di = bdev->bd_disk->private_data;
-       int ret;
-
-       mutex_lock(&viocd_mutex);
-       ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg);
-       mutex_unlock(&viocd_mutex);
-
-       return ret;
-}
-
-static unsigned int viocd_blk_check_events(struct gendisk *disk,
-                                          unsigned int clearing)
-{
-       struct disk_info *di = disk->private_data;
-       return cdrom_check_events(&di->viocd_info, clearing);
-}
-
-static const struct block_device_operations viocd_fops = {
-       .owner =                THIS_MODULE,
-       .open =                 viocd_blk_open,
-       .release =              viocd_blk_release,
-       .ioctl =                viocd_blk_ioctl,
-       .check_events =         viocd_blk_check_events,
-};
-
-static int viocd_open(struct cdrom_device_info *cdi, int purpose)
-{
-        struct disk_info *diskinfo = cdi->handle;
-       int device_no = DEVICE_NR(diskinfo);
-       HvLpEvent_Rc hvrc;
-       struct viocd_waitevent we;
-
-       init_completion(&we.com);
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_cdio | viocdopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-                          (int)hvrc);
-               return -EIO;
-       }
-
-       wait_for_completion(&we.com);
-
-       if (we.rc) {
-               const struct vio_error_entry *err =
-                       vio_lookup_rc(viocd_err_table, we.sub_result);
-               pr_warning("bad rc %d:0x%04X on open: %s\n",
-                          we.rc, we.sub_result, err->msg);
-               return -err->errno;
-       }
-
-       return 0;
-}
-
-static void viocd_release(struct cdrom_device_info *cdi)
-{
-       int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-       HvLpEvent_Rc hvrc;
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_cdio | viocdclose,
-                       HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp), 0,
-                       VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0);
-       if (hvrc != 0)
-               pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-                          (int)hvrc);
-}
-
-/* Send a read or write request to OS/400 */
-static int send_request(struct request *req)
-{
-       HvLpEvent_Rc hvrc;
-       struct disk_info *diskinfo = req->rq_disk->private_data;
-       u64 len;
-       dma_addr_t dmaaddr;
-       int direction;
-       u16 cmd;
-       struct scatterlist sg;
-
-       BUG_ON(req->nr_phys_segments > 1);
-
-       if (rq_data_dir(req) == READ) {
-               direction = DMA_FROM_DEVICE;
-               cmd = viomajorsubtype_cdio | viocdread;
-       } else {
-               direction = DMA_TO_DEVICE;
-               cmd = viomajorsubtype_cdio | viocdwrite;
-       }
-
-       sg_init_table(&sg, 1);
-        if (blk_rq_map_sg(req->q, req, &sg) == 0) {
-               pr_warning("error setting up scatter/gather list\n");
-               return -1;
-       }
-
-       if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) {
-               pr_warning("error allocating sg tce\n");
-               return -1;
-       }
-       dmaaddr = sg_dma_address(&sg);
-       len = sg_dma_len(&sg);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo, cmd,
-                       HvLpEvent_AckInd_DoAck,
-                       HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)req, VIOVERSION << 16,
-                       ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
-                       (u64)blk_rq_pos(req) * 512, len, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               pr_warning("hv error on op %d\n", (int)hvrc);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int rwreq;
-
-static void do_viocd_request(struct request_queue *q)
-{
-       struct request *req;
-
-       while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) {
-               if (req->cmd_type != REQ_TYPE_FS)
-                       __blk_end_request_all(req, -EIO);
-               else if (send_request(req) < 0) {
-                       pr_warning("unable to send message to OS/400!\n");
-                       __blk_end_request_all(req, -EIO);
-               } else
-                       rwreq++;
-       }
-}
-
-static unsigned int viocd_check_events(struct cdrom_device_info *cdi,
-                                      unsigned int clearing, int disc_nr)
-{
-       struct viocd_waitevent we;
-       HvLpEvent_Rc hvrc;
-       int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-
-       init_completion(&we.com);
-
-       /* Send the open event to OS/400 */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_cdio | viocdcheck,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
-                       0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-                          (int)hvrc);
-               return 0;
-       }
-
-       wait_for_completion(&we.com);
-
-       /* Check the return code.  If bad, assume no change */
-       if (we.rc) {
-               const struct vio_error_entry *err =
-                       vio_lookup_rc(viocd_err_table, we.sub_result);
-               pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n",
-                          we.rc, we.sub_result, err->msg);
-               return 0;
-       }
-
-       return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static int viocd_lock_door(struct cdrom_device_info *cdi, int locking)
-{
-       HvLpEvent_Rc hvrc;
-       u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-       /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */
-       u64 flags = !!locking;
-       struct viocd_waitevent we;
-
-       init_completion(&we.com);
-
-       /* Send the lockdoor event to OS/400 */
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_cdio | viocdlockdoor,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)&we, VIOVERSION << 16,
-                       (device_no << 48) | (flags << 32), 0, 0, 0);
-       if (hvrc != 0) {
-               pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
-                          (int)hvrc);
-               return -EIO;
-       }
-
-       wait_for_completion(&we.com);
-
-       if (we.rc != 0)
-               return -EIO;
-       return 0;
-}
-
-static int viocd_packet(struct cdrom_device_info *cdi,
-               struct packet_command *cgc)
-{
-       unsigned int buflen = cgc->buflen;
-       int ret = -EIO;
-
-       switch (cgc->cmd[0]) {
-       case GPCMD_READ_DISC_INFO:
-               {
-                       disc_information *di = (disc_information *)cgc->buffer;
-
-                       if (buflen >= 2) {
-                               di->disc_information_length = cpu_to_be16(1);
-                               ret = 0;
-                       }
-                       if (buflen >= 3)
-                               di->erasable =
-                                       (cdi->ops->capability & ~cdi->mask
-                                        & (CDC_DVD_RAM | CDC_RAM)) != 0;
-               }
-               break;
-       case GPCMD_GET_CONFIGURATION:
-               if (cgc->cmd[3] == CDF_RWRT) {
-                       struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
-
-                       if ((buflen >=
-                            (sizeof(struct feature_header) + sizeof(*rfd))) &&
-                           (cdi->ops->capability & ~cdi->mask
-                            & (CDC_DVD_RAM | CDC_RAM))) {
-                               rfd->feature_code = cpu_to_be16(CDF_RWRT);
-                               rfd->curr = 1;
-                               ret = 0;
-                       }
-               }
-               break;
-       default:
-               if (cgc->sense) {
-                       /* indicate Unknown code */
-                       cgc->sense->sense_key = 0x05;
-                       cgc->sense->asc = 0x20;
-                       cgc->sense->ascq = 0x00;
-               }
-               break;
-       }
-
-       cgc->stat = ret;
-       return ret;
-}
-
-static void restart_all_queues(int first_index)
-{
-       int i;
-
-       for (i = first_index + 1; i < viocd_numdev; i++)
-               if (viocd_diskinfo[i].viocd_disk)
-                       blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
-       for (i = 0; i <= first_index; i++)
-               if (viocd_diskinfo[i].viocd_disk)
-                       blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
-}
-
-/* This routine handles incoming CD LP events */
-static void vio_handle_cd_event(struct HvLpEvent *event)
-{
-       struct viocdlpevent *bevent;
-       struct viocd_waitevent *pwe;
-       struct disk_info *di;
-       unsigned long flags;
-       struct request *req;
-
-
-       if (event == NULL)
-               /* Notification that a partition went away! */
-               return;
-       /* First, we should NEVER get an int here...only acks */
-       if (hvlpevent_is_int(event)) {
-               pr_warning("Yikes! got an int in viocd event handler!\n");
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-
-       bevent = (struct viocdlpevent *)event;
-
-       switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
-       case viocdopen:
-               if (event->xRc == 0) {
-                       di = &viocd_diskinfo[bevent->disk];
-                       blk_queue_logical_block_size(di->viocd_disk->queue,
-                                                    bevent->block_size);
-                       set_capacity(di->viocd_disk,
-                                       bevent->media_size *
-                                       bevent->block_size / 512);
-               }
-               /* FALLTHROUGH !! */
-       case viocdlockdoor:
-               pwe = (struct viocd_waitevent *)event->xCorrelationToken;
-return_complete:
-               pwe->rc = event->xRc;
-               pwe->sub_result = bevent->sub_result;
-               complete(&pwe->com);
-               break;
-
-       case viocdcheck:
-               pwe = (struct viocd_waitevent *)event->xCorrelationToken;
-               pwe->changed = bevent->flags;
-               goto return_complete;
-
-       case viocdclose:
-               break;
-
-       case viocdwrite:
-       case viocdread:
-               /*
-                * Since this is running in interrupt mode, we need to
-                * make sure we're not stepping on any global I/O operations
-                */
-               di = &viocd_diskinfo[bevent->disk];
-               spin_lock_irqsave(&viocd_reqlock, flags);
-               dma_unmap_single(di->dev, bevent->token, bevent->len,
-                               ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread)
-                               ?  DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               req = (struct request *)bevent->event.xCorrelationToken;
-               rwreq--;
-
-               if (event->xRc != HvLpEvent_Rc_Good) {
-                       const struct vio_error_entry *err =
-                               vio_lookup_rc(viocd_err_table,
-                                               bevent->sub_result);
-                       pr_warning("request %p failed with rc %d:0x%04X: %s\n",
-                                  req, event->xRc,
-                                  bevent->sub_result, err->msg);
-                       __blk_end_request_all(req, -EIO);
-               } else
-                       __blk_end_request_all(req, 0);
-
-               /* restart handling of incoming requests */
-               spin_unlock_irqrestore(&viocd_reqlock, flags);
-               restart_all_queues(bevent->disk);
-               break;
-
-       default:
-               pr_warning("message with invalid subtype %0x04X!\n",
-                          event->xSubtype & VIOMINOR_SUBTYPE_MASK);
-               if (hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                            void *arg)
-{
-       return -EINVAL;
-}
-
-static struct cdrom_device_ops viocd_dops = {
-       .open = viocd_open,
-       .release = viocd_release,
-       .check_events = viocd_check_events,
-       .lock_door = viocd_lock_door,
-       .generic_packet = viocd_packet,
-       .audio_ioctl = viocd_audio_ioctl,
-       .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
-};
-
-static int find_capability(const char *type)
-{
-       struct capability_entry *entry;
-
-       for(entry = capability_table; entry->type; ++entry)
-               if(!strncmp(entry->type, type, 4))
-                       break;
-       return entry->capability;
-}
-
-static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-       struct gendisk *gendisk;
-       int deviceno;
-       struct disk_info *d;
-       struct cdrom_device_info *c;
-       struct request_queue *q;
-       struct device_node *node = vdev->dev.of_node;
-
-       deviceno = vdev->unit_address;
-       if (deviceno >= VIOCD_MAX_CD)
-               return -ENODEV;
-       if (!node)
-               return -ENODEV;
-
-       if (deviceno >= viocd_numdev)
-               viocd_numdev = deviceno + 1;
-
-       d = &viocd_diskinfo[deviceno];
-       d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
-       d->type = of_get_property(node, "linux,vio_type", NULL);
-       d->model = of_get_property(node, "linux,vio_model", NULL);
-
-       c = &d->viocd_info;
-
-       c->ops = &viocd_dops;
-       c->speed = 4;
-       c->capacity = 1;
-       c->handle = d;
-       c->mask = ~find_capability(d->type);
-       sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
-
-       if (register_cdrom(c) != 0) {
-               pr_warning("Cannot register viocd CD-ROM %s!\n", c->name);
-               goto out;
-       }
-       pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n",
-               c->name, d->rsrcname, d->type, d->model);
-       q = blk_init_queue(do_viocd_request, &viocd_reqlock);
-       if (q == NULL) {
-               pr_warning("Cannot allocate queue for %s!\n", c->name);
-               goto out_unregister_cdrom;
-       }
-       gendisk = alloc_disk(1);
-       if (gendisk == NULL) {
-               pr_warning("Cannot create gendisk for %s!\n", c->name);
-               goto out_cleanup_queue;
-       }
-       gendisk->major = VIOCD_MAJOR;
-       gendisk->first_minor = deviceno;
-       strncpy(gendisk->disk_name, c->name,
-                       sizeof(gendisk->disk_name));
-       blk_queue_max_segments(q, 1);
-       blk_queue_max_hw_sectors(q, 4096 / 512);
-       gendisk->queue = q;
-       gendisk->fops = &viocd_fops;
-       gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
-                        GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-       set_capacity(gendisk, 0);
-       gendisk->private_data = d;
-       d->viocd_disk = gendisk;
-       d->dev = &vdev->dev;
-       gendisk->driverfs_dev = d->dev;
-       add_disk(gendisk);
-       return 0;
-
-out_cleanup_queue:
-       blk_cleanup_queue(q);
-out_unregister_cdrom:
-       unregister_cdrom(c);
-out:
-       return -ENODEV;
-}
-
-static int viocd_remove(struct vio_dev *vdev)
-{
-       struct disk_info *d = &viocd_diskinfo[vdev->unit_address];
-
-       unregister_cdrom(&d->viocd_info);
-       del_gendisk(d->viocd_disk);
-       blk_cleanup_queue(d->viocd_disk->queue);
-       put_disk(d->viocd_disk);
-       return 0;
-}
-
-/**
- * viocd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viocd_device_table[] __devinitdata = {
-       { "block", "IBM,iSeries-viocd" },
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viocd_device_table);
-
-static struct vio_driver viocd_driver = {
-       .id_table = viocd_device_table,
-       .probe = viocd_probe,
-       .remove = viocd_remove,
-       .driver = {
-               .name = "viocd",
-               .owner = THIS_MODULE,
-       }
-};
-
-static int __init viocd_init(void)
-{
-       int ret = 0;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return -ENODEV;
-
-       if (viopath_hostLp == HvLpIndexInvalid) {
-               vio_set_hostlp();
-               /* If we don't have a host, bail out */
-               if (viopath_hostLp == HvLpIndexInvalid)
-                       return -ENODEV;
-       }
-
-       pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp);
-
-       if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) {
-               pr_warning("Unable to get major %d for %s\n",
-                          VIOCD_MAJOR, VIOCD_DEVICE);
-               return -EIO;
-       }
-
-       ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio,
-                       MAX_CD_REQ + 2);
-       if (ret) {
-               pr_warning("error opening path to host partition %d\n",
-                          viopath_hostLp);
-               goto out_unregister;
-       }
-
-       /* Initialize our request handler */
-       vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
-
-       spin_lock_init(&viocd_reqlock);
-
-       ret = vio_register_driver(&viocd_driver);
-       if (ret)
-               goto out_free_info;
-
-       proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL,
-                   &proc_viocd_operations);
-       return 0;
-
-out_free_info:
-       vio_clearHandler(viomajorsubtype_cdio);
-       viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
-out_unregister:
-       unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
-       return ret;
-}
-
-static void __exit viocd_exit(void)
-{
-       remove_proc_entry("iSeries/viocd", NULL);
-       vio_unregister_driver(&viocd_driver);
-       viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
-       vio_clearHandler(viomajorsubtype_cdio);
-       unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
-}
-
-module_init(viocd_init);
-module_exit(viocd_exit);
-MODULE_LICENSE("GPL");
index 0bc0cb7..de473ef 100644 (file)
@@ -115,10 +115,7 @@ static int __init tx4939_rng_probe(struct platform_device *dev)
        rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
        if (!rngdev)
                return -ENOMEM;
-       if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r),
-                                    dev_name(&dev->dev)))
-               return -EBUSY;
-       rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r));
+       rngdev->base = devm_request_and_ioremap(&dev->dev, r);
        if (!rngdev->base)
                return -EBUSY;
 
index 7fc75e4..a048199 100644 (file)
@@ -5,7 +5,6 @@
 menuconfig TCG_TPM
        tristate "TPM Hardware Support"
        depends on HAS_IOMEM
-       depends on EXPERIMENTAL
        select SECURITYFS
        ---help---
          If you have a TPM security chip in your system, which
index 32362cf..ad7c732 100644 (file)
@@ -1221,12 +1221,13 @@ ssize_t tpm_read(struct file *file, char __user *buf,
        ret_size = atomic_read(&chip->data_pending);
        atomic_set(&chip->data_pending, 0);
        if (ret_size > 0) {     /* relay data */
+               ssize_t orig_ret_size = ret_size;
                if (size < ret_size)
                        ret_size = size;
 
                mutex_lock(&chip->buffer_mutex);
                rc = copy_to_user(buf, chip->data_buffer, ret_size);
-               memset(chip->data_buffer, 0, ret_size);
+               memset(chip->data_buffer, 0, orig_ret_size);
                if (rc)
                        ret_size = -EFAULT;
 
index 0105471..b1c5280 100644 (file)
@@ -99,6 +99,8 @@ struct tpm_vendor_specific {
        wait_queue_head_t int_queue;
 };
 
+#define TPM_VID_INTEL    0x8086
+
 struct tpm_chip {
        struct device *dev;     /* Device stuff */
 
index 70fac9a..d2a70ca 100644 (file)
@@ -367,7 +367,12 @@ static int probe_itpm(struct tpm_chip *chip)
                0x00, 0x00, 0x00, 0xf1
        };
        size_t len = sizeof(cmd_getticks);
-       int rem_itpm = itpm;
+       bool rem_itpm = itpm;
+       u16 vendor = ioread16(chip->vendor.iobase + TPM_DID_VID(0));
+
+       /* probe only iTPMS */
+       if (vendor != TPM_VID_INTEL)
+               return 0;
 
        itpm = 0;
 
@@ -390,9 +395,6 @@ static int probe_itpm(struct tpm_chip *chip)
 out:
        itpm = rem_itpm;
        tpm_tis_ready(chip);
-       /* some TPMs need a break here otherwise they will not work
-        * correctly on the immediately subsequent command */
-       msleep(chip->vendor.timeout_b);
        release_locality(chip, chip->vendor.locality, 0);
 
        return rc;
@@ -508,7 +510,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                        resource_size_t len, unsigned int irq)
 {
        u32 vendor, intfcaps, intmask;
-       int rc, i, irq_s, irq_e;
+       int rc, i, irq_s, irq_e, probe;
        struct tpm_chip *chip;
 
        if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
@@ -538,11 +540,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
        if (!itpm) {
-               itpm = probe_itpm(chip);
-               if (itpm < 0) {
+               probe = probe_itpm(chip);
+               if (probe < 0) {
                        rc = -ENODEV;
                        goto out_err;
                }
+               itpm = (probe == 0) ? 0 : 1;
        }
 
        if (itpm)
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
deleted file mode 100644 (file)
index 8b34c65..0000000
+++ /dev/null
@@ -1,1041 +0,0 @@
-/* -*- linux-c -*-
- *  drivers/char/viotape.c
- *
- *  iSeries Virtual Tape
- *
- *  Authors: Dave Boutcher <boutcher@us.ibm.com>
- *           Ryan Arnold <ryanarn@us.ibm.com>
- *           Colin Devilbiss <devilbis@us.ibm.com>
- *           Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM 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; either version 2 of the
- * License, or (at your option) anyu later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This routine provides access to tape drives owned and managed by an OS/400
- * partition running on the same box as this Linux partition.
- *
- * All tape operations are performed by sending messages back and forth to
- * the OS/400 partition.  The format of the messages is defined in
- * iseries/vio.h
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mtio.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/major.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/ioctls.h>
-#include <asm/firmware.h>
-#include <asm/vio.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_lp_config.h>
-
-#define VIOTAPE_VERSION                "1.2"
-#define VIOTAPE_MAXREQ         1
-
-#define VIOTAPE_KERN_WARN      KERN_WARNING "viotape: "
-#define VIOTAPE_KERN_INFO      KERN_INFO "viotape: "
-
-static DEFINE_MUTEX(proc_viotape_mutex);
-static int viotape_numdev;
-
-/*
- * The minor number follows the conventions of the SCSI tape drives.  The
- * rewind and mode are encoded in the minor #.  We use this struct to break
- * them out
- */
-struct viot_devinfo_struct {
-       int devno;
-       int mode;
-       int rewind;
-};
-
-#define VIOTAPOP_RESET          0
-#define VIOTAPOP_FSF           1
-#define VIOTAPOP_BSF           2
-#define VIOTAPOP_FSR           3
-#define VIOTAPOP_BSR           4
-#define VIOTAPOP_WEOF          5
-#define VIOTAPOP_REW           6
-#define VIOTAPOP_NOP           7
-#define VIOTAPOP_EOM           8
-#define VIOTAPOP_ERASE          9
-#define VIOTAPOP_SETBLK        10
-#define VIOTAPOP_SETDENSITY    11
-#define VIOTAPOP_SETPOS               12
-#define VIOTAPOP_GETPOS               13
-#define VIOTAPOP_SETPART       14
-#define VIOTAPOP_UNLOAD        15
-
-enum viotaperc {
-       viotape_InvalidRange = 0x0601,
-       viotape_InvalidToken = 0x0602,
-       viotape_DMAError = 0x0603,
-       viotape_UseError = 0x0604,
-       viotape_ReleaseError = 0x0605,
-       viotape_InvalidTape = 0x0606,
-       viotape_InvalidOp = 0x0607,
-       viotape_TapeErr = 0x0608,
-
-       viotape_AllocTimedOut = 0x0640,
-       viotape_BOTEnc = 0x0641,
-       viotape_BlankTape = 0x0642,
-       viotape_BufferEmpty = 0x0643,
-       viotape_CleanCartFound = 0x0644,
-       viotape_CmdNotAllowed = 0x0645,
-       viotape_CmdNotSupported = 0x0646,
-       viotape_DataCheck = 0x0647,
-       viotape_DecompressErr = 0x0648,
-       viotape_DeviceTimeout = 0x0649,
-       viotape_DeviceUnavail = 0x064a,
-       viotape_DeviceBusy = 0x064b,
-       viotape_EndOfMedia = 0x064c,
-       viotape_EndOfTape = 0x064d,
-       viotape_EquipCheck = 0x064e,
-       viotape_InsufficientRs = 0x064f,
-       viotape_InvalidLogBlk = 0x0650,
-       viotape_LengthError = 0x0651,
-       viotape_LibDoorOpen = 0x0652,
-       viotape_LoadFailure = 0x0653,
-       viotape_NotCapable = 0x0654,
-       viotape_NotOperational = 0x0655,
-       viotape_NotReady = 0x0656,
-       viotape_OpCancelled = 0x0657,
-       viotape_PhyLinkErr = 0x0658,
-       viotape_RdyNotBOT = 0x0659,
-       viotape_TapeMark = 0x065a,
-       viotape_WriteProt = 0x065b
-};
-
-static const struct vio_error_entry viotape_err_table[] = {
-       { viotape_InvalidRange, EIO, "Internal error" },
-       { viotape_InvalidToken, EIO, "Internal error" },
-       { viotape_DMAError, EIO, "DMA error" },
-       { viotape_UseError, EIO, "Internal error" },
-       { viotape_ReleaseError, EIO, "Internal error" },
-       { viotape_InvalidTape, EIO, "Invalid tape device" },
-       { viotape_InvalidOp, EIO, "Invalid operation" },
-       { viotape_TapeErr, EIO, "Tape error" },
-       { viotape_AllocTimedOut, EBUSY, "Allocate timed out" },
-       { viotape_BOTEnc, EIO, "Beginning of tape encountered" },
-       { viotape_BlankTape, EIO, "Blank tape" },
-       { viotape_BufferEmpty, EIO, "Buffer empty" },
-       { viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" },
-       { viotape_CmdNotAllowed, EIO, "Command not allowed" },
-       { viotape_CmdNotSupported, EIO, "Command not supported" },
-       { viotape_DataCheck, EIO, "Data check" },
-       { viotape_DecompressErr, EIO, "Decompression error" },
-       { viotape_DeviceTimeout, EBUSY, "Device timeout" },
-       { viotape_DeviceUnavail, EIO, "Device unavailable" },
-       { viotape_DeviceBusy, EBUSY, "Device busy" },
-       { viotape_EndOfMedia, ENOSPC, "End of media" },
-       { viotape_EndOfTape, ENOSPC, "End of tape" },
-       { viotape_EquipCheck, EIO, "Equipment check" },
-       { viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" },
-       { viotape_InvalidLogBlk, EIO, "Invalid logical block location" },
-       { viotape_LengthError, EOVERFLOW, "Length error" },
-       { viotape_LibDoorOpen, EBUSY, "Door open" },
-       { viotape_LoadFailure, ENOMEDIUM, "Load failure" },
-       { viotape_NotCapable, EIO, "Not capable" },
-       { viotape_NotOperational, EIO, "Not operational" },
-       { viotape_NotReady, EIO, "Not ready" },
-       { viotape_OpCancelled, EIO, "Operation cancelled" },
-       { viotape_PhyLinkErr, EIO, "Physical link error" },
-       { viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" },
-       { viotape_TapeMark, EIO, "Tape mark" },
-       { viotape_WriteProt, EROFS, "Write protection error" },
-       { 0, 0, NULL },
-};
-
-/* Maximum number of tapes we support */
-#define VIOTAPE_MAX_TAPE       HVMAXARCHITECTEDVIRTUALTAPES
-#define MAX_PARTITIONS         4
-
-/* defines for current tape state */
-#define VIOT_IDLE              0
-#define VIOT_READING           1
-#define VIOT_WRITING           2
-
-/* Our info on the tapes */
-static struct {
-       const char *rsrcname;
-       const char *type;
-       const char *model;
-} viotape_unitinfo[VIOTAPE_MAX_TAPE];
-
-static struct mtget viomtget[VIOTAPE_MAX_TAPE];
-
-static struct class *tape_class;
-
-static struct device *tape_device[VIOTAPE_MAX_TAPE];
-
-/*
- * maintain the current state of each tape (and partition)
- * so that we know when to write EOF marks.
- */
-static struct {
-       unsigned char   cur_part;
-       unsigned char   part_stat_rwi[MAX_PARTITIONS];
-} state[VIOTAPE_MAX_TAPE];
-
-/* We single-thread */
-static struct semaphore reqSem;
-
-/*
- * When we send a request, we use this struct to get the response back
- * from the interrupt handler
- */
-struct op_struct {
-       void                    *buffer;
-       dma_addr_t              dmaaddr;
-       size_t                  count;
-       int                     rc;
-       int                     non_blocking;
-       struct completion       com;
-       struct device           *dev;
-       struct op_struct        *next;
-};
-
-static spinlock_t      op_struct_list_lock;
-static struct op_struct        *op_struct_list;
-
-/* forward declaration to resolve interdependence */
-static int chg_state(int index, unsigned char new_state, struct file *file);
-
-/* procfs support */
-static int proc_viotape_show(struct seq_file *m, void *v)
-{
-       int i;
-
-       seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n");
-       for (i = 0; i < viotape_numdev; i++) {
-               seq_printf(m, "viotape device %d is iSeries resource %10.10s"
-                               "type %4.4s, model %3.3s\n",
-                               i, viotape_unitinfo[i].rsrcname,
-                               viotape_unitinfo[i].type,
-                               viotape_unitinfo[i].model);
-       }
-       return 0;
-}
-
-static int proc_viotape_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, proc_viotape_show, NULL);
-}
-
-static const struct file_operations proc_viotape_operations = {
-       .owner          = THIS_MODULE,
-       .open           = proc_viotape_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-/* Decode the device minor number into its parts */
-void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi)
-{
-       devi->devno = iminor(ino) & 0x1F;
-       devi->mode = (iminor(ino) & 0x60) >> 5;
-       /* if bit is set in the minor, do _not_ rewind automatically */
-       devi->rewind = (iminor(ino) & 0x80) == 0;
-}
-
-/* This is called only from the exit and init paths, so no need for locking */
-static void clear_op_struct_pool(void)
-{
-       while (op_struct_list) {
-               struct op_struct *toFree = op_struct_list;
-               op_struct_list = op_struct_list->next;
-               kfree(toFree);
-       }
-}
-
-/* Likewise, this is only called from the init path */
-static int add_op_structs(int structs)
-{
-       int i;
-
-       for (i = 0; i < structs; ++i) {
-               struct op_struct *new_struct =
-                       kmalloc(sizeof(*new_struct), GFP_KERNEL);
-               if (!new_struct) {
-                       clear_op_struct_pool();
-                       return -ENOMEM;
-               }
-               new_struct->next = op_struct_list;
-               op_struct_list = new_struct;
-       }
-       return 0;
-}
-
-/* Allocate an op structure from our pool */
-static struct op_struct *get_op_struct(void)
-{
-       struct op_struct *retval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&op_struct_list_lock, flags);
-       retval = op_struct_list;
-       if (retval)
-               op_struct_list = retval->next;
-       spin_unlock_irqrestore(&op_struct_list_lock, flags);
-       if (retval) {
-               memset(retval, 0, sizeof(*retval));
-               init_completion(&retval->com);
-       }
-
-       return retval;
-}
-
-/* Return an op structure to our pool */
-static void free_op_struct(struct op_struct *op_struct)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&op_struct_list_lock, flags);
-       op_struct->next = op_struct_list;
-       op_struct_list = op_struct;
-       spin_unlock_irqrestore(&op_struct_list_lock, flags);
-}
-
-/* Map our tape return codes to errno values */
-int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
-{
-       const struct vio_error_entry *err;
-
-       if (tape_rc == 0)
-               return 0;
-
-       err = vio_lookup_rc(viotape_err_table, tape_rc);
-       printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n",
-                       operation, tape_rc, tapeno,
-                       viotape_unitinfo[tapeno].rsrcname, err->msg);
-       return -err->errno;
-}
-
-/* Write */
-static ssize_t viotap_write(struct file *file, const char *buf,
-               size_t count, loff_t * ppos)
-{
-       HvLpEvent_Rc hvrc;
-       unsigned short flags = file->f_flags;
-       int noblock = ((flags & O_NONBLOCK) != 0);
-       ssize_t ret;
-       struct viot_devinfo_struct devi;
-       struct op_struct *op = get_op_struct();
-
-       if (op == NULL)
-               return -ENOMEM;
-
-       get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-       /*
-        * We need to make sure we can send a request.  We use
-        * a semaphore to keep track of # requests in use.  If
-        * we are non-blocking, make sure we don't block on the
-        * semaphore
-        */
-       if (noblock) {
-               if (down_trylock(&reqSem)) {
-                       ret = -EWOULDBLOCK;
-                       goto free_op;
-               }
-       } else
-               down(&reqSem);
-
-       /* Allocate a DMA buffer */
-       op->dev = tape_device[devi.devno];
-       op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
-                       GFP_ATOMIC);
-
-       if (op->buffer == NULL) {
-               printk(VIOTAPE_KERN_WARN
-                               "error allocating dma buffer for len %ld\n",
-                               count);
-               ret = -EFAULT;
-               goto up_sem;
-       }
-
-       /* Copy the data into the buffer */
-       if (copy_from_user(op->buffer, buf, count)) {
-               printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n");
-               ret = -EFAULT;
-               goto free_dma;
-       }
-
-       op->non_blocking = noblock;
-       init_completion(&op->com);
-       op->count = count;
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotapewrite,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)op, VIOVERSION << 16,
-                       ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-                               (int)hvrc);
-               ret = -EIO;
-               goto free_dma;
-       }
-
-       if (noblock)
-               return count;
-
-       wait_for_completion(&op->com);
-
-       if (op->rc)
-               ret = tape_rc_to_errno(op->rc, "write", devi.devno);
-       else {
-               chg_state(devi.devno, VIOT_WRITING, file);
-               ret = op->count;
-       }
-
-free_dma:
-       dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
-       up(&reqSem);
-free_op:
-       free_op_struct(op);
-       return ret;
-}
-
-/* read */
-static ssize_t viotap_read(struct file *file, char *buf, size_t count,
-               loff_t *ptr)
-{
-       HvLpEvent_Rc hvrc;
-       unsigned short flags = file->f_flags;
-       struct op_struct *op = get_op_struct();
-       int noblock = ((flags & O_NONBLOCK) != 0);
-       ssize_t ret;
-       struct viot_devinfo_struct devi;
-
-       if (op == NULL)
-               return -ENOMEM;
-
-       get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-       /*
-        * We need to make sure we can send a request.  We use
-        * a semaphore to keep track of # requests in use.  If
-        * we are non-blocking, make sure we don't block on the
-        * semaphore
-        */
-       if (noblock) {
-               if (down_trylock(&reqSem)) {
-                       ret = -EWOULDBLOCK;
-                       goto free_op;
-               }
-       } else
-               down(&reqSem);
-
-       chg_state(devi.devno, VIOT_READING, file);
-
-       /* Allocate a DMA buffer */
-       op->dev = tape_device[devi.devno];
-       op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
-                       GFP_ATOMIC);
-       if (op->buffer == NULL) {
-               ret = -EFAULT;
-               goto up_sem;
-       }
-
-       op->count = count;
-       init_completion(&op->com);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotaperead,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)op, VIOVERSION << 16,
-                       ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
-       if (hvrc != HvLpEvent_Rc_Good) {
-               printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n",
-                               (int)hvrc);
-               ret = -EIO;
-               goto free_dma;
-       }
-
-       wait_for_completion(&op->com);
-
-       if (op->rc)
-               ret = tape_rc_to_errno(op->rc, "read", devi.devno);
-       else {
-               ret = op->count;
-               if (ret && copy_to_user(buf, op->buffer, ret)) {
-                       printk(VIOTAPE_KERN_WARN "error on copy_to_user\n");
-                       ret = -EFAULT;
-               }
-       }
-
-free_dma:
-       dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
-       up(&reqSem);
-free_op:
-       free_op_struct(op);
-       return ret;
-}
-
-/* ioctl */
-static int viotap_ioctl(struct inode *inode, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       HvLpEvent_Rc hvrc;
-       int ret;
-       struct viot_devinfo_struct devi;
-       struct mtop mtc;
-       u32 myOp;
-       struct op_struct *op = get_op_struct();
-
-       if (op == NULL)
-               return -ENOMEM;
-
-       get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-       down(&reqSem);
-
-       ret = -EINVAL;
-
-       switch (cmd) {
-       case MTIOCTOP:
-               ret = -EFAULT;
-               /*
-                * inode is null if and only if we (the kernel)
-                * made the request
-                */
-               if (inode == NULL)
-                       memcpy(&mtc, (void *) arg, sizeof(struct mtop));
-               else if (copy_from_user((char *)&mtc, (char *)arg,
-                                       sizeof(struct mtop)))
-                       goto free_op;
-
-               ret = -EIO;
-               switch (mtc.mt_op) {
-               case MTRESET:
-                       myOp = VIOTAPOP_RESET;
-                       break;
-               case MTFSF:
-                       myOp = VIOTAPOP_FSF;
-                       break;
-               case MTBSF:
-                       myOp = VIOTAPOP_BSF;
-                       break;
-               case MTFSR:
-                       myOp = VIOTAPOP_FSR;
-                       break;
-               case MTBSR:
-                       myOp = VIOTAPOP_BSR;
-                       break;
-               case MTWEOF:
-                       myOp = VIOTAPOP_WEOF;
-                       break;
-               case MTREW:
-                       myOp = VIOTAPOP_REW;
-                       break;
-               case MTNOP:
-                       myOp = VIOTAPOP_NOP;
-                       break;
-               case MTEOM:
-                       myOp = VIOTAPOP_EOM;
-                       break;
-               case MTERASE:
-                       myOp = VIOTAPOP_ERASE;
-                       break;
-               case MTSETBLK:
-                       myOp = VIOTAPOP_SETBLK;
-                       break;
-               case MTSETDENSITY:
-                       myOp = VIOTAPOP_SETDENSITY;
-                       break;
-               case MTTELL:
-                       myOp = VIOTAPOP_GETPOS;
-                       break;
-               case MTSEEK:
-                       myOp = VIOTAPOP_SETPOS;
-                       break;
-               case MTSETPART:
-                       myOp = VIOTAPOP_SETPART;
-                       break;
-               case MTOFFL:
-                       myOp = VIOTAPOP_UNLOAD;
-                       break;
-               default:
-                       printk(VIOTAPE_KERN_WARN "MTIOCTOP called "
-                                       "with invalid op 0x%x\n", mtc.mt_op);
-                       goto free_op;
-               }
-
-               /*
-                * if we moved the head, we are no longer
-                * reading or writing
-                */
-               switch (mtc.mt_op) {
-               case MTFSF:
-               case MTBSF:
-               case MTFSR:
-               case MTBSR:
-               case MTTELL:
-               case MTSEEK:
-               case MTREW:
-                       chg_state(devi.devno, VIOT_IDLE, file);
-               }
-
-               init_completion(&op->com);
-               hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                               HvLpEvent_Type_VirtualIo,
-                               viomajorsubtype_tape | viotapeop,
-                               HvLpEvent_AckInd_DoAck,
-                               HvLpEvent_AckType_ImmediateAck,
-                               viopath_sourceinst(viopath_hostLp),
-                               viopath_targetinst(viopath_hostLp),
-                               (u64)(unsigned long)op,
-                               VIOVERSION << 16,
-                               ((u64)devi.devno << 48), 0,
-                               (((u64)myOp) << 32) | mtc.mt_count, 0);
-               if (hvrc != HvLpEvent_Rc_Good) {
-                       printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-                                       (int)hvrc);
-                       goto free_op;
-               }
-               wait_for_completion(&op->com);
-               ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno);
-               goto free_op;
-
-       case MTIOCGET:
-               ret = -EIO;
-               init_completion(&op->com);
-               hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                               HvLpEvent_Type_VirtualIo,
-                               viomajorsubtype_tape | viotapegetstatus,
-                               HvLpEvent_AckInd_DoAck,
-                               HvLpEvent_AckType_ImmediateAck,
-                               viopath_sourceinst(viopath_hostLp),
-                               viopath_targetinst(viopath_hostLp),
-                               (u64)(unsigned long)op, VIOVERSION << 16,
-                               ((u64)devi.devno << 48), 0, 0, 0);
-               if (hvrc != HvLpEvent_Rc_Good) {
-                       printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-                                       (int)hvrc);
-                       goto free_op;
-               }
-               wait_for_completion(&op->com);
-
-               /* Operation is complete - grab the error code */
-               ret = tape_rc_to_errno(op->rc, "get status", devi.devno);
-               free_op_struct(op);
-               up(&reqSem);
-
-               if ((ret == 0) && copy_to_user((void *)arg,
-                                       &viomtget[devi.devno],
-                                       sizeof(viomtget[0])))
-                       ret = -EFAULT;
-               return ret;
-       case MTIOCPOS:
-               printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n");
-               break;
-       default:
-               printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n",
-                               cmd);
-               break;
-       }
-
-free_op:
-       free_op_struct(op);
-       up(&reqSem);
-       return ret;
-}
-
-static long viotap_unlocked_ioctl(struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       long rc;
-
-       mutex_lock(&proc_viotape_mutex);
-       rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-       mutex_unlock(&proc_viotape_mutex);
-       return rc;
-}
-
-static int viotap_open(struct inode *inode, struct file *file)
-{
-       HvLpEvent_Rc hvrc;
-       struct viot_devinfo_struct devi;
-       int ret;
-       struct op_struct *op = get_op_struct();
-
-       if (op == NULL)
-               return -ENOMEM;
-
-       mutex_lock(&proc_viotape_mutex);
-       get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-       /* Note: We currently only support one mode! */
-       if ((devi.devno >= viotape_numdev) || (devi.mode)) {
-               ret = -ENODEV;
-               goto free_op;
-       }
-
-       init_completion(&op->com);
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotapeopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)op, VIOVERSION << 16,
-                       ((u64)devi.devno << 48), 0, 0, 0);
-       if (hvrc != 0) {
-               printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
-                               (int) hvrc);
-               ret = -EIO;
-               goto free_op;
-       }
-
-       wait_for_completion(&op->com);
-       ret = tape_rc_to_errno(op->rc, "open", devi.devno);
-
-free_op:
-       free_op_struct(op);
-       mutex_unlock(&proc_viotape_mutex);
-       return ret;
-}
-
-
-static int viotap_release(struct inode *inode, struct file *file)
-{
-       HvLpEvent_Rc hvrc;
-       struct viot_devinfo_struct devi;
-       int ret = 0;
-       struct op_struct *op = get_op_struct();
-
-       if (op == NULL)
-               return -ENOMEM;
-       init_completion(&op->com);
-
-       get_dev_info(file->f_path.dentry->d_inode, &devi);
-
-       if (devi.devno >= viotape_numdev) {
-               ret = -ENODEV;
-               goto free_op;
-       }
-
-       chg_state(devi.devno, VIOT_IDLE, file);
-
-       if (devi.rewind) {
-               hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                               HvLpEvent_Type_VirtualIo,
-                               viomajorsubtype_tape | viotapeop,
-                               HvLpEvent_AckInd_DoAck,
-                               HvLpEvent_AckType_ImmediateAck,
-                               viopath_sourceinst(viopath_hostLp),
-                               viopath_targetinst(viopath_hostLp),
-                               (u64)(unsigned long)op, VIOVERSION << 16,
-                               ((u64)devi.devno << 48), 0,
-                               ((u64)VIOTAPOP_REW) << 32, 0);
-               wait_for_completion(&op->com);
-
-               tape_rc_to_errno(op->rc, "rewind", devi.devno);
-       }
-
-       hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_tape | viotapeclose,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(viopath_hostLp),
-                       viopath_targetinst(viopath_hostLp),
-                       (u64)(unsigned long)op, VIOVERSION << 16,
-                       ((u64)devi.devno << 48), 0, 0, 0);
-       if (hvrc != 0) {
-               printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
-                               (int) hvrc);
-               ret = -EIO;
-               goto free_op;
-       }
-
-       wait_for_completion(&op->com);
-
-       if (op->rc)
-               printk(VIOTAPE_KERN_WARN "close failed\n");
-
-free_op:
-       free_op_struct(op);
-       return ret;
-}
-
-const struct file_operations viotap_fops = {
-       .owner =                THIS_MODULE,
-       .read =                 viotap_read,
-       .write =                viotap_write,
-       .unlocked_ioctl =       viotap_unlocked_ioctl,
-       .open =                 viotap_open,
-       .release =              viotap_release,
-       .llseek =               noop_llseek,
-};
-
-/* Handle interrupt events for tape */
-static void vioHandleTapeEvent(struct HvLpEvent *event)
-{
-       int tapeminor;
-       struct op_struct *op;
-       struct viotapelpevent *tevent = (struct viotapelpevent *)event;
-
-       if (event == NULL) {
-               /* Notification that a partition went away! */
-               if (!viopath_isactive(viopath_hostLp)) {
-                       /* TODO! Clean up */
-               }
-               return;
-       }
-
-       tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
-       op = (struct op_struct *)event->xCorrelationToken;
-       switch (tapeminor) {
-       case viotapeopen:
-       case viotapeclose:
-               op->rc = tevent->sub_type_result;
-               complete(&op->com);
-               break;
-       case viotaperead:
-               op->rc = tevent->sub_type_result;
-               op->count = tevent->len;
-               complete(&op->com);
-               break;
-       case viotapewrite:
-               if (op->non_blocking) {
-                       dma_free_coherent(op->dev, op->count,
-                                       op->buffer, op->dmaaddr);
-                       free_op_struct(op);
-                       up(&reqSem);
-               } else {
-                       op->rc = tevent->sub_type_result;
-                       op->count = tevent->len;
-                       complete(&op->com);
-               }
-               break;
-       case viotapeop:
-       case viotapegetpos:
-       case viotapesetpos:
-       case viotapegetstatus:
-               if (op) {
-                       op->count = tevent->u.op.count;
-                       op->rc = tevent->sub_type_result;
-                       if (!op->non_blocking)
-                               complete(&op->com);
-               }
-               break;
-       default:
-               printk(VIOTAPE_KERN_WARN "weird ack\n");
-       }
-}
-
-static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
-       int i = vdev->unit_address;
-       int j;
-       struct device_node *node = vdev->dev.of_node;
-
-       if (i >= VIOTAPE_MAX_TAPE)
-               return -ENODEV;
-       if (!node)
-               return -ENODEV;
-
-       if (i >= viotape_numdev)
-               viotape_numdev = i + 1;
-
-       tape_device[i] = &vdev->dev;
-       viotape_unitinfo[i].rsrcname = of_get_property(node,
-                                       "linux,vio_rsrcname", NULL);
-       viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
-                                       NULL);
-       viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
-                                       NULL);
-
-       state[i].cur_part = 0;
-       for (j = 0; j < MAX_PARTITIONS; ++j)
-               state[i].part_stat_rwi[j] = VIOT_IDLE;
-       device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
-                     "iseries!vt%d", i);
-       device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL,
-                     "iseries!nvt%d", i);
-       printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
-                       "resource %10.10s type %4.4s, model %3.3s\n",
-                       i, viotape_unitinfo[i].rsrcname,
-                       viotape_unitinfo[i].type, viotape_unitinfo[i].model);
-       return 0;
-}
-
-static int viotape_remove(struct vio_dev *vdev)
-{
-       int i = vdev->unit_address;
-
-       device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
-       device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
-       return 0;
-}
-
-/**
- * viotape_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viotape_device_table[] __devinitdata = {
-       { "byte", "IBM,iSeries-viotape" },
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viotape_device_table);
-
-static struct vio_driver viotape_driver = {
-       .id_table = viotape_device_table,
-       .probe = viotape_probe,
-       .remove = viotape_remove,
-       .driver = {
-               .name = "viotape",
-               .owner = THIS_MODULE,
-       }
-};
-
-
-int __init viotap_init(void)
-{
-       int ret;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return -ENODEV;
-
-       op_struct_list = NULL;
-       if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {
-               printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");
-               return ret;
-       }
-       spin_lock_init(&op_struct_list_lock);
-
-       sema_init(&reqSem, VIOTAPE_MAXREQ);
-
-       if (viopath_hostLp == HvLpIndexInvalid) {
-               vio_set_hostlp();
-               if (viopath_hostLp == HvLpIndexInvalid) {
-                       ret = -ENODEV;
-                       goto clear_op;
-               }
-       }
-
-       ret = viopath_open(viopath_hostLp, viomajorsubtype_tape,
-                       VIOTAPE_MAXREQ + 2);
-       if (ret) {
-               printk(VIOTAPE_KERN_WARN
-                               "error on viopath_open to hostlp %d\n", ret);
-               ret = -EIO;
-               goto clear_op;
-       }
-
-       printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION
-                       ", hosting partition %d\n", viopath_hostLp);
-
-       vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent);
-
-       ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops);
-       if (ret < 0) {
-               printk(VIOTAPE_KERN_WARN "Error registering viotape device\n");
-               goto clear_handler;
-       }
-
-       tape_class = class_create(THIS_MODULE, "tape");
-       if (IS_ERR(tape_class)) {
-               printk(VIOTAPE_KERN_WARN "Unable to allocate class\n");
-               ret = PTR_ERR(tape_class);
-               goto unreg_chrdev;
-       }
-
-       ret = vio_register_driver(&viotape_driver);
-       if (ret)
-               goto unreg_class;
-
-       proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL,
-                   &proc_viotape_operations);
-
-       return 0;
-
-unreg_class:
-       class_destroy(tape_class);
-unreg_chrdev:
-       unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-clear_handler:
-       vio_clearHandler(viomajorsubtype_tape);
-       viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
-clear_op:
-       clear_op_struct_pool();
-       return ret;
-}
-
-/* Give a new state to the tape object */
-static int chg_state(int index, unsigned char new_state, struct file *file)
-{
-       unsigned char *cur_state =
-           &state[index].part_stat_rwi[state[index].cur_part];
-       int rc = 0;
-
-       /* if the same state, don't bother */
-       if (*cur_state == new_state)
-               return 0;
-
-       /* write an EOF if changing from writing to some other state */
-       if (*cur_state == VIOT_WRITING) {
-               struct mtop write_eof = { MTWEOF, 1 };
-
-               rc = viotap_ioctl(NULL, file, MTIOCTOP,
-                                 (unsigned long)&write_eof);
-       }
-       *cur_state = new_state;
-       return rc;
-}
-
-/* Cleanup */
-static void __exit viotap_exit(void)
-{
-       remove_proc_entry("iSeries/viotape", NULL);
-       vio_unregister_driver(&viotape_driver);
-       class_destroy(tape_class);
-       unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-       viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
-       vio_clearHandler(viomajorsubtype_tape);
-       clear_op_struct_pool();
-}
-
-MODULE_LICENSE("GPL");
-module_init(viotap_init);
-module_exit(viotap_exit);
index 6d16b4b..e707979 100644 (file)
@@ -293,4 +293,15 @@ config CRYPTO_DEV_S5P
          Select this to offload Samsung S5PV210 or S5PC110 from AES
          algorithms execution.
 
+config CRYPTO_DEV_TEGRA_AES
+       tristate "Support for TEGRA AES hw engine"
+       depends on ARCH_TEGRA
+       select CRYPTO_AES
+       help
+         TEGRA processors have AES module accelerator. Select this if you
+         want to use the TEGRA module for AES algorithms.
+
+         To compile this driver as a module, choose M here: the module
+         will be called tegra-aes.
+
 endif # CRYPTO_HW
index 53ea501..f3e64ea 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
 obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
index e73cf2e..534a364 100644 (file)
@@ -1843,6 +1843,25 @@ static struct caam_alg_template driver_algs[] = {
                .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha224),cbc(aes))",
+               .driver_name = "authenc-hmac-sha224-cbc-aes-caam",
+               .blocksize = AES_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = SHA224_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha256),cbc(aes))",
                .driver_name = "authenc-hmac-sha256-cbc-aes-caam",
@@ -1863,6 +1882,26 @@ static struct caam_alg_template driver_algs[] = {
                                   OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha384),cbc(aes))",
+               .driver_name = "authenc-hmac-sha384-cbc-aes-caam",
+               .blocksize = AES_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = SHA384_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC,
+       },
+
        {
                .name = "authenc(hmac(sha512),cbc(aes))",
                .driver_name = "authenc-hmac-sha512-cbc-aes-caam",
@@ -1921,6 +1960,25 @@ static struct caam_alg_template driver_algs[] = {
                .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha224),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-sha224-cbc-des3_ede-caam",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = SHA224_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha256),cbc(des3_ede))",
                .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam",
@@ -1941,6 +1999,25 @@ static struct caam_alg_template driver_algs[] = {
                                   OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha384),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-sha384-cbc-des3_ede-caam",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = SHA384_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha512),cbc(des3_ede))",
                .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam",
@@ -1999,6 +2076,25 @@ static struct caam_alg_template driver_algs[] = {
                .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha224),cbc(des))",
+               .driver_name = "authenc-hmac-sha224-cbc-des-caam",
+               .blocksize = DES_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES_BLOCK_SIZE,
+                       .maxauthsize = SHA224_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha256),cbc(des))",
                .driver_name = "authenc-hmac-sha256-cbc-des-caam",
@@ -2019,6 +2115,25 @@ static struct caam_alg_template driver_algs[] = {
                                   OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(sha384),cbc(des))",
+               .driver_name = "authenc-hmac-sha384-cbc-des-caam",
+               .blocksize = DES_BLOCK_SIZE,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES_BLOCK_SIZE,
+                       .maxauthsize = SHA384_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+                                  OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha512),cbc(des))",
                .driver_name = "authenc-hmac-sha512-cbc-des-caam",
@@ -2205,7 +2320,8 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev,
        alg->cra_blocksize = template->blocksize;
        alg->cra_alignmask = 0;
        alg->cra_ctxsize = sizeof(struct caam_ctx);
-       alg->cra_flags = CRYPTO_ALG_ASYNC | template->type;
+       alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+                        template->type;
        switch (template->type) {
        case CRYPTO_ALG_TYPE_ABLKCIPHER:
                alg->cra_type = &crypto_ablkcipher_type;
@@ -2285,12 +2401,12 @@ static int __init caam_algapi_init(void)
                        dev_warn(ctrldev, "%s alg registration failed\n",
                                t_alg->crypto_alg.cra_driver_name);
                        kfree(t_alg);
-               } else {
+               } else
                        list_add_tail(&t_alg->entry, &priv->alg_list);
-                       dev_info(ctrldev, "%s\n",
-                                t_alg->crypto_alg.cra_driver_name);
-               }
        }
+       if (!list_empty(&priv->alg_list))
+               dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n",
+                        (char *)of_get_property(dev_node, "compatible", NULL));
 
        return err;
 }
index 8ae3ba2..c5f61c5 100644 (file)
@@ -46,7 +46,7 @@ static int caam_remove(struct platform_device *pdev)
 /* Probe routine for CAAM top (controller) level */
 static int caam_probe(struct platform_device *pdev)
 {
-       int d, ring, rspec;
+       int ring, rspec;
        struct device *dev;
        struct device_node *nprop, *np;
        struct caam_ctrl __iomem *ctrl;
index 219d09c..f3e36c8 100644 (file)
@@ -393,7 +393,8 @@ static struct crypto_alg geode_cbc_alg = {
        .cra_driver_name        =       "cbc-aes-geode",
        .cra_priority           =       400,
        .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
-                                                       CRYPTO_ALG_NEED_FALLBACK,
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
+                                               CRYPTO_ALG_NEED_FALLBACK,
        .cra_init                       =       fallback_init_blk,
        .cra_exit                       =       fallback_exit_blk,
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
@@ -479,7 +480,8 @@ static struct crypto_alg geode_ecb_alg = {
        .cra_driver_name        =       "ecb-aes-geode",
        .cra_priority           =       400,
        .cra_flags                      =       CRYPTO_ALG_TYPE_BLKCIPHER |
-                                                       CRYPTO_ALG_NEED_FALLBACK,
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
+                                               CRYPTO_ALG_NEED_FALLBACK,
        .cra_init                       =       fallback_init_blk,
        .cra_exit                       =       fallback_exit_blk,
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
index 76368f9..c9c4bef 100644 (file)
@@ -2494,7 +2494,8 @@ static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
                 t->drv_name, dev->name);
 
        alg->alg.cra_priority = 300;
-       alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+       alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                               CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC;
        alg->alg.cra_blocksize = t->bsize;
        alg->alg.cra_ctxsize = sizeof(struct hifn_context);
        alg->alg.cra_alignmask = 0;
index 4c20c5b..0053d7e 100644 (file)
@@ -265,7 +265,7 @@ static int setup_crypt_desc(void)
        BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64);
        crypt_virt = dma_alloc_coherent(dev,
                        NPE_QLEN * sizeof(struct crypt_ctl),
-                       &crypt_phys, GFP_KERNEL);
+                       &crypt_phys, GFP_ATOMIC);
        if (!crypt_virt)
                return -ENOMEM;
        memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl));
@@ -1449,6 +1449,7 @@ static int __init ixp_module_init(void)
                        /* block ciphers */
                        cra->cra_type = &crypto_ablkcipher_type;
                        cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                        CRYPTO_ALG_KERN_DRIVER_ONLY |
                                         CRYPTO_ALG_ASYNC;
                        if (!cra->cra_ablkcipher.setkey)
                                cra->cra_ablkcipher.setkey = ablk_setkey;
@@ -1461,6 +1462,7 @@ static int __init ixp_module_init(void)
                        /* authenc */
                        cra->cra_type = &crypto_aead_type;
                        cra->cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                        CRYPTO_ALG_KERN_DRIVER_ONLY |
                                         CRYPTO_ALG_ASYNC;
                        cra->cra_aead.setkey = aead_setkey;
                        cra->cra_aead.setauthsize = aead_setauthsize;
index 0d40cf6..e6ecc5f 100644 (file)
@@ -899,7 +899,8 @@ struct crypto_alg mv_aes_alg_ecb = {
        .cra_name               = "ecb(aes)",
        .cra_driver_name        = "mv-ecb-aes",
        .cra_priority   = 300,
-       .cra_flags      = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_flags      = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                         CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
        .cra_blocksize  = 16,
        .cra_ctxsize    = sizeof(struct mv_ctx),
        .cra_alignmask  = 0,
@@ -921,7 +922,8 @@ struct crypto_alg mv_aes_alg_cbc = {
        .cra_name               = "cbc(aes)",
        .cra_driver_name        = "mv-cbc-aes",
        .cra_priority   = 300,
-       .cra_flags      = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_flags      = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                         CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
        .cra_blocksize  = AES_BLOCK_SIZE,
        .cra_ctxsize    = sizeof(struct mv_ctx),
        .cra_alignmask  = 0,
@@ -953,7 +955,8 @@ struct ahash_alg mv_sha1_alg = {
                          .cra_driver_name = "mv-sha1",
                          .cra_priority = 300,
                          .cra_flags =
-                         CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+                         CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+                         CRYPTO_ALG_NEED_FALLBACK,
                          .cra_blocksize = SHA1_BLOCK_SIZE,
                          .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx),
                          .cra_init = mv_cra_hash_sha1_init,
@@ -977,7 +980,8 @@ struct ahash_alg mv_hmac_sha1_alg = {
                          .cra_driver_name = "mv-hmac-sha1",
                          .cra_priority = 300,
                          .cra_flags =
-                         CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+                         CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+                         CRYPTO_ALG_NEED_FALLBACK,
                          .cra_blocksize = SHA1_BLOCK_SIZE,
                          .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx),
                          .cra_init = mv_cra_hash_hmac_sha1_init,
index 8944dab..67b97c5 100644 (file)
@@ -1402,7 +1402,8 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
        snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
        snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name);
        alg->cra_priority = N2_CRA_PRIORITY;
-       alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+       alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                        CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC;
        alg->cra_blocksize = tmpl->block_size;
        p->enc_type = tmpl->enc_type;
        alg->cra_ctxsize = sizeof(struct n2_cipher_context);
@@ -1493,7 +1494,9 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
        snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
        snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name);
        base->cra_priority = N2_CRA_PRIORITY;
-       base->cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK;
+       base->cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                         CRYPTO_ALG_KERN_DRIVER_ONLY |
+                         CRYPTO_ALG_NEED_FALLBACK;
        base->cra_blocksize = tmpl->block_size;
        base->cra_ctxsize = sizeof(struct n2_hash_ctx);
        base->cra_module = THIS_MODULE;
index 5b970d9..63e57b5 100644 (file)
@@ -756,7 +756,9 @@ static struct crypto_alg algs[] = {
        .cra_name               = "ecb(aes)",
        .cra_driver_name        = "ecb-aes-omap",
        .cra_priority           = 100,
-       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                 CRYPTO_ALG_KERN_DRIVER_ONLY |
+                                 CRYPTO_ALG_ASYNC,
        .cra_blocksize          = AES_BLOCK_SIZE,
        .cra_ctxsize            = sizeof(struct omap_aes_ctx),
        .cra_alignmask          = 0,
@@ -776,7 +778,9 @@ static struct crypto_alg algs[] = {
        .cra_name               = "cbc(aes)",
        .cra_driver_name        = "cbc-aes-omap",
        .cra_priority           = 100,
-       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                 CRYPTO_ALG_KERN_DRIVER_ONLY |
+                                 CRYPTO_ALG_ASYNC,
        .cra_blocksize          = AES_BLOCK_SIZE,
        .cra_ctxsize            = sizeof(struct omap_aes_ctx),
        .cra_alignmask          = 0,
index 6399a8f..a3fd6fc 100644 (file)
@@ -953,6 +953,7 @@ static struct ahash_alg algs[] = {
                .cra_driver_name        = "omap-sha1",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
                                                CRYPTO_ALG_ASYNC |
                                                CRYPTO_ALG_NEED_FALLBACK,
                .cra_blocksize          = SHA1_BLOCK_SIZE,
@@ -975,6 +976,7 @@ static struct ahash_alg algs[] = {
                .cra_driver_name        = "omap-md5",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
                                                CRYPTO_ALG_ASYNC |
                                                CRYPTO_ALG_NEED_FALLBACK,
                .cra_blocksize          = SHA1_BLOCK_SIZE,
@@ -998,6 +1000,7 @@ static struct ahash_alg algs[] = {
                .cra_driver_name        = "omap-hmac-sha1",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
                                                CRYPTO_ALG_ASYNC |
                                                CRYPTO_ALG_NEED_FALLBACK,
                .cra_blocksize          = SHA1_BLOCK_SIZE,
@@ -1022,6 +1025,7 @@ static struct ahash_alg algs[] = {
                .cra_driver_name        = "omap-hmac-md5",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_KERN_DRIVER_ONLY |
                                                CRYPTO_ALG_ASYNC |
                                                CRYPTO_ALG_NEED_FALLBACK,
                .cra_blocksize          = SHA1_BLOCK_SIZE,
index 58480d0..410a03c 100644 (file)
@@ -1322,6 +1322,7 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_driver_name = "cbc-aes-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
                        .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                    CRYPTO_ALG_KERN_DRIVER_ONLY |
                                     CRYPTO_ALG_ASYNC |
                                     CRYPTO_ALG_NEED_FALLBACK,
                        .cra_blocksize = AES_BLOCK_SIZE,
@@ -1349,6 +1350,7 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_driver_name = "ecb-aes-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
                        .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                               CRYPTO_ALG_KERN_DRIVER_ONLY |
                                CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
                        .cra_blocksize = AES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
@@ -1373,7 +1375,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "cbc(des)",
                        .cra_driver_name = "cbc-des-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
                        .cra_type = &crypto_ablkcipher_type,
@@ -1398,7 +1402,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "ecb(des)",
                        .cra_driver_name = "ecb-des-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
                        .cra_type = &crypto_ablkcipher_type,
@@ -1422,7 +1428,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "cbc(des3_ede)",
                        .cra_driver_name = "cbc-des3-ede-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
                        .cra_type = &crypto_ablkcipher_type,
@@ -1447,7 +1455,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "ecb(des3_ede)",
                        .cra_driver_name = "ecb-des3-ede-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
                        .cra_type = &crypto_ablkcipher_type,
@@ -1472,7 +1482,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(sha1),cbc(aes))",
                        .cra_driver_name = "authenc-hmac-sha1-cbc-aes-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = AES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1500,7 +1512,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(sha256),cbc(aes))",
                        .cra_driver_name = "authenc-hmac-sha256-cbc-aes-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = AES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1527,7 +1541,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(md5),cbc(aes))",
                        .cra_driver_name = "authenc-hmac-md5-cbc-aes-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = AES_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1554,7 +1570,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(sha1),cbc(des3_ede))",
                        .cra_driver_name = "authenc-hmac-sha1-cbc-3des-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1582,7 +1600,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(sha256),cbc(des3_ede))",
                        .cra_driver_name = "authenc-hmac-sha256-cbc-3des-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1609,7 +1629,9 @@ static struct spacc_alg ipsec_engine_algs[] = {
                        .cra_name = "authenc(hmac(md5),cbc(des3_ede))",
                        .cra_driver_name = "authenc-hmac-md5-cbc-3des-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = DES3_EDE_BLOCK_SIZE,
                        .cra_ctxsize = sizeof(struct spacc_aead_ctx),
                        .cra_type = &crypto_aead_type,
@@ -1639,7 +1661,9 @@ static struct spacc_alg l2_engine_algs[] = {
                        .cra_name = "f8(kasumi)",
                        .cra_driver_name = "f8-kasumi-picoxcell",
                        .cra_priority = SPACC_CRYPTO_ALG_PRIORITY,
-                       .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_ASYNC,
+                       .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER |
+                                       CRYPTO_ALG_ASYNC |
+                                       CRYPTO_ALG_KERN_DRIVER_ONLY,
                        .cra_blocksize = 8,
                        .cra_ctxsize = sizeof(struct spacc_ablk_ctx),
                        .cra_type = &crypto_ablkcipher_type,
index 3376bca..bc986f8 100644 (file)
@@ -518,7 +518,8 @@ static struct crypto_alg algs[] = {
                .cra_driver_name        = "ecb-aes-s5p",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER |
-                                         CRYPTO_ALG_ASYNC,
+                                         CRYPTO_ALG_ASYNC |
+                                         CRYPTO_ALG_KERN_DRIVER_ONLY,
                .cra_blocksize          = AES_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct s5p_aes_ctx),
                .cra_alignmask          = 0x0f,
@@ -538,7 +539,8 @@ static struct crypto_alg algs[] = {
                .cra_driver_name        = "cbc-aes-s5p",
                .cra_priority           = 100,
                .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER |
-                                         CRYPTO_ALG_ASYNC,
+                                         CRYPTO_ALG_ASYNC |
+                                         CRYPTO_ALG_KERN_DRIVER_ONLY,
                .cra_blocksize          = AES_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct s5p_aes_ctx),
                .cra_alignmask          = 0x0f,
index 2d8c789..dc641c7 100644 (file)
@@ -2648,6 +2648,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
        alg->cra_priority = TALITOS_CRA_PRIORITY;
        alg->cra_alignmask = 0;
        alg->cra_ctxsize = sizeof(struct talitos_ctx);
+       alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
 
        t_alg->dev = dev;
 
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
new file mode 100644 (file)
index 0000000..422a976
--- /dev/null
@@ -0,0 +1,1096 @@
+/*
+ * drivers/crypto/tegra-aes.c
+ *
+ * Driver for NVIDIA Tegra AES hardware engine residing inside the
+ * Bit Stream Engine for Video (BSEV) hardware block.
+ *
+ * The programming sequence for this engine is with the help
+ * of commands which travel via a command queue residing between the
+ * CPU and the BSEV block. The BSEV engine has an internal RAM (VRAM)
+ * where the final input plaintext, keys and the IV have to be copied
+ * before starting the encrypt/decrypt operation.
+ *
+ * Copyright (c) 2010, NVIDIA 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+
+#include <mach/clk.h>
+
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+#include <crypto/internal/rng.h>
+
+#include "tegra-aes.h"
+
+#define FLAGS_MODE_MASK                        0x00FF
+#define FLAGS_ENCRYPT                  BIT(0)
+#define FLAGS_CBC                      BIT(1)
+#define FLAGS_GIV                      BIT(2)
+#define FLAGS_RNG                      BIT(3)
+#define FLAGS_OFB                      BIT(4)
+#define FLAGS_NEW_KEY                  BIT(5)
+#define FLAGS_NEW_IV                   BIT(6)
+#define FLAGS_INIT                     BIT(7)
+#define FLAGS_FAST                     BIT(8)
+#define FLAGS_BUSY                     9
+
+/*
+ * Defines AES engine Max process bytes size in one go, which takes 1 msec.
+ * AES engine spends about 176 cycles/16-bytes or 11 cycles/byte
+ * The duration CPU can use the BSE to 1 msec, then the number of available
+ * cycles of AVP/BSE is 216K. In this duration, AES can process 216/11 ~= 19KB
+ * Based on this AES_HW_DMA_BUFFER_SIZE_BYTES is configured to 16KB.
+ */
+#define AES_HW_DMA_BUFFER_SIZE_BYTES 0x4000
+
+/*
+ * The key table length is 64 bytes
+ * (This includes first upto 32 bytes key + 16 bytes original initial vector
+ * and 16 bytes updated initial vector)
+ */
+#define AES_HW_KEY_TABLE_LENGTH_BYTES 64
+
+/*
+ * The memory being used is divides as follows:
+ * 1. Key - 32 bytes
+ * 2. Original IV - 16 bytes
+ * 3. Updated IV - 16 bytes
+ * 4. Key schedule - 256 bytes
+ *
+ * 1+2+3 constitute the hw key table.
+ */
+#define AES_HW_IV_SIZE 16
+#define AES_HW_KEYSCHEDULE_LEN 256
+#define AES_IVKEY_SIZE (AES_HW_KEY_TABLE_LENGTH_BYTES + AES_HW_KEYSCHEDULE_LEN)
+
+/* Define commands required for AES operation */
+enum {
+       CMD_BLKSTARTENGINE = 0x0E,
+       CMD_DMASETUP = 0x10,
+       CMD_DMACOMPLETE = 0x11,
+       CMD_SETTABLE = 0x15,
+       CMD_MEMDMAVD = 0x22,
+};
+
+/* Define sub-commands */
+enum {
+       SUBCMD_VRAM_SEL = 0x1,
+       SUBCMD_CRYPTO_TABLE_SEL = 0x3,
+       SUBCMD_KEY_TABLE_SEL = 0x8,
+};
+
+/* memdma_vd command */
+#define MEMDMA_DIR_DTOVRAM             0 /* sdram -> vram */
+#define MEMDMA_DIR_VTODRAM             1 /* vram -> sdram */
+#define MEMDMA_DIR_SHIFT               25
+#define MEMDMA_NUM_WORDS_SHIFT         12
+
+/* command queue bit shifts */
+enum {
+       CMDQ_KEYTABLEADDR_SHIFT = 0,
+       CMDQ_KEYTABLEID_SHIFT = 17,
+       CMDQ_VRAMSEL_SHIFT = 23,
+       CMDQ_TABLESEL_SHIFT = 24,
+       CMDQ_OPCODE_SHIFT = 26,
+};
+
+/*
+ * The secure key slot contains a unique secure key generated
+ * and loaded by the bootloader. This slot is marked as non-accessible
+ * to the kernel.
+ */
+#define SSK_SLOT_NUM           4
+
+#define AES_NR_KEYSLOTS                8
+#define TEGRA_AES_QUEUE_LENGTH 50
+#define DEFAULT_RNG_BLK_SZ     16
+
+/* The command queue depth */
+#define AES_HW_MAX_ICQ_LENGTH  5
+
+struct tegra_aes_slot {
+       struct list_head node;
+       int slot_num;
+};
+
+static struct tegra_aes_slot ssk = {
+       .slot_num = SSK_SLOT_NUM,
+};
+
+struct tegra_aes_reqctx {
+       unsigned long mode;
+};
+
+struct tegra_aes_dev {
+       struct device *dev;
+       void __iomem *io_base;
+       dma_addr_t ivkey_phys_base;
+       void __iomem *ivkey_base;
+       struct clk *aes_clk;
+       struct tegra_aes_ctx *ctx;
+       int irq;
+       unsigned long flags;
+       struct completion op_complete;
+       u32 *buf_in;
+       dma_addr_t dma_buf_in;
+       u32 *buf_out;
+       dma_addr_t dma_buf_out;
+       u8 *iv;
+       u8 dt[DEFAULT_RNG_BLK_SZ];
+       int ivlen;
+       u64 ctr;
+       spinlock_t lock;
+       struct crypto_queue queue;
+       struct tegra_aes_slot *slots;
+       struct ablkcipher_request *req;
+       size_t total;
+       struct scatterlist *in_sg;
+       size_t in_offset;
+       struct scatterlist *out_sg;
+       size_t out_offset;
+};
+
+static struct tegra_aes_dev *aes_dev;
+
+struct tegra_aes_ctx {
+       struct tegra_aes_dev *dd;
+       unsigned long flags;
+       struct tegra_aes_slot *slot;
+       u8 key[AES_MAX_KEY_SIZE];
+       size_t keylen;
+};
+
+static struct tegra_aes_ctx rng_ctx = {
+       .flags = FLAGS_NEW_KEY,
+       .keylen = AES_KEYSIZE_128,
+};
+
+/* keep registered devices data here */
+static struct list_head dev_list;
+static DEFINE_SPINLOCK(list_lock);
+static DEFINE_MUTEX(aes_lock);
+
+static void aes_workqueue_handler(struct work_struct *work);
+static DECLARE_WORK(aes_work, aes_workqueue_handler);
+static struct workqueue_struct *aes_wq;
+
+extern unsigned long long tegra_chip_uid(void);
+
+static inline u32 aes_readl(struct tegra_aes_dev *dd, u32 offset)
+{
+       return readl(dd->io_base + offset);
+}
+
+static inline void aes_writel(struct tegra_aes_dev *dd, u32 val, u32 offset)
+{
+       writel(val, dd->io_base + offset);
+}
+
+static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
+       int nblocks, int mode, bool upd_iv)
+{
+       u32 cmdq[AES_HW_MAX_ICQ_LENGTH];
+       int i, eng_busy, icq_empty, ret;
+       u32 value;
+
+       /* reset all the interrupt bits */
+       aes_writel(dd, 0xFFFFFFFF, TEGRA_AES_INTR_STATUS);
+
+       /* enable error, dma xfer complete interrupts */
+       aes_writel(dd, 0x33, TEGRA_AES_INT_ENB);
+
+       cmdq[0] = CMD_DMASETUP << CMDQ_OPCODE_SHIFT;
+       cmdq[1] = in_addr;
+       cmdq[2] = CMD_BLKSTARTENGINE << CMDQ_OPCODE_SHIFT | (nblocks-1);
+       cmdq[3] = CMD_DMACOMPLETE << CMDQ_OPCODE_SHIFT;
+
+       value = aes_readl(dd, TEGRA_AES_CMDQUE_CONTROL);
+       /* access SDRAM through AHB */
+       value &= ~TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD;
+       value &= ~TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD;
+       value |= TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD |
+                TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD |
+                TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD;
+       aes_writel(dd, value, TEGRA_AES_CMDQUE_CONTROL);
+       dev_dbg(dd->dev, "cmd_q_ctrl=0x%x", value);
+
+       value = (0x1 << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) |
+               ((dd->ctx->keylen * 8) <<
+                       TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) |
+               ((u32)upd_iv << TEGRA_AES_SECURE_IV_SELECT_SHIFT);
+
+       if (mode & FLAGS_CBC) {
+               value |= ((((mode & FLAGS_ENCRYPT) ? 2 : 3)
+                               << TEGRA_AES_SECURE_XOR_POS_SHIFT) |
+                       (((mode & FLAGS_ENCRYPT) ? 2 : 3)
+                               << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) |
+                       ((mode & FLAGS_ENCRYPT) ? 1 : 0)
+                               << TEGRA_AES_SECURE_CORE_SEL_SHIFT);
+       } else if (mode & FLAGS_OFB) {
+               value |= ((TEGRA_AES_SECURE_XOR_POS_FIELD) |
+                       (2 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) |
+                       (TEGRA_AES_SECURE_CORE_SEL_FIELD));
+       } else if (mode & FLAGS_RNG) {
+               value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0)
+                               << TEGRA_AES_SECURE_CORE_SEL_SHIFT |
+                         TEGRA_AES_SECURE_RNG_ENB_FIELD);
+       } else {
+               value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0)
+                               << TEGRA_AES_SECURE_CORE_SEL_SHIFT);
+       }
+
+       dev_dbg(dd->dev, "secure_in_sel=0x%x", value);
+       aes_writel(dd, value, TEGRA_AES_SECURE_INPUT_SELECT);
+
+       aes_writel(dd, out_addr, TEGRA_AES_SECURE_DEST_ADDR);
+       INIT_COMPLETION(dd->op_complete);
+
+       for (i = 0; i < AES_HW_MAX_ICQ_LENGTH - 1; i++) {
+               do {
+                       value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
+                       eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
+                       icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
+               } while (eng_busy & (!icq_empty));
+               aes_writel(dd, cmdq[i], TEGRA_AES_ICMDQUE_WR);
+       }
+
+       ret = wait_for_completion_timeout(&dd->op_complete,
+                                         msecs_to_jiffies(150));
+       if (ret == 0) {
+               dev_err(dd->dev, "timed out (0x%x)\n",
+                       aes_readl(dd, TEGRA_AES_INTR_STATUS));
+               return -ETIMEDOUT;
+       }
+
+       aes_writel(dd, cmdq[AES_HW_MAX_ICQ_LENGTH - 1], TEGRA_AES_ICMDQUE_WR);
+       return 0;
+}
+
+static void aes_release_key_slot(struct tegra_aes_slot *slot)
+{
+       if (slot->slot_num == SSK_SLOT_NUM)
+               return;
+
+       spin_lock(&list_lock);
+       list_add_tail(&slot->node, &dev_list);
+       slot = NULL;
+       spin_unlock(&list_lock);
+}
+
+static struct tegra_aes_slot *aes_find_key_slot(void)
+{
+       struct tegra_aes_slot *slot = NULL;
+       struct list_head *new_head;
+       int empty;
+
+       spin_lock(&list_lock);
+       empty = list_empty(&dev_list);
+       if (!empty) {
+               slot = list_entry(&dev_list, struct tegra_aes_slot, node);
+               new_head = dev_list.next;
+               list_del(&dev_list);
+               dev_list.next = new_head->next;
+               dev_list.prev = NULL;
+       }
+       spin_unlock(&list_lock);
+
+       return slot;
+}
+
+static int aes_set_key(struct tegra_aes_dev *dd)
+{
+       u32 value, cmdq[2];
+       struct tegra_aes_ctx *ctx = dd->ctx;
+       int eng_busy, icq_empty, dma_busy;
+       bool use_ssk = false;
+
+       /* use ssk? */
+       if (!dd->ctx->slot) {
+               dev_dbg(dd->dev, "using ssk");
+               dd->ctx->slot = &ssk;
+               use_ssk = true;
+       }
+
+       /* enable key schedule generation in hardware */
+       value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG_EXT);
+       value &= ~TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD;
+       aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG_EXT);
+
+       /* select the key slot */
+       value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG);
+       value &= ~TEGRA_AES_SECURE_KEY_INDEX_FIELD;
+       value |= (ctx->slot->slot_num << TEGRA_AES_SECURE_KEY_INDEX_SHIFT);
+       aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG);
+
+       if (use_ssk)
+               return 0;
+
+       /* copy the key table from sdram to vram */
+       cmdq[0] = CMD_MEMDMAVD << CMDQ_OPCODE_SHIFT |
+               MEMDMA_DIR_DTOVRAM << MEMDMA_DIR_SHIFT |
+               AES_HW_KEY_TABLE_LENGTH_BYTES / sizeof(u32) <<
+                       MEMDMA_NUM_WORDS_SHIFT;
+       cmdq[1] = (u32)dd->ivkey_phys_base;
+
+       aes_writel(dd, cmdq[0], TEGRA_AES_ICMDQUE_WR);
+       aes_writel(dd, cmdq[1], TEGRA_AES_ICMDQUE_WR);
+
+       do {
+               value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
+               eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
+               icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
+               dma_busy = value & TEGRA_AES_DMA_BUSY_FIELD;
+       } while (eng_busy & (!icq_empty) & dma_busy);
+
+       /* settable command to get key into internal registers */
+       value = CMD_SETTABLE << CMDQ_OPCODE_SHIFT |
+               SUBCMD_CRYPTO_TABLE_SEL << CMDQ_TABLESEL_SHIFT |
+               SUBCMD_VRAM_SEL << CMDQ_VRAMSEL_SHIFT |
+               (SUBCMD_KEY_TABLE_SEL | ctx->slot->slot_num) <<
+                       CMDQ_KEYTABLEID_SHIFT;
+       aes_writel(dd, value, TEGRA_AES_ICMDQUE_WR);
+
+       do {
+               value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
+               eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
+               icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD;
+       } while (eng_busy & (!icq_empty));
+
+       return 0;
+}
+
+static int tegra_aes_handle_req(struct tegra_aes_dev *dd)
+{
+       struct crypto_async_request *async_req, *backlog;
+       struct crypto_ablkcipher *tfm;
+       struct tegra_aes_ctx *ctx;
+       struct tegra_aes_reqctx *rctx;
+       struct ablkcipher_request *req;
+       unsigned long flags;
+       int dma_max = AES_HW_DMA_BUFFER_SIZE_BYTES;
+       int ret = 0, nblocks, total;
+       int count = 0;
+       dma_addr_t addr_in, addr_out;
+       struct scatterlist *in_sg, *out_sg;
+
+       if (!dd)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dd->lock, flags);
+       backlog = crypto_get_backlog(&dd->queue);
+       async_req = crypto_dequeue_request(&dd->queue);
+       if (!async_req)
+               clear_bit(FLAGS_BUSY, &dd->flags);
+       spin_unlock_irqrestore(&dd->lock, flags);
+
+       if (!async_req)
+               return -ENODATA;
+
+       if (backlog)
+               backlog->complete(backlog, -EINPROGRESS);
+
+       req = ablkcipher_request_cast(async_req);
+
+       dev_dbg(dd->dev, "%s: get new req\n", __func__);
+
+       if (!req->src || !req->dst)
+               return -EINVAL;
+
+       /* take mutex to access the aes hw */
+       mutex_lock(&aes_lock);
+
+       /* assign new request to device */
+       dd->req = req;
+       dd->total = req->nbytes;
+       dd->in_offset = 0;
+       dd->in_sg = req->src;
+       dd->out_offset = 0;
+       dd->out_sg = req->dst;
+
+       in_sg = dd->in_sg;
+       out_sg = dd->out_sg;
+
+       total = dd->total;
+
+       tfm = crypto_ablkcipher_reqtfm(req);
+       rctx = ablkcipher_request_ctx(req);
+       ctx = crypto_ablkcipher_ctx(tfm);
+       rctx->mode &= FLAGS_MODE_MASK;
+       dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+       dd->iv = (u8 *)req->info;
+       dd->ivlen = crypto_ablkcipher_ivsize(tfm);
+
+       /* assign new context to device */
+       ctx->dd = dd;
+       dd->ctx = ctx;
+
+       if (ctx->flags & FLAGS_NEW_KEY) {
+               /* copy the key */
+               memcpy(dd->ivkey_base, ctx->key, ctx->keylen);
+               memset(dd->ivkey_base + ctx->keylen, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - ctx->keylen);
+               aes_set_key(dd);
+               ctx->flags &= ~FLAGS_NEW_KEY;
+       }
+
+       if (((dd->flags & FLAGS_CBC) || (dd->flags & FLAGS_OFB)) && dd->iv) {
+               /* set iv to the aes hw slot
+                * Hw generates updated iv only after iv is set in slot.
+                * So key and iv is passed asynchronously.
+                */
+               memcpy(dd->buf_in, dd->iv, dd->ivlen);
+
+               ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
+                                     dd->dma_buf_out, 1, FLAGS_CBC, false);
+               if (ret < 0) {
+                       dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
+                       goto out;
+               }
+       }
+
+       while (total) {
+               dev_dbg(dd->dev, "remain: %d\n", total);
+               ret = dma_map_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE);
+               if (!ret) {
+                       dev_err(dd->dev, "dma_map_sg() error\n");
+                       goto out;
+               }
+
+               ret = dma_map_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE);
+               if (!ret) {
+                       dev_err(dd->dev, "dma_map_sg() error\n");
+                       dma_unmap_sg(dd->dev, dd->in_sg,
+                               1, DMA_TO_DEVICE);
+                       goto out;
+               }
+
+               addr_in = sg_dma_address(in_sg);
+               addr_out = sg_dma_address(out_sg);
+               dd->flags |= FLAGS_FAST;
+               count = min_t(int, sg_dma_len(in_sg), dma_max);
+               WARN_ON(sg_dma_len(in_sg) != sg_dma_len(out_sg));
+               nblocks = DIV_ROUND_UP(count, AES_BLOCK_SIZE);
+
+               ret = aes_start_crypt(dd, addr_in, addr_out, nblocks,
+                       dd->flags, true);
+
+               dma_unmap_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE);
+               dma_unmap_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE);
+
+               if (ret < 0) {
+                       dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
+                       goto out;
+               }
+               dd->flags &= ~FLAGS_FAST;
+
+               dev_dbg(dd->dev, "out: copied %d\n", count);
+               total -= count;
+               in_sg = sg_next(in_sg);
+               out_sg = sg_next(out_sg);
+               WARN_ON(((total != 0) && (!in_sg || !out_sg)));
+       }
+
+out:
+       mutex_unlock(&aes_lock);
+
+       dd->total = total;
+
+       if (dd->req->base.complete)
+               dd->req->base.complete(&dd->req->base, ret);
+
+       dev_dbg(dd->dev, "%s: exit\n", __func__);
+       return ret;
+}
+
+static int tegra_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+                           unsigned int keylen)
+{
+       struct tegra_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       struct tegra_aes_dev *dd = aes_dev;
+       struct tegra_aes_slot *key_slot;
+
+       if ((keylen != AES_KEYSIZE_128) && (keylen != AES_KEYSIZE_192) &&
+               (keylen != AES_KEYSIZE_256)) {
+               dev_err(dd->dev, "unsupported key size\n");
+               crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+
+       dev_dbg(dd->dev, "keylen: %d\n", keylen);
+
+       ctx->dd = dd;
+
+       if (key) {
+               if (!ctx->slot) {
+                       key_slot = aes_find_key_slot();
+                       if (!key_slot) {
+                               dev_err(dd->dev, "no empty slot\n");
+                               return -ENOMEM;
+                       }
+
+                       ctx->slot = key_slot;
+               }
+
+               memcpy(ctx->key, key, keylen);
+               ctx->keylen = keylen;
+       }
+
+       ctx->flags |= FLAGS_NEW_KEY;
+       dev_dbg(dd->dev, "done\n");
+       return 0;
+}
+
+static void aes_workqueue_handler(struct work_struct *work)
+{
+       struct tegra_aes_dev *dd = aes_dev;
+       int ret;
+
+       ret = clk_enable(dd->aes_clk);
+       if (ret)
+               BUG_ON("clock enable failed");
+
+       /* empty the crypto queue and then return */
+       do {
+               ret = tegra_aes_handle_req(dd);
+       } while (!ret);
+
+       clk_disable(dd->aes_clk);
+}
+
+static irqreturn_t aes_irq(int irq, void *dev_id)
+{
+       struct tegra_aes_dev *dd = (struct tegra_aes_dev *)dev_id;
+       u32 value = aes_readl(dd, TEGRA_AES_INTR_STATUS);
+       int busy = test_bit(FLAGS_BUSY, &dd->flags);
+
+       if (!busy) {
+               dev_dbg(dd->dev, "spurious interrupt\n");
+               return IRQ_NONE;
+       }
+
+       dev_dbg(dd->dev, "irq_stat: 0x%x\n", value);
+       if (value & TEGRA_AES_INT_ERROR_MASK)
+               aes_writel(dd, TEGRA_AES_INT_ERROR_MASK, TEGRA_AES_INTR_STATUS);
+
+       if (!(value & TEGRA_AES_ENGINE_BUSY_FIELD))
+               complete(&dd->op_complete);
+       else
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+
+static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+       struct tegra_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+       struct tegra_aes_dev *dd = aes_dev;
+       unsigned long flags;
+       int err = 0;
+       int busy;
+
+       dev_dbg(dd->dev, "nbytes: %d, enc: %d, cbc: %d, ofb: %d\n",
+               req->nbytes, !!(mode & FLAGS_ENCRYPT),
+               !!(mode & FLAGS_CBC), !!(mode & FLAGS_OFB));
+
+       rctx->mode = mode;
+
+       spin_lock_irqsave(&dd->lock, flags);
+       err = ablkcipher_enqueue_request(&dd->queue, req);
+       busy = test_and_set_bit(FLAGS_BUSY, &dd->flags);
+       spin_unlock_irqrestore(&dd->lock, flags);
+
+       if (!busy)
+               queue_work(aes_wq, &aes_work);
+
+       return err;
+}
+
+static int tegra_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int tegra_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, 0);
+}
+
+static int tegra_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int tegra_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, FLAGS_CBC);
+}
+
+static int tegra_aes_ofb_encrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_OFB);
+}
+
+static int tegra_aes_ofb_decrypt(struct ablkcipher_request *req)
+{
+       return tegra_aes_crypt(req, FLAGS_OFB);
+}
+
+static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
+                               unsigned int dlen)
+{
+       struct tegra_aes_dev *dd = aes_dev;
+       struct tegra_aes_ctx *ctx = &rng_ctx;
+       int ret, i;
+       u8 *dest = rdata, *dt = dd->dt;
+
+       /* take mutex to access the aes hw */
+       mutex_lock(&aes_lock);
+
+       ret = clk_enable(dd->aes_clk);
+       if (ret)
+               return ret;
+
+       ctx->dd = dd;
+       dd->ctx = ctx;
+       dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
+
+       memcpy(dd->buf_in, dt, DEFAULT_RNG_BLK_SZ);
+
+       ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
+                             (u32)dd->dma_buf_out, 1, dd->flags, true);
+       if (ret < 0) {
+               dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
+               dlen = ret;
+               goto out;
+       }
+       memcpy(dest, dd->buf_out, dlen);
+
+       /* update the DT */
+       for (i = DEFAULT_RNG_BLK_SZ - 1; i >= 0; i--) {
+               dt[i] += 1;
+               if (dt[i] != 0)
+                       break;
+       }
+
+out:
+       clk_disable(dd->aes_clk);
+       mutex_unlock(&aes_lock);
+
+       dev_dbg(dd->dev, "%s: done\n", __func__);
+       return dlen;
+}
+
+static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
+                              unsigned int slen)
+{
+       struct tegra_aes_dev *dd = aes_dev;
+       struct tegra_aes_ctx *ctx = &rng_ctx;
+       struct tegra_aes_slot *key_slot;
+       struct timespec ts;
+       int ret = 0;
+       u64 nsec, tmp[2];
+       u8 *dt;
+
+       if (!ctx || !dd) {
+               dev_err(dd->dev, "ctx=0x%x, dd=0x%x\n",
+                       (unsigned int)ctx, (unsigned int)dd);
+               return -EINVAL;
+       }
+
+       if (slen < (DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) {
+               dev_err(dd->dev, "seed size invalid");
+               return -ENOMEM;
+       }
+
+       /* take mutex to access the aes hw */
+       mutex_lock(&aes_lock);
+
+       if (!ctx->slot) {
+               key_slot = aes_find_key_slot();
+               if (!key_slot) {
+                       dev_err(dd->dev, "no empty slot\n");
+                       mutex_unlock(&aes_lock);
+                       return -ENOMEM;
+               }
+               ctx->slot = key_slot;
+       }
+
+       ctx->dd = dd;
+       dd->ctx = ctx;
+       dd->ctr = 0;
+
+       ctx->keylen = AES_KEYSIZE_128;
+       ctx->flags |= FLAGS_NEW_KEY;
+
+       /* copy the key to the key slot */
+       memcpy(dd->ivkey_base, seed + DEFAULT_RNG_BLK_SZ, AES_KEYSIZE_128);
+       memset(dd->ivkey_base + AES_KEYSIZE_128, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - AES_KEYSIZE_128);
+
+       dd->iv = seed;
+       dd->ivlen = slen;
+
+       dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
+
+       ret = clk_enable(dd->aes_clk);
+       if (ret)
+               return ret;
+
+       aes_set_key(dd);
+
+       /* set seed to the aes hw slot */
+       memcpy(dd->buf_in, dd->iv, DEFAULT_RNG_BLK_SZ);
+       ret = aes_start_crypt(dd, (u32)dd->dma_buf_in,
+                             dd->dma_buf_out, 1, FLAGS_CBC, false);
+       if (ret < 0) {
+               dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret);
+               goto out;
+       }
+
+       if (dd->ivlen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) {
+               dt = dd->iv + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128;
+       } else {
+               getnstimeofday(&ts);
+               nsec = timespec_to_ns(&ts);
+               do_div(nsec, 1000);
+               nsec ^= dd->ctr << 56;
+               dd->ctr++;
+               tmp[0] = nsec;
+               tmp[1] = tegra_chip_uid();
+               dt = (u8 *)tmp;
+       }
+       memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ);
+
+out:
+       clk_disable(dd->aes_clk);
+       mutex_unlock(&aes_lock);
+
+       dev_dbg(dd->dev, "%s: done\n", __func__);
+       return ret;
+}
+
+static int tegra_aes_cra_init(struct crypto_tfm *tfm)
+{
+       tfm->crt_ablkcipher.reqsize = sizeof(struct tegra_aes_reqctx);
+
+       return 0;
+}
+
+void tegra_aes_cra_exit(struct crypto_tfm *tfm)
+{
+       struct tegra_aes_ctx *ctx =
+               crypto_ablkcipher_ctx((struct crypto_ablkcipher *)tfm);
+
+       if (ctx && ctx->slot)
+               aes_release_key_slot(ctx->slot);
+}
+
+static struct crypto_alg algs[] = {
+       {
+               .cra_name = "ecb(aes)",
+               .cra_driver_name = "ecb-aes-tegra",
+               .cra_priority = 300,
+               .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+               .cra_blocksize = AES_BLOCK_SIZE,
+               .cra_alignmask = 3,
+               .cra_type = &crypto_ablkcipher_type,
+               .cra_u.ablkcipher = {
+                       .min_keysize = AES_MIN_KEY_SIZE,
+                       .max_keysize = AES_MAX_KEY_SIZE,
+                       .setkey = tegra_aes_setkey,
+                       .encrypt = tegra_aes_ecb_encrypt,
+                       .decrypt = tegra_aes_ecb_decrypt,
+               },
+       }, {
+               .cra_name = "cbc(aes)",
+               .cra_driver_name = "cbc-aes-tegra",
+               .cra_priority = 300,
+               .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+               .cra_blocksize = AES_BLOCK_SIZE,
+               .cra_alignmask = 3,
+               .cra_type = &crypto_ablkcipher_type,
+               .cra_u.ablkcipher = {
+                       .min_keysize = AES_MIN_KEY_SIZE,
+                       .max_keysize = AES_MAX_KEY_SIZE,
+                       .ivsize = AES_MIN_KEY_SIZE,
+                       .setkey = tegra_aes_setkey,
+                       .encrypt = tegra_aes_cbc_encrypt,
+                       .decrypt = tegra_aes_cbc_decrypt,
+               }
+       }, {
+               .cra_name = "ofb(aes)",
+               .cra_driver_name = "ofb-aes-tegra",
+               .cra_priority = 300,
+               .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+               .cra_blocksize = AES_BLOCK_SIZE,
+               .cra_alignmask = 3,
+               .cra_type = &crypto_ablkcipher_type,
+               .cra_u.ablkcipher = {
+                       .min_keysize = AES_MIN_KEY_SIZE,
+                       .max_keysize = AES_MAX_KEY_SIZE,
+                       .ivsize = AES_MIN_KEY_SIZE,
+                       .setkey = tegra_aes_setkey,
+                       .encrypt = tegra_aes_ofb_encrypt,
+                       .decrypt = tegra_aes_ofb_decrypt,
+               }
+       }, {
+               .cra_name = "ansi_cprng",
+               .cra_driver_name = "rng-aes-tegra",
+               .cra_flags = CRYPTO_ALG_TYPE_RNG,
+               .cra_ctxsize = sizeof(struct tegra_aes_ctx),
+               .cra_type = &crypto_rng_type,
+               .cra_u.rng = {
+                       .rng_make_random = tegra_aes_get_random,
+                       .rng_reset = tegra_aes_rng_reset,
+                       .seedsize = AES_KEYSIZE_128 + (2 * DEFAULT_RNG_BLK_SZ),
+               }
+       }
+};
+
+static int tegra_aes_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra_aes_dev *dd;
+       struct resource *res;
+       int err = -ENOMEM, i = 0, j;
+
+       dd = devm_kzalloc(dev, sizeof(struct tegra_aes_dev), GFP_KERNEL);
+       if (dd == NULL) {
+               dev_err(dev, "unable to alloc data struct.\n");
+               return err;
+       }
+
+       dd->dev = dev;
+       platform_set_drvdata(pdev, dd);
+
+       dd->slots = devm_kzalloc(dev, sizeof(struct tegra_aes_slot) *
+                                AES_NR_KEYSLOTS, GFP_KERNEL);
+       if (dd->slots == NULL) {
+               dev_err(dev, "unable to alloc slot struct.\n");
+               goto out;
+       }
+
+       spin_lock_init(&dd->lock);
+       crypto_init_queue(&dd->queue, TEGRA_AES_QUEUE_LENGTH);
+
+       /* Get the module base address */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "invalid resource type: base\n");
+               err = -ENODEV;
+               goto out;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res),
+                                    dev_name(&pdev->dev))) {
+               dev_err(&pdev->dev, "Couldn't request MEM resource\n");
+               return -ENODEV;
+       }
+
+       dd->io_base = devm_ioremap(dev, res->start, resource_size(res));
+       if (!dd->io_base) {
+               dev_err(dev, "can't ioremap register space\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Initialize the vde clock */
+       dd->aes_clk = clk_get(dev, "vde");
+       if (IS_ERR(dd->aes_clk)) {
+               dev_err(dev, "iclock intialization failed.\n");
+               err = -ENODEV;
+               goto out;
+       }
+
+       err = clk_set_rate(dd->aes_clk, ULONG_MAX);
+       if (err) {
+               dev_err(dd->dev, "iclk set_rate fail(%d)\n", err);
+               goto out;
+       }
+
+       /*
+        * the foll contiguous memory is allocated as follows -
+        * - hardware key table
+        * - key schedule
+        */
+       dd->ivkey_base = dma_alloc_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
+                                           &dd->ivkey_phys_base,
+               GFP_KERNEL);
+       if (!dd->ivkey_base) {
+               dev_err(dev, "can not allocate iv/key buffer\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       dd->buf_in = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                                       &dd->dma_buf_in, GFP_KERNEL);
+       if (!dd->buf_in) {
+               dev_err(dev, "can not allocate dma-in buffer\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       dd->buf_out = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                                        &dd->dma_buf_out, GFP_KERNEL);
+       if (!dd->buf_out) {
+               dev_err(dev, "can not allocate dma-out buffer\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       init_completion(&dd->op_complete);
+       aes_wq = alloc_workqueue("tegra_aes_wq", WQ_HIGHPRI | WQ_UNBOUND, 1);
+       if (!aes_wq) {
+               dev_err(dev, "alloc_workqueue failed\n");
+               goto out;
+       }
+
+       /* get the irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev, "invalid resource type: base\n");
+               err = -ENODEV;
+               goto out;
+       }
+       dd->irq = res->start;
+
+       err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |
+                               IRQF_SHARED, "tegra-aes", dd);
+       if (err) {
+               dev_err(dev, "request_irq failed\n");
+               goto out;
+       }
+
+       mutex_init(&aes_lock);
+       INIT_LIST_HEAD(&dev_list);
+
+       spin_lock_init(&list_lock);
+       spin_lock(&list_lock);
+       for (i = 0; i < AES_NR_KEYSLOTS; i++) {
+               if (i == SSK_SLOT_NUM)
+                       continue;
+               dd->slots[i].slot_num = i;
+               INIT_LIST_HEAD(&dd->slots[i].node);
+               list_add_tail(&dd->slots[i].node, &dev_list);
+       }
+       spin_unlock(&list_lock);
+
+       aes_dev = dd;
+       for (i = 0; i < ARRAY_SIZE(algs); i++) {
+               INIT_LIST_HEAD(&algs[i].cra_list);
+
+               algs[i].cra_priority = 300;
+               algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx);
+               algs[i].cra_module = THIS_MODULE;
+               algs[i].cra_init = tegra_aes_cra_init;
+               algs[i].cra_exit = tegra_aes_cra_exit;
+
+               err = crypto_register_alg(&algs[i]);
+               if (err)
+                       goto out;
+       }
+
+       dev_info(dev, "registered");
+       return 0;
+
+out:
+       for (j = 0; j < i; j++)
+               crypto_unregister_alg(&algs[j]);
+       if (dd->ivkey_base)
+               dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
+                       dd->ivkey_base, dd->ivkey_phys_base);
+       if (dd->buf_in)
+               dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                       dd->buf_in, dd->dma_buf_in);
+       if (dd->buf_out)
+               dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                       dd->buf_out, dd->dma_buf_out);
+       if (IS_ERR(dd->aes_clk))
+               clk_put(dd->aes_clk);
+       if (aes_wq)
+               destroy_workqueue(aes_wq);
+       spin_lock(&list_lock);
+       list_del(&dev_list);
+       spin_unlock(&list_lock);
+
+       aes_dev = NULL;
+
+       dev_err(dev, "%s: initialization failed.\n", __func__);
+       return err;
+}
+
+static int __devexit tegra_aes_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra_aes_dev *dd = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(algs); i++)
+               crypto_unregister_alg(&algs[i]);
+
+       cancel_work_sync(&aes_work);
+       destroy_workqueue(aes_wq);
+       spin_lock(&list_lock);
+       list_del(&dev_list);
+       spin_unlock(&list_lock);
+
+       dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES,
+                         dd->ivkey_base, dd->ivkey_phys_base);
+       dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                         dd->buf_in, dd->dma_buf_in);
+       dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES,
+                         dd->buf_out, dd->dma_buf_out);
+       clk_put(dd->aes_clk);
+       aes_dev = NULL;
+
+       return 0;
+}
+
+static struct of_device_id tegra_aes_of_match[] __devinitdata = {
+       { .compatible = "nvidia,tegra20-aes", },
+       { .compatible = "nvidia,tegra30-aes", },
+       { },
+};
+
+static struct platform_driver tegra_aes_driver = {
+       .probe  = tegra_aes_probe,
+       .remove = __devexit_p(tegra_aes_remove),
+       .driver = {
+               .name   = "tegra-aes",
+               .owner  = THIS_MODULE,
+               .of_match_table = tegra_aes_of_match,
+       },
+};
+
+module_platform_driver(tegra_aes_driver);
+
+MODULE_DESCRIPTION("Tegra AES/OFB/CPRNG hw acceleration support.");
+MODULE_AUTHOR("NVIDIA Corporation");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/tegra-aes.h b/drivers/crypto/tegra-aes.h
new file mode 100644 (file)
index 0000000..6006333
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010, NVIDIA 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __CRYPTODEV_TEGRA_AES_H
+#define __CRYPTODEV_TEGRA_AES_H
+
+#define TEGRA_AES_ICMDQUE_WR                   0x1000
+#define TEGRA_AES_CMDQUE_CONTROL               0x1008
+#define TEGRA_AES_INTR_STATUS                  0x1018
+#define TEGRA_AES_INT_ENB                      0x1040
+#define TEGRA_AES_CONFIG                       0x1044
+#define TEGRA_AES_IRAM_ACCESS_CFG              0x10A0
+#define TEGRA_AES_SECURE_DEST_ADDR             0x1100
+#define TEGRA_AES_SECURE_INPUT_SELECT          0x1104
+#define TEGRA_AES_SECURE_CONFIG                        0x1108
+#define TEGRA_AES_SECURE_CONFIG_EXT            0x110C
+#define TEGRA_AES_SECURE_SECURITY              0x1110
+#define TEGRA_AES_SECURE_HASH_RESULT0          0x1120
+#define TEGRA_AES_SECURE_HASH_RESULT1          0x1124
+#define TEGRA_AES_SECURE_HASH_RESULT2          0x1128
+#define TEGRA_AES_SECURE_HASH_RESULT3          0x112C
+#define TEGRA_AES_SECURE_SEC_SEL0              0x1140
+#define TEGRA_AES_SECURE_SEC_SEL1              0x1144
+#define TEGRA_AES_SECURE_SEC_SEL2              0x1148
+#define TEGRA_AES_SECURE_SEC_SEL3              0x114C
+#define TEGRA_AES_SECURE_SEC_SEL4              0x1150
+#define TEGRA_AES_SECURE_SEC_SEL5              0x1154
+#define TEGRA_AES_SECURE_SEC_SEL6              0x1158
+#define TEGRA_AES_SECURE_SEC_SEL7              0x115C
+
+/* interrupt status reg masks and shifts */
+#define TEGRA_AES_ENGINE_BUSY_FIELD            BIT(0)
+#define TEGRA_AES_ICQ_EMPTY_FIELD              BIT(3)
+#define TEGRA_AES_DMA_BUSY_FIELD               BIT(23)
+
+/* secure select reg masks and shifts */
+#define TEGRA_AES_SECURE_SEL0_KEYREAD_ENB0_FIELD       BIT(0)
+
+/* secure config ext masks and shifts */
+#define TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD     BIT(15)
+
+/* secure config masks and shifts */
+#define TEGRA_AES_SECURE_KEY_INDEX_SHIFT       20
+#define TEGRA_AES_SECURE_KEY_INDEX_FIELD       (0x1F << TEGRA_AES_SECURE_KEY_INDEX_SHIFT)
+#define TEGRA_AES_SECURE_BLOCK_CNT_SHIFT       0
+#define TEGRA_AES_SECURE_BLOCK_CNT_FIELD       (0xFFFFF << TEGRA_AES_SECURE_BLOCK_CNT_SHIFT)
+
+/* stream interface select masks and shifts */
+#define TEGRA_AES_CMDQ_CTRL_UCMDQEN_FIELD      BIT(0)
+#define TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD      BIT(1)
+#define TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD  BIT(4)
+#define TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD  BIT(5)
+
+/* config register masks and shifts */
+#define TEGRA_AES_CONFIG_ENDIAN_ENB_FIELD      BIT(10)
+#define TEGRA_AES_CONFIG_MODE_SEL_SHIFT                0
+#define TEGRA_AES_CONFIG_MODE_SEL_FIELD                (0x1F << TEGRA_AES_CONFIG_MODE_SEL_SHIFT)
+
+/* extended config */
+#define TEGRA_AES_SECURE_OFFSET_CNT_SHIFT      24
+#define TEGRA_AES_SECURE_OFFSET_CNT_FIELD      (0xFF << TEGRA_AES_SECURE_OFFSET_CNT_SHIFT)
+#define TEGRA_AES_SECURE_KEYSCHED_GEN_FIELD    BIT(15)
+
+/* init vector select */
+#define TEGRA_AES_SECURE_IV_SELECT_SHIFT       10
+#define TEGRA_AES_SECURE_IV_SELECT_FIELD       BIT(10)
+
+/* secure engine input */
+#define TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT   28
+#define TEGRA_AES_SECURE_INPUT_ALG_SEL_FIELD   (0xF << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT)
+#define TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT   16
+#define TEGRA_AES_SECURE_INPUT_KEY_LEN_FIELD   (0xFFF << TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT)
+#define TEGRA_AES_SECURE_RNG_ENB_FIELD         BIT(11)
+#define TEGRA_AES_SECURE_CORE_SEL_SHIFT                9
+#define TEGRA_AES_SECURE_CORE_SEL_FIELD                BIT(9)
+#define TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT      7
+#define TEGRA_AES_SECURE_VCTRAM_SEL_FIELD      (0x3 << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT)
+#define TEGRA_AES_SECURE_INPUT_SEL_SHIFT       5
+#define TEGRA_AES_SECURE_INPUT_SEL_FIELD       (0x3 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT)
+#define TEGRA_AES_SECURE_XOR_POS_SHIFT         3
+#define TEGRA_AES_SECURE_XOR_POS_FIELD         (0x3 << TEGRA_AES_SECURE_XOR_POS_SHIFT)
+#define TEGRA_AES_SECURE_HASH_ENB_FIELD                BIT(2)
+#define TEGRA_AES_SECURE_ON_THE_FLY_FIELD      BIT(0)
+
+/* interrupt error mask */
+#define TEGRA_AES_INT_ERROR_MASK               0xFFF000
+
+#endif
index d0c4118..0409cf3 100644 (file)
@@ -190,6 +190,17 @@ config GPIO_VX855
          additional drivers must be enabled in order to use the
          functionality of the device.
 
+config GPIO_GE_FPGA
+       bool "GE FPGA based GPIO"
+       depends on GE_FPGA
+       help
+         Support for common GPIO functionality provided on some GE Single Board
+         Computers.
+
+         This driver provides basic support (configure as input or output, read
+         and write pin state) for GPIO implemented in a number of GE single
+         board computers.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX7300
index fa10df6..9a8fb54 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_CS5535)     += gpio-cs5535.o
 obj-$(CONFIG_GPIO_DA9052)      += gpio-da9052.o
 obj-$(CONFIG_ARCH_DAVINCI)     += gpio-davinci.o
 obj-$(CONFIG_GPIO_EP93XX)      += gpio-ep93xx.o
+obj-$(CONFIG_GPIO_GE_FPGA)     += gpio-ge.o
 obj-$(CONFIG_GPIO_IT8761E)     += gpio-it8761e.o
 obj-$(CONFIG_GPIO_JANZ_TTL)    += gpio-janz-ttl.o
 obj-$(CONFIG_ARCH_KS8695)      += gpio-ks8695.o
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
new file mode 100644 (file)
index 0000000..7b95a4a
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Driver for GE FPGA based GPIO
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ *
+ * 2008 (c) GE Intelligent Platforms Embedded Systems, 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.
+ */
+
+/* TODO
+ *
+ * Configuration of output modes (totem-pole/open-drain)
+ * Interrupt configuration - interrupts are always generated the FPGA relies on
+ * the I/O interrupt controllers mask to stop them propergating
+ */
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#define GEF_GPIO_DIRECT                0x00
+#define GEF_GPIO_IN            0x04
+#define GEF_GPIO_OUT           0x08
+#define GEF_GPIO_TRIG          0x0C
+#define GEF_GPIO_POLAR_A       0x10
+#define GEF_GPIO_POLAR_B       0x14
+#define GEF_GPIO_INT_STAT      0x18
+#define GEF_GPIO_OVERRUN       0x1C
+#define GEF_GPIO_MODE          0x20
+
+static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
+{
+       unsigned int data;
+
+       data = ioread32be(reg);
+       /* value: 0=low; 1=high */
+       if (value & 0x1)
+               data = data | (0x1 << offset);
+       else
+               data = data & ~(0x1 << offset);
+
+       iowrite32be(data, reg);
+}
+
+
+static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned int data;
+       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+       data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+       data = data | (0x1 << offset);
+       iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+       return 0;
+}
+
+static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+       unsigned int data;
+       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+       /* Set direction before switching to input */
+       _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+
+       data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
+       data = data & ~(0x1 << offset);
+       iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
+
+       return 0;
+}
+
+static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned int data;
+       int state = 0;
+       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+       data = ioread32be(mmchip->regs + GEF_GPIO_IN);
+       state = (int)((data >> offset) & 0x1);
+
+       return state;
+}
+
+static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
+
+       _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+}
+
+static int __init gef_gpio_init(void)
+{
+       struct device_node *np;
+       int retval;
+       struct of_mm_gpio_chip *gef_gpio_chip;
+
+       for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
+
+               pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+               /* Allocate chip structure */
+               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+               if (!gef_gpio_chip) {
+                       pr_err("%s: Unable to allocate structure\n",
+                               np->full_name);
+                       continue;
+               }
+
+               /* Setup pointers to chip functions */
+               gef_gpio_chip->gc.of_gpio_n_cells = 2;
+               gef_gpio_chip->gc.ngpio = 19;
+               gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+               gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+               gef_gpio_chip->gc.get = gef_gpio_get;
+               gef_gpio_chip->gc.set = gef_gpio_set;
+
+               /* This function adds a memory mapped GPIO chip */
+               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+               if (retval) {
+                       kfree(gef_gpio_chip);
+                       pr_err("%s: Unable to add GPIO\n", np->full_name);
+               }
+       }
+
+       for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
+
+               pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
+
+               /* Allocate chip structure */
+               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+               if (!gef_gpio_chip) {
+                       pr_err("%s: Unable to allocate structure\n",
+                               np->full_name);
+                       continue;
+               }
+
+               /* Setup pointers to chip functions */
+               gef_gpio_chip->gc.of_gpio_n_cells = 2;
+               gef_gpio_chip->gc.ngpio = 6;
+               gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+               gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+               gef_gpio_chip->gc.get = gef_gpio_get;
+               gef_gpio_chip->gc.set = gef_gpio_set;
+
+               /* This function adds a memory mapped GPIO chip */
+               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+               if (retval) {
+                       kfree(gef_gpio_chip);
+                       pr_err("%s: Unable to add GPIO\n", np->full_name);
+               }
+       }
+
+       for_each_compatible_node(np, NULL, "ge,imp3a-gpio") {
+
+               pr_debug("%s: Initialising GE GPIO\n", np->full_name);
+
+               /* Allocate chip structure */
+               gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
+               if (!gef_gpio_chip) {
+                       pr_err("%s: Unable to allocate structure\n",
+                               np->full_name);
+                       continue;
+               }
+
+               /* Setup pointers to chip functions */
+               gef_gpio_chip->gc.of_gpio_n_cells = 2;
+               gef_gpio_chip->gc.ngpio = 16;
+               gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
+               gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
+               gef_gpio_chip->gc.get = gef_gpio_get;
+               gef_gpio_chip->gc.set = gef_gpio_set;
+
+               /* This function adds a memory mapped GPIO chip */
+               retval = of_mm_gpiochip_add(np, gef_gpio_chip);
+               if (retval) {
+                       kfree(gef_gpio_chip);
+                       pr_err("%s: Unable to add GPIO\n", np->full_name);
+               }
+       }
+
+       return 0;
+};
+arch_initcall(gef_gpio_init);
+
+MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
+MODULE_LICENSE("GPL");
index 366bc15..8c279da 100644 (file)
@@ -560,6 +560,9 @@ static void data_enable_interrupts(struct fpga_device *priv)
 
        /* flush the writes */
        fpga_read_reg(priv, 0, MMAP_REG_STATUS);
+       fpga_read_reg(priv, 1, MMAP_REG_STATUS);
+       fpga_read_reg(priv, 2, MMAP_REG_STATUS);
+       fpga_read_reg(priv, 3, MMAP_REG_STATUS);
 
        /* switch back to the external interrupt source */
        iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL);
@@ -591,8 +594,12 @@ static void data_dma_cb(void *data)
        list_move_tail(&priv->inflight->entry, &priv->used);
        priv->inflight = NULL;
 
-       /* clear the FPGA status and re-enable interrupts */
-       data_enable_interrupts(priv);
+       /*
+        * If data dumping is still enabled, then clear the FPGA
+        * status registers and re-enable FPGA interrupts
+        */
+       if (priv->enabled)
+               data_enable_interrupts(priv);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -708,6 +715,15 @@ static irqreturn_t data_irq(int irq, void *dev_id)
 
        spin_lock(&priv->lock);
 
+       /*
+        * This is an error case that should never happen.
+        *
+        * If this driver has a bug and manages to re-enable interrupts while
+        * a DMA is in progress, then we will hit this statement and should
+        * start paying attention immediately.
+        */
+       BUG_ON(priv->inflight != NULL);
+
        /* hide the interrupt by switching the IRQ driver to GPIO */
        data_disable_interrupts(priv);
 
@@ -762,11 +778,15 @@ out:
  */
 static int data_device_enable(struct fpga_device *priv)
 {
+       bool enabled;
        u32 val;
        int ret;
 
        /* multiple enables are safe: they do nothing */
-       if (priv->enabled)
+       spin_lock_irq(&priv->lock);
+       enabled = priv->enabled;
+       spin_unlock_irq(&priv->lock);
+       if (enabled)
                return 0;
 
        /* check that the FPGAs are programmed */
@@ -797,6 +817,9 @@ static int data_device_enable(struct fpga_device *priv)
                goto out_error;
        }
 
+       /* prevent the FPGAs from generating interrupts */
+       data_disable_interrupts(priv);
+
        /* hookup the irq handler */
        ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv);
        if (ret) {
@@ -804,11 +827,13 @@ static int data_device_enable(struct fpga_device *priv)
                goto out_error;
        }
 
-       /* switch to the external FPGA IRQ line */
-       data_enable_interrupts(priv);
-
-       /* success, we're enabled */
+       /* allow the DMA callback to re-enable FPGA interrupts */
+       spin_lock_irq(&priv->lock);
        priv->enabled = true;
+       spin_unlock_irq(&priv->lock);
+
+       /* allow the FPGAs to generate interrupts */
+       data_enable_interrupts(priv);
        return 0;
 
 out_error:
@@ -834,41 +859,40 @@ out_error:
  */
 static int data_device_disable(struct fpga_device *priv)
 {
-       int ret;
+       spin_lock_irq(&priv->lock);
 
        /* allow multiple disable */
-       if (!priv->enabled)
+       if (!priv->enabled) {
+               spin_unlock_irq(&priv->lock);
                return 0;
+       }
+
+       /*
+        * Mark the device disabled
+        *
+        * This stops DMA callbacks from re-enabling interrupts
+        */
+       priv->enabled = false;
 
-       /* switch to the internal GPIO IRQ line */
+       /* prevent the FPGAs from generating interrupts */
        data_disable_interrupts(priv);
 
+       /* wait until all ongoing DMA has finished */
+       while (priv->inflight != NULL) {
+               spin_unlock_irq(&priv->lock);
+               wait_event(priv->wait, priv->inflight == NULL);
+               spin_lock_irq(&priv->lock);
+       }
+
+       spin_unlock_irq(&priv->lock);
+
        /* unhook the irq handler */
        free_irq(priv->irq, priv);
 
-       /*
-        * wait for all outstanding DMA to complete
-        *
-        * Device interrupts are disabled, therefore another buffer cannot
-        * be marked inflight.
-        */
-       ret = wait_event_interruptible(priv->wait, priv->inflight == NULL);
-       if (ret)
-               return ret;
-
        /* free the correlation table */
        sg_free_table(&priv->corl_table);
        priv->corl_nents = 0;
 
-       /*
-        * We are taking the spinlock not to protect priv->enabled, but instead
-        * to make sure that there are no readers in the process of altering
-        * the free or used lists while we are setting this flag.
-        */
-       spin_lock_irq(&priv->lock);
-       priv->enabled = false;
-       spin_unlock_irq(&priv->lock);
-
        /* free all buffers: the free and used lists are not being changed */
        data_free_buffers(priv);
        return 0;
@@ -896,15 +920,6 @@ static unsigned int list_num_entries(struct list_head *list)
 static int data_debug_show(struct seq_file *f, void *offset)
 {
        struct fpga_device *priv = f->private;
-       int ret;
-
-       /*
-        * Lock the mutex first, so that we get an accurate value for enable
-        * Lock the spinlock next, to get accurate list counts
-        */
-       ret = mutex_lock_interruptible(&priv->mutex);
-       if (ret)
-               return ret;
 
        spin_lock_irq(&priv->lock);
 
@@ -917,7 +932,6 @@ static int data_debug_show(struct seq_file *f, void *offset)
        seq_printf(f, "num_dropped: %d\n", priv->num_dropped);
 
        spin_unlock_irq(&priv->lock);
-       mutex_unlock(&priv->mutex);
        return 0;
 }
 
@@ -970,7 +984,13 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
        struct fpga_device *priv = dev_get_drvdata(dev);
-       return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled);
+       int ret;
+
+       spin_lock_irq(&priv->lock);
+       ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled);
+       spin_unlock_irq(&priv->lock);
+
+       return ret;
 }
 
 static ssize_t data_en_set(struct device *dev, struct device_attribute *attr,
@@ -986,6 +1006,7 @@ static ssize_t data_en_set(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
        }
 
+       /* protect against concurrent enable/disable */
        ret = mutex_lock_interruptible(&priv->mutex);
        if (ret)
                return ret;
@@ -1079,6 +1100,7 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count,
        struct fpga_reader *reader = filp->private_data;
        struct fpga_device *priv = reader->priv;
        struct list_head *used = &priv->used;
+       bool drop_buffer = false;
        struct data_buf *dbuf;
        size_t avail;
        void *data;
@@ -1166,10 +1188,12 @@ have_buffer:
         * One of two things has happened, the device is disabled, or the
         * device has been reconfigured underneath us. In either case, we
         * should just throw away the buffer.
+        *
+        * Lockdep complains if this is done under the spinlock, so we
+        * handle it during the unlock path.
         */
        if (!priv->enabled || dbuf->size != priv->bufsize) {
-               videobuf_dma_unmap(priv->dev, &dbuf->vb);
-               data_free_buffer(dbuf);
+               drop_buffer = true;
                goto out_unlock;
        }
 
@@ -1178,6 +1202,12 @@ have_buffer:
 
 out_unlock:
        spin_unlock_irq(&priv->lock);
+
+       if (drop_buffer) {
+               videobuf_dma_unmap(priv->dev, &dbuf->vb);
+               data_free_buffer(dbuf);
+       }
+
        return count;
 }
 
index 3536175..1c034b8 100644 (file)
@@ -87,7 +87,7 @@
 static LIST_HEAD(service_processors);
 
 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
-static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
+static void ibmasmfs_create_files (struct super_block *sb);
 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
 
 
@@ -114,7 +114,6 @@ static struct file_system_type ibmasmfs_type = {
 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
 {
        struct inode *root;
-       struct dentry *root_dentry;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -129,14 +128,11 @@ static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
        root->i_op = &simple_dir_inode_operations;
        root->i_fop = ibmasmfs_dir_ops;
 
-       root_dentry = d_alloc_root(root);
-       if (!root_dentry) {
-               iput(root);
+       sb->s_root = d_make_root(root);
+       if (!sb->s_root)
                return -ENOMEM;
-       }
-       sb->s_root = root_dentry;
 
-       ibmasmfs_create_files(sb, root_dentry);
+       ibmasmfs_create_files(sb);
        return 0;
 }
 
@@ -612,7 +608,7 @@ static const struct file_operations remote_settings_fops = {
 };
 
 
-static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
+static void ibmasmfs_create_files (struct super_block *sb)
 {
        struct list_head *entry;
        struct service_processor *sp;
@@ -621,7 +617,7 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
                struct dentry *dir;
                struct dentry *remote_dir;
                sp = list_entry(entry, struct service_processor, node);
-               dir = ibmasmfs_create_dir(sb, root, sp->dirname);
+               dir = ibmasmfs_create_dir(sb, sb->s_root, sp->dirname);
                if (!dir)
                        continue;
 
index 1ccedb7..168d800 100644 (file)
@@ -211,18 +211,17 @@ static void __exit ibmasm_exit (void)
 
 static int __init ibmasm_init(void)
 {
-       int result;
+       int result = pci_register_driver(&ibmasm_driver);
+       if (result)
+               return result;
 
        result = ibmasmfs_register();
        if (result) {
+               pci_unregister_driver(&ibmasm_driver);
                err("Failed to register ibmasmfs file system");
                return result;
        }
-       result = pci_register_driver(&ibmasm_driver);
-       if (result) {
-               ibmasmfs_unregister();
-               return result;
-       }
+
        ibmasm_register_panic_notifier();
        info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
        return 0;
index c6a383d..e5a3c7b 100644 (file)
@@ -1685,7 +1685,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
 
        if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
             card->ext_csd.boot_ro_lockable) {
-               mode_t mode;
+               umode_t mode;
 
                if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
                        mode = S_IRUGO;
index 31b034b..3b1d6da 100644 (file)
@@ -462,6 +462,16 @@ config MTD_NAND_FSL_ELBC
          Enabling this option will enable you to use this to control
          external NAND devices.
 
+config MTD_NAND_FSL_IFC
+       tristate "NAND support for Freescale IFC controller"
+       depends on MTD_NAND && FSL_SOC
+       select FSL_IFC
+       help
+         Various Freescale chips e.g P1010, include a NAND Flash machine
+         with built-in hardware ECC capabilities.
+         Enabling this option will enable you to use this to control
+         external NAND devices.
+
 config MTD_NAND_FSL_UPM
        tristate "Support for NAND on Freescale UPM"
        depends on PPC_83xx || PPC_85xx
index 618f4ba..19bc8cb 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_MTD_ALAUDA)              += alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC)         += fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)         += fsl_upm.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)                += sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)             += mxc_nand.o
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
new file mode 100644 (file)
index 0000000..c30ac7b
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011-2012 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/fsl_ifc.h>
+
+#define ERR_BYTE               0xFF /* Value returned for read
+                                       bytes when read failed  */
+#define IFC_TIMEOUT_MSECS      500  /* Maximum number of mSecs to wait
+                                       for IFC NAND Machine    */
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+       struct mtd_info mtd;
+       struct nand_chip chip;
+       struct fsl_ifc_ctrl *ctrl;
+
+       struct device *dev;
+       int bank;               /* Chip select bank number              */
+       unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+       u8 __iomem *vbase;      /* Chip select base virtual address     */
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+       struct nand_hw_control controller;
+       struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+       u8 __iomem *addr;       /* Address of assigned IFC buffer       */
+       unsigned int page;      /* Last page written to / read from     */
+       unsigned int read_bytes;/* Number of bytes read during command  */
+       unsigned int column;    /* Saved column from SEQIN              */
+       unsigned int index;     /* Pointer to next byte to 'read'       */
+       unsigned int oob;       /* Non zero if operating on OOB data    */
+       unsigned int eccread;   /* Non zero for a full-page ECC read    */
+       unsigned int counter;   /* counter for the initializations      */
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/* 512-byte page with 4-bit ECC, 8-bit */
+static struct nand_ecclayout oob_512_8bit_ecc4 = {
+       .eccbytes = 8,
+       .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+       .oobfree = { {0, 5}, {6, 2} },
+};
+
+/* 512-byte page with 4-bit ECC, 16-bit */
+static struct nand_ecclayout oob_512_16bit_ecc4 = {
+       .eccbytes = 8,
+       .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+       .oobfree = { {2, 6}, },
+};
+
+/* 2048-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_2048_ecc4 = {
+       .eccbytes = 32,
+       .eccpos = {
+               8, 9, 10, 11, 12, 13, 14, 15,
+               16, 17, 18, 19, 20, 21, 22, 23,
+               24, 25, 26, 27, 28, 29, 30, 31,
+               32, 33, 34, 35, 36, 37, 38, 39,
+       },
+       .oobfree = { {2, 6}, {40, 24} },
+};
+
+/* 4096-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_4096_ecc4 = {
+       .eccbytes = 64,
+       .eccpos = {
+               8, 9, 10, 11, 12, 13, 14, 15,
+               16, 17, 18, 19, 20, 21, 22, 23,
+               24, 25, 26, 27, 28, 29, 30, 31,
+               32, 33, 34, 35, 36, 37, 38, 39,
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
+               56, 57, 58, 59, 60, 61, 62, 63,
+               64, 65, 66, 67, 68, 69, 70, 71,
+       },
+       .oobfree = { {2, 6}, {72, 56} },
+};
+
+/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
+static struct nand_ecclayout oob_4096_ecc8 = {
+       .eccbytes = 128,
+       .eccpos = {
+               8, 9, 10, 11, 12, 13, 14, 15,
+               16, 17, 18, 19, 20, 21, 22, 23,
+               24, 25, 26, 27, 28, 29, 30, 31,
+               32, 33, 34, 35, 36, 37, 38, 39,
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
+               56, 57, 58, 59, 60, 61, 62, 63,
+               64, 65, 66, 67, 68, 69, 70, 71,
+               72, 73, 74, 75, 76, 77, 78, 79,
+               80, 81, 82, 83, 84, 85, 86, 87,
+               88, 89, 90, 91, 92, 93, 94, 95,
+               96, 97, 98, 99, 100, 101, 102, 103,
+               104, 105, 106, 107, 108, 109, 110, 111,
+               112, 113, 114, 115, 116, 117, 118, 119,
+               120, 121, 122, 123, 124, 125, 126, 127,
+               128, 129, 130, 131, 132, 133, 134, 135,
+       },
+       .oobfree = { {2, 6}, {136, 82} },
+};
+
+
+/*
+ * Generic flash bbt descriptors
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+                  NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 2, /* 0 on 8-bit small page */
+       .len = 4,
+       .veroffs = 6,
+       .maxblocks = 4,
+       .pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+                  NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 2, /* 0 on 8-bit small page */
+       .len = 4,
+       .veroffs = 6,
+       .maxblocks = 4,
+       .pattern = mirror_pattern,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       int buf_num;
+
+       ifc_nand_ctrl->page = page_addr;
+       /* Program ROW0/COL0 */
+       out_be32(&ifc->ifc_nand.row0, page_addr);
+       out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
+
+       buf_num = page_addr & priv->bufnum_mask;
+
+       ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+       ifc_nand_ctrl->index = column;
+
+       /* for OOB data point to the second half of the buffer */
+       if (oob)
+               ifc_nand_ctrl->index += mtd->writesize;
+}
+
+static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
+       u32 __iomem *mainarea = (u32 *)addr;
+       u8 __iomem *oob = addr + mtd->writesize;
+       int i;
+
+       for (i = 0; i < mtd->writesize / 4; i++) {
+               if (__raw_readl(&mainarea[i]) != 0xffffffff)
+                       return 0;
+       }
+
+       for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
+               int pos = chip->ecc.layout->eccpos[i];
+
+               if (__raw_readb(&oob[pos]) != 0xff)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+                         u32 *eccstat, unsigned int bufnum)
+{
+       u32 reg = eccstat[bufnum / 4];
+       int errors;
+
+       errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+
+       return errors;
+}
+
+/*
+ * execute IFC NAND command and wait for it to complete
+ */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       u32 eccstat[4];
+       int i;
+
+       /* set the chip select for NAND Transaction */
+       out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
+
+       dev_vdbg(priv->dev,
+                       "%s: fir0=%08x fcr0=%08x\n",
+                       __func__,
+                       in_be32(&ifc->ifc_nand.nand_fir0),
+                       in_be32(&ifc->ifc_nand.nand_fcr0));
+
+       ctrl->nand_stat = 0;
+
+       /* start read/write seq */
+       out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+
+       /* wait for command complete flag or timeout */
+       wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+                          IFC_TIMEOUT_MSECS * HZ/1000);
+
+       /* ctrl->nand_stat will be updated from IRQ context */
+       if (!ctrl->nand_stat)
+               dev_err(priv->dev, "Controller is not responding\n");
+       if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+               dev_err(priv->dev, "NAND Flash Timeout Error\n");
+       if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+               dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+
+       if (nctrl->eccread) {
+               int errors;
+               int bufnum = nctrl->page & priv->bufnum_mask;
+               int sector = bufnum * chip->ecc.steps;
+               int sector_end = sector + chip->ecc.steps - 1;
+
+               for (i = sector / 4; i <= sector_end / 4; i++)
+                       eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+
+               for (i = sector; i <= sector_end; i++) {
+                       errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+                       if (errors == 15) {
+                               /*
+                                * Uncorrectable error.
+                                * OK only if the whole page is blank.
+                                *
+                                * We disable ECCER reporting due to...
+                                * erratum IFC-A002770 -- so report it now if we
+                                * see an uncorrectable error in ECCSTAT.
+                                */
+                               if (!is_blank(mtd, bufnum))
+                                       ctrl->nand_stat |=
+                                               IFC_NAND_EVTER_STAT_ECCER;
+                               break;
+                       }
+
+                       mtd->ecc_stats.corrected += errors;
+               }
+
+               nctrl->eccread = 0;
+       }
+}
+
+static void fsl_ifc_do_read(struct nand_chip *chip,
+                           int oob,
+                           struct mtd_info *mtd)
+{
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+       /* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+       if (mtd->writesize > 512) {
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                        (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                        (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                        (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+                        (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
+               out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+               out_be32(&ifc->ifc_nand.nand_fcr0,
+                       (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+                       (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+       } else {
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                        (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                        (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+                        (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
+               out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+               if (oob)
+                       out_be32(&ifc->ifc_nand.nand_fcr0,
+                                NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+               else
+                       out_be32(&ifc->ifc_nand.nand_fcr0,
+                               NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+       }
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+                            int column, int page_addr) {
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+       /* clear the read buffer */
+       ifc_nand_ctrl->read_bytes = 0;
+       if (command != NAND_CMD_PAGEPROG)
+               ifc_nand_ctrl->index = 0;
+
+       switch (command) {
+       /* READ0 read the entire buffer to use hardware ECC. */
+       case NAND_CMD_READ0:
+               out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+               set_addr(mtd, 0, page_addr, 0);
+
+               ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+               ifc_nand_ctrl->index += column;
+
+               if (chip->ecc.mode == NAND_ECC_HW)
+                       ifc_nand_ctrl->eccread = 1;
+
+               fsl_ifc_do_read(chip, 0, mtd);
+               fsl_ifc_run_command(mtd);
+               return;
+
+       /* READOOB reads only the OOB because no ECC is performed. */
+       case NAND_CMD_READOOB:
+               out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
+               set_addr(mtd, column, page_addr, 1);
+
+               ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+               fsl_ifc_do_read(chip, 1, mtd);
+               fsl_ifc_run_command(mtd);
+
+               return;
+
+       /* READID must read all 8 possible bytes */
+       case NAND_CMD_READID:
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                               (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+                               (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+               out_be32(&ifc->ifc_nand.nand_fcr0,
+                               NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+               /* 8 bytes for manuf, device and exts */
+               out_be32(&ifc->ifc_nand.nand_fbcr, 8);
+               ifc_nand_ctrl->read_bytes = 8;
+
+               set_addr(mtd, 0, 0, 0);
+               fsl_ifc_run_command(mtd);
+               return;
+
+       /* ERASE1 stores the block and page address */
+       case NAND_CMD_ERASE1:
+               set_addr(mtd, 0, page_addr, 0);
+               return;
+
+       /* ERASE2 uses the block and page address from ERASE1 */
+       case NAND_CMD_ERASE2:
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                        (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                        (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+
+               out_be32(&ifc->ifc_nand.nand_fcr0,
+                        (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+                        (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+
+               out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+               ifc_nand_ctrl->read_bytes = 0;
+               fsl_ifc_run_command(mtd);
+               return;
+
+       /* SEQIN sets up the addr buffer and all registers except the length */
+       case NAND_CMD_SEQIN: {
+               u32 nand_fcr0;
+               ifc_nand_ctrl->column = column;
+               ifc_nand_ctrl->oob = 0;
+
+               if (mtd->writesize > 512) {
+                       nand_fcr0 =
+                               (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+                               (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
+
+                       out_be32(&ifc->ifc_nand.nand_fir0,
+                                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                                (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                                (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                                (IFC_FIR_OP_WBCD  << IFC_NAND_FIR0_OP3_SHIFT) |
+                                (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
+               } else {
+                       nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+                                       IFC_NAND_FCR0_CMD1_SHIFT) |
+                                   (NAND_CMD_SEQIN <<
+                                       IFC_NAND_FCR0_CMD2_SHIFT));
+
+                       out_be32(&ifc->ifc_nand.nand_fir0,
+                                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                                (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+                                (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                                (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+                                (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
+                       out_be32(&ifc->ifc_nand.nand_fir1,
+                                (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
+
+                       if (column >= mtd->writesize)
+                               nand_fcr0 |=
+                               NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+                       else
+                               nand_fcr0 |=
+                               NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+               }
+
+               if (column >= mtd->writesize) {
+                       /* OOB area --> READOOB */
+                       column -= mtd->writesize;
+                       ifc_nand_ctrl->oob = 1;
+               }
+               out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
+               set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+               return;
+       }
+
+       /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+       case NAND_CMD_PAGEPROG: {
+               if (ifc_nand_ctrl->oob) {
+                       out_be32(&ifc->ifc_nand.nand_fbcr,
+                               ifc_nand_ctrl->index - ifc_nand_ctrl->column);
+               } else {
+                       out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+               }
+
+               fsl_ifc_run_command(mtd);
+               return;
+       }
+
+       case NAND_CMD_STATUS:
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
+               out_be32(&ifc->ifc_nand.nand_fcr0,
+                               NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
+               out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+               set_addr(mtd, 0, 0, 0);
+               ifc_nand_ctrl->read_bytes = 1;
+
+               fsl_ifc_run_command(mtd);
+
+               /*
+                * The chip always seems to report that it is
+                * write-protected, even when it is not.
+                */
+               setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP);
+               return;
+
+       case NAND_CMD_RESET:
+               out_be32(&ifc->ifc_nand.nand_fir0,
+                               IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
+               out_be32(&ifc->ifc_nand.nand_fcr0,
+                               NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+               fsl_ifc_run_command(mtd);
+               return;
+
+       default:
+               dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+                                       __func__, command);
+       }
+}
+
+static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+{
+       /* The hardware does not seem to support multiple
+        * chips per bank.
+        */
+}
+
+/*
+ * Write buf to the IFC NAND Controller Data Buffer
+ */
+static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+       if (len <= 0) {
+               dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+               return;
+       }
+
+       if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+               dev_err(priv->dev,
+                       "%s: beyond end of buffer (%d requested, %u available)\n",
+                       __func__, len, bufsize - ifc_nand_ctrl->index);
+               len = bufsize - ifc_nand_ctrl->index;
+       }
+
+       memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len);
+       ifc_nand_ctrl->index += len;
+}
+
+/*
+ * Read a byte from either the IFC hardware buffer
+ * read function for 8-bit buswidth
+ */
+static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+
+       /*
+        * If there are still bytes in the IFC buffer, then use the
+        * next byte.
+        */
+       if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes)
+               return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]);
+
+       dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+       return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       uint16_t data;
+
+       /*
+        * If there are still bytes in the IFC buffer, then use the
+        * next byte.
+        */
+       if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+               data = in_be16((uint16_t *)&ifc_nand_ctrl->
+                                       addr[ifc_nand_ctrl->index]);
+               ifc_nand_ctrl->index += 2;
+               return (uint8_t) data;
+       }
+
+       dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+       return ERR_BYTE;
+}
+
+/*
+ * Read from the IFC Controller Data Buffer
+ */
+static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       int avail;
+
+       if (len < 0) {
+               dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+               return;
+       }
+
+       avail = min((unsigned int)len,
+                       ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+       memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail);
+       ifc_nand_ctrl->index += avail;
+
+       if (len > avail)
+               dev_err(priv->dev,
+                       "%s: beyond end of buffer (%d requested, %d available)\n",
+                       __func__, len, avail);
+}
+
+/*
+ * Verify buffer against the IFC Controller Data Buffer
+ */
+static int fsl_ifc_verify_buf(struct mtd_info *mtd,
+                              const u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+       int i;
+
+       if (len < 0) {
+               dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len);
+               return -EINVAL;
+       }
+
+       if ((unsigned int)len > nctrl->read_bytes - nctrl->index) {
+               dev_err(priv->dev,
+                       "%s: beyond end of buffer (%d requested, %u available)\n",
+                       __func__, len, nctrl->read_bytes - nctrl->index);
+
+               nctrl->index = nctrl->read_bytes;
+               return -EINVAL;
+       }
+
+       for (i = 0; i < len; i++)
+               if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i])
+                       break;
+
+       nctrl->index += len;
+
+       if (i != len)
+               return -EIO;
+       if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       u32 nand_fsr;
+
+       /* Use READ_STATUS command, but wait for the device to be ready */
+       out_be32(&ifc->ifc_nand.nand_fir0,
+                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
+       out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
+                       IFC_NAND_FCR0_CMD0_SHIFT);
+       out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+       set_addr(mtd, 0, 0, 0);
+       ifc_nand_ctrl->read_bytes = 1;
+
+       fsl_ifc_run_command(mtd);
+
+       nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr);
+
+       /*
+        * The chip always seems to report that it is
+        * write-protected, even when it is not.
+        */
+       return nand_fsr | NAND_STATUS_WP;
+}
+
+static int fsl_ifc_read_page(struct mtd_info *mtd,
+                             struct nand_chip *chip,
+                             uint8_t *buf, int page)
+{
+       struct fsl_ifc_mtd *priv = chip->priv;
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+       fsl_ifc_read_buf(mtd, buf, mtd->writesize);
+       fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER)
+               dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n");
+
+       if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+               mtd->ecc_stats.failed++;
+
+       return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_ifc_write_page(struct mtd_info *mtd,
+                               struct nand_chip *chip,
+                               const uint8_t *buf)
+{
+       fsl_ifc_write_buf(mtd, buf, mtd->writesize);
+       fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_ifc_mtd *priv = chip->priv;
+
+       dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+                                                       chip->numchips);
+       dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+                                                       chip->chipsize);
+       dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+                                                       chip->pagemask);
+       dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+                                                       chip->chip_delay);
+       dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+                                                       chip->badblockpos);
+       dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+                                                       chip->chip_shift);
+       dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+                                                       chip->page_shift);
+       dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+                                                       chip->phys_erase_shift);
+       dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__,
+                                                       chip->ecclayout);
+       dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+                                                       chip->ecc.mode);
+       dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+                                                       chip->ecc.steps);
+       dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+                                                       chip->ecc.bytes);
+       dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+                                                       chip->ecc.total);
+       dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__,
+                                                       chip->ecc.layout);
+       dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+       dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+       dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+                                                       mtd->erasesize);
+       dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+                                                       mtd->writesize);
+       dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+                                                       mtd->oobsize);
+
+       return 0;
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+       struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+       struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+       struct nand_chip *chip = &priv->chip;
+       struct nand_ecclayout *layout;
+       u32 csor;
+
+       /* Fill in fsl_ifc_mtd structure */
+       priv->mtd.priv = chip;
+       priv->mtd.owner = THIS_MODULE;
+
+       /* fill in nand_chip structure */
+       /* set up function call table */
+       if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+               chip->read_byte = fsl_ifc_read_byte16;
+       else
+               chip->read_byte = fsl_ifc_read_byte;
+
+       chip->write_buf = fsl_ifc_write_buf;
+       chip->read_buf = fsl_ifc_read_buf;
+       chip->verify_buf = fsl_ifc_verify_buf;
+       chip->select_chip = fsl_ifc_select_chip;
+       chip->cmdfunc = fsl_ifc_cmdfunc;
+       chip->waitfunc = fsl_ifc_wait;
+
+       chip->bbt_td = &bbt_main_descr;
+       chip->bbt_md = &bbt_mirror_descr;
+
+       out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+
+       /* set up nand options */
+       chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+       chip->bbt_options = NAND_BBT_USE_FLASH;
+
+
+       if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+               chip->read_byte = fsl_ifc_read_byte16;
+               chip->options |= NAND_BUSWIDTH_16;
+       } else {
+               chip->read_byte = fsl_ifc_read_byte;
+       }
+
+       chip->controller = &ifc_nand_ctrl->controller;
+       chip->priv = priv;
+
+       chip->ecc.read_page = fsl_ifc_read_page;
+       chip->ecc.write_page = fsl_ifc_write_page;
+
+       csor = in_be32(&ifc->csor_cs[priv->bank].csor);
+
+       /* Hardware generates ECC per 512 Bytes */
+       chip->ecc.size = 512;
+       chip->ecc.bytes = 8;
+
+       switch (csor & CSOR_NAND_PGS_MASK) {
+       case CSOR_NAND_PGS_512:
+               if (chip->options & NAND_BUSWIDTH_16) {
+                       layout = &oob_512_16bit_ecc4;
+               } else {
+                       layout = &oob_512_8bit_ecc4;
+
+                       /* Avoid conflict with bad block marker */
+                       bbt_main_descr.offs = 0;
+                       bbt_mirror_descr.offs = 0;
+               }
+
+               priv->bufnum_mask = 15;
+               break;
+
+       case CSOR_NAND_PGS_2K:
+               layout = &oob_2048_ecc4;
+               priv->bufnum_mask = 3;
+               break;
+
+       case CSOR_NAND_PGS_4K:
+               if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+                   CSOR_NAND_ECC_MODE_4) {
+                       layout = &oob_4096_ecc4;
+               } else {
+                       layout = &oob_4096_ecc8;
+                       chip->ecc.bytes = 16;
+               }
+
+               priv->bufnum_mask = 1;
+               break;
+
+       default:
+               dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+               return -ENODEV;
+       }
+
+       /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+       if (csor & CSOR_NAND_ECC_DEC_EN) {
+               chip->ecc.mode = NAND_ECC_HW;
+               chip->ecc.layout = layout;
+       } else {
+               chip->ecc.mode = NAND_ECC_SOFT;
+       }
+
+       return 0;
+}
+
+static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+{
+       nand_release(&priv->mtd);
+
+       kfree(priv->mtd.name);
+
+       if (priv->vbase)
+               iounmap(priv->vbase);
+
+       ifc_nand_ctrl->chips[priv->bank] = NULL;
+       dev_set_drvdata(priv->dev, NULL);
+       kfree(priv);
+
+       return 0;
+}
+
+static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
+                     phys_addr_t addr)
+{
+       u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr);
+
+       if (!(cspr & CSPR_V))
+               return 0;
+       if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+               return 0;
+
+       return (cspr & CSPR_BA) == convert_ifc_address(addr);
+}
+
+static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+
+static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+{
+       struct fsl_ifc_regs __iomem *ifc;
+       struct fsl_ifc_mtd *priv;
+       struct resource res;
+       static const char *part_probe_types[]
+               = { "cmdlinepart", "RedBoot", "ofpart", NULL };
+       int ret;
+       int bank;
+       struct device_node *node = dev->dev.of_node;
+       struct mtd_part_parser_data ppdata;
+
+       ppdata.of_node = dev->dev.of_node;
+       if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+               return -ENODEV;
+       ifc = fsl_ifc_ctrl_dev->regs;
+
+       /* get, allocate and map the memory resource */
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret) {
+               dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+               return ret;
+       }
+
+       /* find which chip select it is connected to */
+       for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) {
+               if (match_bank(ifc, bank, res.start))
+                       break;
+       }
+
+       if (bank >= FSL_IFC_BANK_COUNT) {
+               dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       mutex_lock(&fsl_ifc_nand_mutex);
+       if (!fsl_ifc_ctrl_dev->nand) {
+               ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+               if (!ifc_nand_ctrl) {
+                       dev_err(&dev->dev, "failed to allocate memory\n");
+                       mutex_unlock(&fsl_ifc_nand_mutex);
+                       return -ENOMEM;
+               }
+
+               ifc_nand_ctrl->read_bytes = 0;
+               ifc_nand_ctrl->index = 0;
+               ifc_nand_ctrl->addr = NULL;
+               fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+
+               spin_lock_init(&ifc_nand_ctrl->controller.lock);
+               init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+       } else {
+               ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+       }
+       mutex_unlock(&fsl_ifc_nand_mutex);
+
+       ifc_nand_ctrl->chips[bank] = priv;
+       priv->bank = bank;
+       priv->ctrl = fsl_ifc_ctrl_dev;
+       priv->dev = &dev->dev;
+
+       priv->vbase = ioremap(res.start, resource_size(&res));
+       if (!priv->vbase) {
+               dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev_set_drvdata(priv->dev, priv);
+
+       out_be32(&ifc->ifc_nand.nand_evter_en,
+                       IFC_NAND_EVTER_EN_OPC_EN |
+                       IFC_NAND_EVTER_EN_FTOER_EN |
+                       IFC_NAND_EVTER_EN_WPER_EN);
+
+       /* enable NAND Machine Interrupts */
+       out_be32(&ifc->ifc_nand.nand_evter_intr_en,
+                       IFC_NAND_EVTER_INTR_OPCIR_EN |
+                       IFC_NAND_EVTER_INTR_FTOERIR_EN |
+                       IFC_NAND_EVTER_INTR_WPERIR_EN);
+
+       priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+       if (!priv->mtd.name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = fsl_ifc_chip_init(priv);
+       if (ret)
+               goto err;
+
+       ret = nand_scan_ident(&priv->mtd, 1, NULL);
+       if (ret)
+               goto err;
+
+       ret = fsl_ifc_chip_init_tail(&priv->mtd);
+       if (ret)
+               goto err;
+
+       ret = nand_scan_tail(&priv->mtd);
+       if (ret)
+               goto err;
+
+       /* First look for RedBoot table or partitions on the command
+        * line, these take precedence over device tree information */
+       mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
+                                               NULL, 0);
+
+       dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+                (unsigned long long)res.start, priv->bank);
+       return 0;
+
+err:
+       fsl_ifc_chip_remove(priv);
+       return ret;
+}
+
+static int fsl_ifc_nand_remove(struct platform_device *dev)
+{
+       struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+
+       fsl_ifc_chip_remove(priv);
+
+       mutex_lock(&fsl_ifc_nand_mutex);
+       ifc_nand_ctrl->counter--;
+       if (!ifc_nand_ctrl->counter) {
+               fsl_ifc_ctrl_dev->nand = NULL;
+               kfree(ifc_nand_ctrl);
+       }
+       mutex_unlock(&fsl_ifc_nand_mutex);
+
+       return 0;
+}
+
+static const struct of_device_id fsl_ifc_nand_match[] = {
+       {
+               .compatible = "fsl,ifc-nand",
+       },
+       {}
+};
+
+static struct platform_driver fsl_ifc_nand_driver = {
+       .driver = {
+               .name   = "fsl,ifc-nand",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_ifc_nand_match,
+       },
+       .probe       = fsl_ifc_nand_probe,
+       .remove      = fsl_ifc_nand_remove,
+};
+
+static int __init fsl_ifc_nand_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&fsl_ifc_nand_driver);
+       if (ret)
+               printk(KERN_ERR "fsl-ifc: Failed to register platform"
+                               "driver\n");
+
+       return ret;
+}
+
+static void __exit fsl_ifc_nand_exit(void)
+{
+       platform_driver_unregister(&fsl_ifc_nand_driver);
+}
+
+module_init(fsl_ifc_nand_init);
+module_exit(fsl_ifc_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
index c9fdceb..6e8bc9d 100644 (file)
@@ -516,7 +516,7 @@ static const struct file_operations bnad_debugfs_op_drvinfo = {
 
 struct bnad_debugfs_entry {
        const char *name;
-       mode_t  mode;
+       umode_t  mode;
        const struct file_operations *fops;
 };
 
index 58dc117..0427c65 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/cdev.h>
+#include <linux/idr.h>
 #include <linux/fs.h>
 
 #include <net/net_namespace.h>
index 2f0aa0f..ee8fd03 100644 (file)
@@ -238,7 +238,6 @@ struct dentry *oprofilefs_mkdir(struct super_block *sb,
 static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *root_inode;
-       struct dentry *root_dentry;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -251,15 +250,11 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        root_inode->i_op = &simple_dir_inode_operations;
        root_inode->i_fop = &simple_dir_operations;
-       root_dentry = d_alloc_root(root_inode);
-       if (!root_dentry) {
-               iput(root_inode);
+       sb->s_root = d_make_root(root_inode);
+       if (!sb->s_root)
                return -ENOMEM;
-       }
-
-       sb->s_root = root_dentry;
 
-       oprofile_create_files(sb, root_dentry);
+       oprofile_create_files(sb, sb->s_root);
 
        // FIXME: verify kill_litter_super removes our dentries
        return 0;
index d3d18e8..4e89103 100644 (file)
@@ -974,9 +974,8 @@ config SCSI_IPS
 
 config SCSI_IBMVSCSI
        tristate "IBM Virtual SCSI support"
-       depends on PPC_PSERIES || PPC_ISERIES
+       depends on PPC_PSERIES
        select SCSI_SRP_ATTRS
-       select VIOPATH if PPC_ISERIES
        help
          This is the IBM POWER Virtual SCSI Client
 
index a423d96..ff5b5c5 100644 (file)
@@ -1,7 +1,6 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsic.o
 
 ibmvscsic-y                    += ibmvscsi.o
-ibmvscsic-$(CONFIG_PPC_ISERIES)        += iseries_vscsi.o 
 ibmvscsic-$(CONFIG_PPC_PSERIES)        += rpa_vscsi.o 
 
 obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvstgt.o
index 3d391dc..e984951 100644 (file)
  * and sends a CRQ message back to inform the client that the request has
  * completed.
  *
- * Note that some of the underlying infrastructure is different between
- * machines conforming to the "RS/6000 Platform Architecture" (RPA) and
- * the older iSeries hypervisor models.  To support both, some low level
- * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c.
- * The Makefile should pick one, not two, not zero, of these.
- *
- * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor
+ * TODO: This is currently pretty tied to the IBM pSeries hypervisor
  * interfaces.  It would be really nice to abstract this above an RDMA
  * layer.
  */
@@ -2085,9 +2079,7 @@ int __init ibmvscsi_module_init(void)
        driver_template.can_queue = max_requests;
        max_events = max_requests + 2;
 
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               ibmvscsi_ops = &iseriesvscsi_ops;
-       else if (firmware_has_feature(FW_FEATURE_VIO))
+       if (firmware_has_feature(FW_FEATURE_VIO))
                ibmvscsi_ops = &rpavscsi_ops;
        else
                return -ENODEV;
index 02197a2..c503e17 100644 (file)
@@ -127,7 +127,6 @@ struct ibmvscsi_ops {
        int (*resume) (struct ibmvscsi_host_data *hostdata);
 };
 
-extern struct ibmvscsi_ops iseriesvscsi_ops;
 extern struct ibmvscsi_ops rpavscsi_ops;
 
 #endif                         /* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
deleted file mode 100644 (file)
index f477645..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* ------------------------------------------------------------
- * iSeries_vscsi.c
- * (C) Copyright IBM Corporation 1994, 2003
- * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
- *          Santiago Leon (santil@us.ibm.com)
- *          Dave Boutcher (sleddog@us.ibm.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
- *
- * ------------------------------------------------------------
- * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices
- *
- * This driver allows the Linux SCSI peripheral drivers to directly
- * access devices in the hosting partition, either on an iSeries
- * hypervisor system or a converged hypervisor system.
- */
-
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/vio.h>
-#include <linux/device.h>
-#include "ibmvscsi.h"
-
-/* global variables */
-static struct ibmvscsi_host_data *single_host_data;
-
-/* ------------------------------------------------------------
- * Routines for direct interpartition interaction
- */
-struct srp_lp_event {
-       struct HvLpEvent lpevt; /* 0x00-0x17          */
-       u32 reserved1;          /* 0x18-0x1B; unused  */
-       u16 version;            /* 0x1C-0x1D; unused  */
-       u16 subtype_rc;         /* 0x1E-0x1F; unused  */
-       struct viosrp_crq crq;  /* 0x20-0x3F          */
-};
-
-/** 
- * standard interface for handling logical partition events.
- */
-static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
-{
-       struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
-
-       if (!evt) {
-               printk(KERN_ERR "ibmvscsi: received null event\n");
-               return;
-       }
-
-       if (single_host_data == NULL) {
-               printk(KERN_ERR
-                      "ibmvscsi: received event, no adapter present\n");
-               return;
-       }
-
-       ibmvscsi_handle_crq(&evt->crq, single_host_data);
-}
-
-/* ------------------------------------------------------------
- * Routines for driver initialization
- */
-static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
-                                      struct ibmvscsi_host_data *hostdata,
-                                      int max_requests)
-{
-       int rc;
-
-       single_host_data = hostdata;
-       rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-       if (rc < 0) {
-               printk("viopath_open failed with rc %d in open_event_path\n",
-                      rc);
-               goto viopath_open_failed;
-       }
-
-       rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
-       if (rc < 0) {
-               printk("vio_setHandler failed with rc %d in open_event_path\n",
-                      rc);
-               goto vio_setHandler_failed;
-       }
-       return 0;
-
-      vio_setHandler_failed:
-       viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-      viopath_open_failed:
-       return -1;
-}
-
-static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
-                                          struct ibmvscsi_host_data *hostdata,
-                                          int max_requests)
-{
-       vio_clearHandler(viomajorsubtype_scsi);
-       viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
-}
-
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue:     crq_queue to initialize and register
- * @hostdata:  ibmvscsi_host_data of host
- *
- * no-op for iSeries
- */
-static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
-                                       struct ibmvscsi_host_data *hostdata)
-{
-       return 0;
-}
-
-/**
- * reenable_crq_queue: - reenables a crq after a failure
- * @queue:     crq_queue to initialize and register
- * @hostdata:  ibmvscsi_host_data of host
- *
- * no-op for iSeries
- */
-static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
-                                          struct ibmvscsi_host_data *hostdata)
-{
-       return 0;
-}
-
-/**
- * iseriesvscsi_send_crq: - Send a CRQ
- * @hostdata:  the adapter
- * @word1:     the first 64 bits of the data
- * @word2:     the second 64 bits of the data
- */
-static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
-                                u64 word1, u64 word2)
-{
-       single_host_data = hostdata;
-       return HvCallEvent_signalLpEventFast(viopath_hostLp,
-                                            HvLpEvent_Type_VirtualIo,
-                                            viomajorsubtype_scsi,
-                                            HvLpEvent_AckInd_NoAck,
-                                            HvLpEvent_AckType_ImmediateAck,
-                                            viopath_sourceinst(viopath_hostLp),
-                                            viopath_targetinst(viopath_hostLp),
-                                            0,
-                                            VIOVERSION << 16, word1, word2, 0,
-                                            0);
-}
-
-static int iseriesvscsi_resume(struct ibmvscsi_host_data *hostdata)
-{
-       return 0;
-}
-
-struct ibmvscsi_ops iseriesvscsi_ops = {
-       .init_crq_queue = iseriesvscsi_init_crq_queue,
-       .release_crq_queue = iseriesvscsi_release_crq_queue,
-       .reset_crq_queue = iseriesvscsi_reset_crq_queue,
-       .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
-       .send_crq = iseriesvscsi_send_crq,
-       .resume = iseriesvscsi_resume,
-};
index 501b27c..1c6f700 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/crypto.h>
 #include <linux/completion.h>
 #include <linux/module.h>
+#include <linux/idr.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi_device.h>
 #include <scsi/iscsi_proto.h>
index 38cb7ce..1ee33a8 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/kthread.h>
 #include <linux/crypto.h>
+#include <linux/idr.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index 4222035..48cb8d3 100644 (file)
@@ -24,16 +24,6 @@ config HVC_OLD_HVSI
        depends on HVC_CONSOLE
        default n
 
-config HVC_ISERIES
-       bool "iSeries Hypervisor Virtual Console support"
-       depends on PPC_ISERIES
-       default y
-       select HVC_DRIVER
-       select HVC_IRQ
-       select VIOPATH
-       help
-         iSeries machines support a hypervisor virtual console.
-
 config HVC_OPAL
        bool "OPAL Console support"
        depends on PPC_POWERNV
@@ -81,6 +71,10 @@ config HVC_UDBG
        depends on PPC && EXPERIMENTAL
        select HVC_DRIVER
        default n
+       help
+         This is meant to be used during HW bring up or debugging when
+        no other console mechanism exist but udbg, to get you a quick
+        console for userspace. Do NOT enable in production kernels. 
 
 config HVC_DCC
        bool "ARM JTAG DCC console"
index 89abf40..4ca3723 100644 (file)
@@ -1,7 +1,6 @@
 obj-$(CONFIG_HVC_CONSOLE)      += hvc_vio.o hvsi_lib.o
 obj-$(CONFIG_HVC_OPAL)         += hvc_opal.o hvsi_lib.o
 obj-$(CONFIG_HVC_OLD_HVSI)     += hvsi.o
-obj-$(CONFIG_HVC_ISERIES)      += hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)         += hvc_rtas.o
 obj-$(CONFIG_HVC_TILE)         += hvc_tile.o
 obj-$(CONFIG_HVC_DCC)          += hvc_dcc.o
diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c
deleted file mode 100644 (file)
index 3f4a897..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * iSeries vio driver interface to hvc_console.c
- *
- * This code is based heavily on hvc_vio.c and viocons.c
- *
- * Copyright (C) 2006 Stephen Rothwell, IBM 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; 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 <stdarg.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/console.h>
-
-#include <asm/hvconsole.h>
-#include <asm/vio.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_lp_event.h>
-
-#include "hvc_console.h"
-
-#define VTTY_PORTS 10
-
-static DEFINE_SPINLOCK(consolelock);
-static DEFINE_SPINLOCK(consoleloglock);
-
-static const char hvc_driver_name[] = "hvc_console";
-
-#define IN_BUF_SIZE    200
-
-/*
- * Our port information.
- */
-static struct port_info {
-       HvLpIndex lp;
-       u64 seq;        /* sequence number of last HV send */
-       u64 ack;        /* last ack from HV */
-       struct hvc_struct *hp;
-       int in_start;
-       int in_end;
-       unsigned char in_buf[IN_BUF_SIZE];
-} port_info[VTTY_PORTS] = {
-       [ 0 ... VTTY_PORTS - 1 ] = {
-               .lp = HvLpIndexInvalid
-       }
-};
-
-#define viochar_is_console(pi) ((pi) == &port_info[0])
-
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
-       {"serial", "IBM,iSeries-vty"},
-       { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
-static void hvlog(char *fmt, ...)
-{
-       int i;
-       unsigned long flags;
-       va_list args;
-       static char buf[256];
-
-       spin_lock_irqsave(&consoleloglock, flags);
-       va_start(args, fmt);
-       i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
-       va_end(args);
-       buf[i++] = '\r';
-       HvCall_writeLogBuffer(buf, i);
-       spin_unlock_irqrestore(&consoleloglock, flags);
-}
-
-/*
- * Initialize the common fields in a charLpEvent
- */
-static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
-{
-       struct HvLpEvent *hev = &viochar->event;
-
-       memset(viochar, 0, sizeof(struct viocharlpevent));
-
-       hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
-               HV_LP_EVENT_INT;
-       hev->xType = HvLpEvent_Type_VirtualIo;
-       hev->xSubtype = viomajorsubtype_chario | viochardata;
-       hev->xSourceLp = HvLpConfig_getLpIndex();
-       hev->xTargetLp = lp;
-       hev->xSizeMinus1 = sizeof(struct viocharlpevent);
-       hev->xSourceInstanceId = viopath_sourceinst(lp);
-       hev->xTargetInstanceId = viopath_targetinst(lp);
-}
-
-static int get_chars(uint32_t vtermno, char *buf, int count)
-{
-       struct port_info *pi;
-       int n = 0;
-       unsigned long flags;
-
-       if (vtermno >= VTTY_PORTS)
-               return -EINVAL;
-       if (count == 0)
-               return 0;
-
-       pi = &port_info[vtermno];
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (pi->in_end == 0)
-               goto done;
-
-       n = pi->in_end - pi->in_start;
-       if (n > count)
-               n = count;
-       memcpy(buf, &pi->in_buf[pi->in_start], n);
-       pi->in_start += n;
-       if (pi->in_start == pi->in_end) {
-               pi->in_start = 0;
-               pi->in_end = 0;
-       }
-done:
-       spin_unlock_irqrestore(&consolelock, flags);
-       return n;
-}
-
-static int put_chars(uint32_t vtermno, const char *buf, int count)
-{
-       struct viocharlpevent *viochar;
-       struct port_info *pi;
-       HvLpEvent_Rc hvrc;
-       unsigned long flags;
-       int sent = 0;
-
-       if (vtermno >= VTTY_PORTS)
-               return -EINVAL;
-
-       pi = &port_info[vtermno];
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
-               HvCall_writeLogBuffer(buf, count);
-               sent = count;
-               goto done;
-       }
-
-       viochar = vio_get_event_buffer(viomajorsubtype_chario);
-       if (viochar == NULL) {
-               hvlog("\n\rviocons: Can't get viochar buffer.");
-               goto done;
-       }
-
-       while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
-               int len;
-
-               len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
-
-               if (viochar_is_console(pi))
-                       HvCall_writeLogBuffer(buf, len);
-
-               init_data_event(viochar, pi->lp);
-
-               viochar->len = len;
-               viochar->event.xCorrelationToken = pi->seq++;
-               viochar->event.xSizeMinus1 =
-                       offsetof(struct viocharlpevent, data) + len;
-
-               memcpy(viochar->data, buf, len);
-
-               hvrc = HvCallEvent_signalLpEvent(&viochar->event);
-               if (hvrc)
-                       hvlog("\n\rerror sending event! return code %d\n\r",
-                               (int)hvrc);
-               sent += len;
-               count -= len;
-               buf += len;
-       }
-
-       vio_free_event_buffer(viomajorsubtype_chario, viochar);
-done:
-       spin_unlock_irqrestore(&consolelock, flags);
-       return sent;
-}
-
-static const struct hv_ops hvc_get_put_ops = {
-       .get_chars = get_chars,
-       .put_chars = put_chars,
-       .notifier_add = notifier_add_irq,
-       .notifier_del = notifier_del_irq,
-       .notifier_hangup = notifier_hangup_irq,
-};
-
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
-                       const struct vio_device_id *id)
-{
-       struct hvc_struct *hp;
-       struct port_info *pi;
-
-       /* probed with invalid parameters. */
-       if (!vdev || !id)
-               return -EPERM;
-
-       if (vdev->unit_address >= VTTY_PORTS)
-               return -ENODEV;
-
-       pi = &port_info[vdev->unit_address];
-
-       hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
-                       VIOCHAR_MAX_DATA);
-       if (IS_ERR(hp))
-               return PTR_ERR(hp);
-       pi->hp = hp;
-       dev_set_drvdata(&vdev->dev, pi);
-
-       return 0;
-}
-
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
-{
-       struct port_info *pi = dev_get_drvdata(&vdev->dev);
-       struct hvc_struct *hp = pi->hp;
-
-       return hvc_remove(hp);
-}
-
-static struct vio_driver hvc_vio_driver = {
-       .id_table       = hvc_driver_table,
-       .probe          = hvc_vio_probe,
-       .remove         = __devexit_p(hvc_vio_remove),
-       .driver         = {
-               .name   = hvc_driver_name,
-               .owner  = THIS_MODULE,
-       }
-};
-
-static void hvc_open_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       u8 port = cevent->virtual_device;
-       struct port_info *pi;
-       int reject = 0;
-
-       if (hvlpevent_is_ack(event)) {
-               if (port >= VTTY_PORTS)
-                       return;
-
-               spin_lock_irqsave(&consolelock, flags);
-
-               pi = &port_info[port];
-               if (event->xRc == HvLpEvent_Rc_Good) {
-                       pi->seq = pi->ack = 0;
-                       /*
-                        * This line allows connections from the primary
-                        * partition but once one is connected from the
-                        * primary partition nothing short of a reboot
-                        * of linux will allow access from the hosting
-                        * partition again without a required iSeries fix.
-                        */
-                       pi->lp = event->xTargetLp;
-               }
-
-               spin_unlock_irqrestore(&consolelock, flags);
-               if (event->xRc != HvLpEvent_Rc_Good)
-                       printk(KERN_WARNING
-                              "hvc: handle_open_event: event->xRc == (%d).\n",
-                              event->xRc);
-
-               if (event->xCorrelationToken != 0) {
-                       atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
-                       atomic_set(aptr, 1);
-               } else
-                       printk(KERN_WARNING
-                              "hvc: weird...got open ack without atomic\n");
-               return;
-       }
-
-       /* This had better require an ack, otherwise complain */
-       if (!hvlpevent_need_ack(event)) {
-               printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
-               return;
-       }
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       /* Make sure this is a good virtual tty */
-       if (port >= VTTY_PORTS) {
-               event->xRc = HvLpEvent_Rc_SubtypeError;
-               cevent->subtype_result_code = viorc_openRejected;
-               /*
-                * Flag state here since we can't printk while holding
-                * the consolelock spinlock.
-                */
-               reject = 1;
-       } else {
-               pi = &port_info[port];
-               if ((pi->lp != HvLpIndexInvalid) &&
-                               (pi->lp != event->xSourceLp)) {
-                       /*
-                        * If this is tty is already connected to a different
-                        * partition, fail.
-                        */
-                       event->xRc = HvLpEvent_Rc_SubtypeError;
-                       cevent->subtype_result_code = viorc_openRejected;
-                       reject = 2;
-               } else {
-                       pi->lp = event->xSourceLp;
-                       event->xRc = HvLpEvent_Rc_Good;
-                       cevent->subtype_result_code = viorc_good;
-                       pi->seq = pi->ack = 0;
-               }
-       }
-
-       spin_unlock_irqrestore(&consolelock, flags);
-
-       if (reject == 1)
-               printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
-       else if (reject == 2)
-               printk(KERN_WARNING "hvc: open rejected: console in exclusive "
-                               "use by another partition.\n");
-
-       /* Return the acknowledgement */
-       HvCallEvent_ackLpEvent(event);
-}
-
-/*
- * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
- * virtual console should never actually issue a close event to the hypervisor
- * because the virtual console never goes away.  A close event coming from the
- * hypervisor simply means that there are no client consoles connected to the
- * virtual console.
- */
-static void hvc_close_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       u8 port = cevent->virtual_device;
-
-       if (!hvlpevent_is_int(event)) {
-               printk(KERN_WARNING
-                       "hvc: got unexpected close acknowledgement\n");
-               return;
-       }
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING
-                       "hvc: close message from invalid virtual device.\n");
-               return;
-       }
-
-       /* For closes, just mark the console partition invalid */
-       spin_lock_irqsave(&consolelock, flags);
-
-       if (port_info[port].lp == event->xSourceLp)
-               port_info[port].lp = HvLpIndexInvalid;
-
-       spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_data_event(struct HvLpEvent *event)
-{
-       unsigned long flags;
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       struct port_info *pi;
-       int n;
-       u8 port = cevent->virtual_device;
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
-                               port);
-               return;
-       }
-       if (cevent->len == 0)
-               return;
-
-       /*
-        * Change 05/01/2003 - Ryan Arnold: If a partition other than
-        * the current exclusive partition tries to send us data
-        * events then just drop them on the floor because we don't
-        * want his stinking data.  He isn't authorized to receive
-        * data because he wasn't the first one to get the console,
-        * therefore he shouldn't be allowed to send data either.
-        * This will work without an iSeries fix.
-        */
-       pi = &port_info[port];
-       if (pi->lp != event->xSourceLp)
-               return;
-
-       spin_lock_irqsave(&consolelock, flags);
-
-       n = IN_BUF_SIZE - pi->in_end;
-       if (n > cevent->len)
-               n = cevent->len;
-       if (n > 0) {
-               memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
-               pi->in_end += n;
-       }
-       spin_unlock_irqrestore(&consolelock, flags);
-       if (n == 0)
-               printk(KERN_WARNING "hvc: input buffer overflow\n");
-}
-
-static void hvc_ack_event(struct HvLpEvent *event)
-{
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-       unsigned long flags;
-       u8 port = cevent->virtual_device;
-
-       if (port >= VTTY_PORTS) {
-               printk(KERN_WARNING "hvc: data on invalid virtual device\n");
-               return;
-       }
-
-       spin_lock_irqsave(&consolelock, flags);
-       port_info[port].ack = event->xCorrelationToken;
-       spin_unlock_irqrestore(&consolelock, flags);
-}
-
-static void hvc_config_event(struct HvLpEvent *event)
-{
-       struct viocharlpevent *cevent = (struct viocharlpevent *)event;
-
-       if (cevent->data[0] == 0x01)
-               printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
-                      cevent->data[1], cevent->data[2],
-                      cevent->data[3], cevent->data[4]);
-       else
-               printk(KERN_WARNING "hvc: unknown config event\n");
-}
-
-static void hvc_handle_event(struct HvLpEvent *event)
-{
-       int charminor;
-
-       if (event == NULL)
-               return;
-
-       charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
-       switch (charminor) {
-       case viocharopen:
-               hvc_open_event(event);
-               break;
-       case viocharclose:
-               hvc_close_event(event);
-               break;
-       case viochardata:
-               hvc_data_event(event);
-               break;
-       case viocharack:
-               hvc_ack_event(event);
-               break;
-       case viocharconfig:
-               hvc_config_event(event);
-               break;
-       default:
-               if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
-                       event->xRc = HvLpEvent_Rc_InvalidSubtype;
-                       HvCallEvent_ackLpEvent(event);
-               }
-       }
-}
-
-static int __init send_open(HvLpIndex remoteLp, void *sem)
-{
-       return HvCallEvent_signalLpEventFast(remoteLp,
-                       HvLpEvent_Type_VirtualIo,
-                       viomajorsubtype_chario | viocharopen,
-                       HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-                       viopath_sourceinst(remoteLp),
-                       viopath_targetinst(remoteLp),
-                       (u64)(unsigned long)sem, VIOVERSION << 16,
-                       0, 0, 0, 0);
-}
-
-static int __init hvc_vio_init(void)
-{
-       atomic_t wait_flag;
-       int rc;
-
-       if (!firmware_has_feature(FW_FEATURE_ISERIES))
-               return -EIO;
-
-       /* +2 for fudge */
-       rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
-                       viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
-       if (rc)
-               printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
-
-       if (viopath_hostLp == HvLpIndexInvalid)
-               vio_set_hostlp();
-
-       /*
-        * And if the primary is not the same as the hosting LP, open to the
-        * hosting lp
-        */
-       if ((viopath_hostLp != HvLpIndexInvalid) &&
-           (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
-               printk(KERN_INFO "hvc: open path to hosting (%d)\n",
-                               viopath_hostLp);
-               rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
-                               VIOCHAR_WINDOW + 2);    /* +2 for fudge */
-               if (rc)
-                       printk(KERN_WARNING
-                               "error opening to partition %d: %d\n",
-                               viopath_hostLp, rc);
-       }
-
-       if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
-               printk(KERN_WARNING
-                       "hvc: error seting handler for console events!\n");
-
-       /*
-        * First, try to open the console to the hosting lp.
-        * Wait on a semaphore for the response.
-        */
-       atomic_set(&wait_flag, 0);
-       if ((viopath_isactive(viopath_hostLp)) &&
-           (send_open(viopath_hostLp, &wait_flag) == 0)) {
-               printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
-               while (atomic_read(&wait_flag) == 0)
-                       mb();
-               atomic_set(&wait_flag, 0);
-       }
-
-       /*
-        * If we don't have an active console, try the primary
-        */
-       if ((!viopath_isactive(port_info[0].lp)) &&
-           (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
-           (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
-               printk(KERN_INFO "hvc: opening console to primary partition\n");
-               while (atomic_read(&wait_flag) == 0)
-                       mb();
-       }
-
-       /* Register as a vio device to receive callbacks */
-       rc = vio_register_driver(&hvc_vio_driver);
-
-       return rc;
-}
-module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-
-static void __exit hvc_vio_exit(void)
-{
-       vio_unregister_driver(&hvc_vio_driver);
-}
-module_exit(hvc_vio_exit);
-
-/* the device tree order defines our numbering */
-static int __init hvc_find_vtys(void)
-{
-       struct device_node *vty;
-       int num_found = 0;
-
-       for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
-                       vty = of_find_node_by_name(vty, "vty")) {
-               const uint32_t *vtermno;
-
-               /* We have statically defined space for only a certain number
-                * of console adapters.
-                */
-               if ((num_found >= MAX_NR_HVC_CONSOLES) ||
-                               (num_found >= VTTY_PORTS)) {
-                       of_node_put(vty);
-                       break;
-               }
-
-               vtermno = of_get_property(vty, "reg", NULL);
-               if (!vtermno)
-                       continue;
-
-               if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
-                       continue;
-
-               if (num_found == 0)
-                       add_preferred_console("hvc", 0, NULL);
-               hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
-               ++num_found;
-       }
-
-       return num_found;
-}
-console_initcall(hvc_find_vtys);
index 4c9b13e..7222827 100644 (file)
@@ -36,7 +36,7 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
 {
        int i;
 
-       for (i = 0; i < count; i++)
+       for (i = 0; i < count && udbg_putc; i++)
                udbg_putc(buf[i]);
 
        return i;
@@ -67,6 +67,9 @@ static int __init hvc_udbg_init(void)
 {
        struct hvc_struct *hp;
 
+       if (!udbg_putc)
+               return -ENODEV;
+
        BUG_ON(hvc_udbg_dev);
 
        hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
@@ -88,6 +91,9 @@ module_exit(hvc_udbg_exit);
 
 static int __init hvc_udbg_console_init(void)
 {
+       if (!udbg_putc)
+               return -ENODEV;
+
        hvc_instantiate(0, 0, &hvc_udbg_ops);
        add_preferred_console("hvc", 0, NULL);
 
index fc3c3ad..3a0d53d 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
 #include <asm/prom.h>
-#include <asm/firmware.h>
 #include <asm/hvsi.h>
 #include <asm/udbg.h>
 
@@ -322,9 +321,6 @@ static int __init hvc_vio_init(void)
 {
        int rc;
 
-       if (firmware_has_feature(FW_FEATURE_ISERIES))
-               return -EIO;
-
        /* Register as a vio device to receive callbacks */
        rc = vio_register_driver(&hvc_vio_driver);
 
index 76e7764..665beb6 100644 (file)
@@ -853,7 +853,7 @@ config SERIAL_MPC52xx_CONSOLE_BAUD
 
 config SERIAL_ICOM
        tristate "IBM Multiport Serial Adapter"
-       depends on PCI && (PPC_ISERIES || PPC_PSERIES)
+       depends on PCI && PPC_PSERIES
        select SERIAL_CORE
        select FW_LOADER
        help
index 9e186f3..cefa0c8 100644 (file)
@@ -50,7 +50,6 @@
 static const struct file_operations default_file_operations;
 static struct vfsmount *usbfs_mount;
 static int usbfs_mount_count;  /* = 0 */
-static int ignore_mount = 0;
 
 static struct dentry *devices_usbfs_dentry;
 static int num_buses;  /* = 0 */
@@ -256,7 +255,7 @@ static int remount(struct super_block *sb, int *flags, char *data)
         * i.e. it's a simple_pin_fs from create_special_files,
         * then ignore it.
         */
-       if (ignore_mount)
+       if (*flags & MS_KERNMOUNT)
                return 0;
 
        if (parse_options(sb, data)) {
@@ -454,7 +453,6 @@ static const struct super_operations usbfs_ops = {
 static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
-       struct dentry *root;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -462,19 +460,11 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op = &usbfs_ops;
        sb->s_time_gran = 1;
        inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
-
-       if (!inode) {
-               dbg("%s: could not get inode!",__func__);
-               return -ENOMEM;
-       }
-
-       root = d_alloc_root(inode);
-       if (!root) {
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root) {
                dbg("%s: could not get root dentry!",__func__);
-               iput(inode);
                return -ENOMEM;
        }
-       sb->s_root = root;
        return 0;
 }
 
@@ -591,11 +581,6 @@ static int create_special_files (void)
        struct dentry *parent;
        int retval;
 
-       /* the simple_pin_fs calls will call remount with no options
-        * without this flag that would overwrite the real mount options (if any)
-        */
-       ignore_mount = 1;
-
        /* create the devices special file */
        retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
        if (retval) {
@@ -603,8 +588,6 @@ static int create_special_files (void)
                goto exit;
        }
 
-       ignore_mount = 0;
-
        parent = usbfs_mount->mnt_root;
        devices_usbfs_dentry = fs_create_file ("devices",
                                               listmode | S_IFREG, parent,
index 7f445ec..1cbba70 100644 (file)
@@ -1063,13 +1063,9 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
                                  &simple_dir_operations,
                                  &simple_dir_inode_operations,
                                  &data->perms);
-       if (unlikely(!inode))
+       sb->s_root = d_make_root(inode);
+       if (unlikely(!sb->s_root))
                goto Enomem;
-       sb->s_root = d_alloc_root(inode);
-       if (unlikely(!sb->s_root)) {
-               iput(inode);
-               goto Enomem;
-       }
 
        /* EP0 file */
        if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
index 4f18a0e..8793f32 100644 (file)
@@ -1571,20 +1571,18 @@ delegate:
 
 static void destroy_ep_files (struct dev_data *dev)
 {
-       struct list_head        *entry, *tmp;
-
        DBG (dev, "%s %d\n", __func__, dev->state);
 
        /* dev->state must prevent interference */
 restart:
        spin_lock_irq (&dev->lock);
-       list_for_each_safe (entry, tmp, &dev->epfiles) {
+       while (!list_empty(&dev->epfiles)) {
                struct ep_data  *ep;
                struct inode    *parent;
                struct dentry   *dentry;
 
                /* break link to FS */
-               ep = list_entry (entry, struct ep_data, epfiles);
+               ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
                list_del_init (&ep->epfiles);
                dentry = ep->dentry;
                ep->dentry = NULL;
@@ -1607,8 +1605,7 @@ restart:
                dput (dentry);
                mutex_unlock (&parent->i_mutex);
 
-               /* fds may still be open */
-               goto restart;
+               spin_lock_irq (&dev->lock);
        }
        spin_unlock_irq (&dev->lock);
 }
@@ -2061,10 +2058,8 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
        if (!inode)
                goto Enomem;
        inode->i_op = &simple_dir_inode_operations;
-       if (!(sb->s_root = d_alloc_root (inode))) {
-               iput(inode);
+       if (!(sb->s_root = d_make_root (inode)))
                goto Enomem;
-       }
 
        /* the ep0 file is named after the controller we expect;
         * user mode code can use it for sanity checks, like we do.
index df9e8f0..7e9e8f4 100644 (file)
@@ -1039,7 +1039,7 @@ config LANTIQ_WDT
 
 config GEF_WDT
        tristate "GE Watchdog Timer"
-       depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
+       depends on GE_FPGA
        ---help---
          Watchdog timer found in a number of GE single board computers.
 
index 1964f98..b85efa7 100644 (file)
@@ -594,21 +594,21 @@ static int __init init_v9fs(void)
        int err;
        pr_info("Installing v9fs 9p2000 file system support\n");
        /* TODO: Setup list of registered trasnport modules */
-       err = register_filesystem(&v9fs_fs_type);
-       if (err < 0) {
-               pr_err("Failed to register filesystem\n");
-               return err;
-       }
 
        err = v9fs_cache_register();
        if (err < 0) {
                pr_err("Failed to register v9fs for caching\n");
-               goto out_fs_unreg;
+               return err;
        }
 
        err = v9fs_sysfs_init();
        if (err < 0) {
                pr_err("Failed to register with sysfs\n");
+               goto out_cache;
+       }
+       err = register_filesystem(&v9fs_fs_type);
+       if (err < 0) {
+               pr_err("Failed to register filesystem\n");
                goto out_sysfs_cleanup;
        }
 
@@ -617,8 +617,8 @@ static int __init init_v9fs(void)
 out_sysfs_cleanup:
        v9fs_sysfs_cleanup();
 
-out_fs_unreg:
-       unregister_filesystem(&v9fs_fs_type);
+out_cache:
+       v9fs_cache_unregister();
 
        return err;
 }
index 7b0cd87..10b7d3c 100644 (file)
@@ -155,9 +155,8 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                goto release_sb;
        }
 
-       root = d_alloc_root(inode);
+       root = d_make_root(inode);
        if (!root) {
-               iput(inode);
                retval = -ENOMEM;
                goto release_sb;
        }
index aa19526..f95ae3a 100644 (file)
@@ -214,6 +214,7 @@ source "fs/minix/Kconfig"
 source "fs/omfs/Kconfig"
 source "fs/hpfs/Kconfig"
 source "fs/qnx4/Kconfig"
+source "fs/qnx6/Kconfig"
 source "fs/romfs/Kconfig"
 source "fs/pstore/Kconfig"
 source "fs/sysv/Kconfig"
index 93804d4..2fb9779 100644 (file)
@@ -102,6 +102,7 @@ obj-$(CONFIG_UBIFS_FS)              += ubifs/
 obj-$(CONFIG_AFFS_FS)          += affs/
 obj-$(CONFIG_ROMFS_FS)         += romfs/
 obj-$(CONFIG_QNX4FS_FS)                += qnx4/
+obj-$(CONFIG_QNX6FS_FS)                += qnx6/
 obj-$(CONFIG_AUTOFS4_FS)       += autofs4/
 obj-$(CONFIG_ADFS_FS)          += adfs/
 obj-$(CONFIG_FUSE_FS)          += fuse/
index 8e3b36a..06fdcc9 100644 (file)
@@ -483,10 +483,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_d_op = &adfs_dentry_operations;
        root = adfs_iget(sb, &root_obj);
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                int i;
-               iput(root);
                for (i = 0; i < asb->s_map_size; i++)
                        brelse(asb->s_map[i].dm_bh);
                kfree(asb->s_map);
index 8ba73fe..0782653 100644 (file)
@@ -473,7 +473,7 @@ got_root:
        root_inode = affs_iget(sb, root_block);
        if (IS_ERR(root_inode)) {
                ret = PTR_ERR(root_inode);
-               goto out_error_noinode;
+               goto out_error;
        }
 
        if (AFFS_SB(sb)->s_flags & SF_INTL)
@@ -481,7 +481,7 @@ got_root:
        else
                sb->s_d_op = &affs_dentry_operations;
 
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (!sb->s_root) {
                printk(KERN_ERR "AFFS: Get root inode failed\n");
                goto out_error;
@@ -494,9 +494,6 @@ got_root:
         * Begin the cascaded cleanup ...
         */
 out_error:
-       if (root_inode)
-               iput(root_inode);
-out_error_noinode:
        kfree(sbi->s_bitmap);
        affs_brelse(root_bh);
        kfree(sbi->s_prefix);
index 983ec59..f02b31e 100644 (file)
@@ -301,7 +301,6 @@ static int afs_fill_super(struct super_block *sb,
 {
        struct afs_super_info *as = sb->s_fs_info;
        struct afs_fid fid;
-       struct dentry *root = NULL;
        struct inode *inode = NULL;
        int ret;
 
@@ -327,18 +326,16 @@ static int afs_fill_super(struct super_block *sb,
                set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
 
        ret = -ENOMEM;
-       root = d_alloc_root(inode);
-       if (!root)
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
                goto error;
 
        sb->s_d_op = &afs_fs_dentry_operations;
-       sb->s_root = root;
 
        _leave(" = 0");
        return 0;
 
 error:
-       iput(inode);
        _leave(" = %d", ret);
        return ret;
 }
index 5b600cb..c7acaf3 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -199,16 +199,7 @@ static int aio_setup_ring(struct kioctx *ctx)
 static void ctx_rcu_free(struct rcu_head *head)
 {
        struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
-       unsigned nr_events = ctx->max_reqs;
-
        kmem_cache_free(kioctx_cachep, ctx);
-
-       if (nr_events) {
-               spin_lock(&aio_nr_lock);
-               BUG_ON(aio_nr - nr_events > aio_nr);
-               aio_nr -= nr_events;
-               spin_unlock(&aio_nr_lock);
-       }
 }
 
 /* __put_ioctx
@@ -217,13 +208,19 @@ static void ctx_rcu_free(struct rcu_head *head)
  */
 static void __put_ioctx(struct kioctx *ctx)
 {
+       unsigned nr_events = ctx->max_reqs;
        BUG_ON(ctx->reqs_active);
 
-       cancel_delayed_work(&ctx->wq);
-       cancel_work_sync(&ctx->wq.work);
+       cancel_delayed_work_sync(&ctx->wq);
        aio_free_ring(ctx);
        mmdrop(ctx->mm);
        ctx->mm = NULL;
+       if (nr_events) {
+               spin_lock(&aio_nr_lock);
+               BUG_ON(aio_nr - nr_events > aio_nr);
+               aio_nr -= nr_events;
+               spin_unlock(&aio_nr_lock);
+       }
        pr_debug("__put_ioctx: freeing %p\n", ctx);
        call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
@@ -247,7 +244,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
 {
        struct mm_struct *mm;
        struct kioctx *ctx;
-       int did_sync = 0;
+       int err = -ENOMEM;
 
        /* Prevent overflows */
        if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
@@ -256,7 +253,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
                return ERR_PTR(-EINVAL);
        }
 
-       if ((unsigned long)nr_events > aio_max_nr)
+       if (!nr_events || (unsigned long)nr_events > aio_max_nr)
                return ERR_PTR(-EAGAIN);
 
        ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL);
@@ -280,25 +277,14 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
                goto out_freectx;
 
        /* limit the number of system wide aios */
-       do {
-               spin_lock_bh(&aio_nr_lock);
-               if (aio_nr + nr_events > aio_max_nr ||
-                   aio_nr + nr_events < aio_nr)
-                       ctx->max_reqs = 0;
-               else
-                       aio_nr += ctx->max_reqs;
-               spin_unlock_bh(&aio_nr_lock);
-               if (ctx->max_reqs || did_sync)
-                       break;
-
-               /* wait for rcu callbacks to have completed before giving up */
-               synchronize_rcu();
-               did_sync = 1;
-               ctx->max_reqs = nr_events;
-       } while (1);
-
-       if (ctx->max_reqs == 0)
+       spin_lock(&aio_nr_lock);
+       if (aio_nr + nr_events > aio_max_nr ||
+           aio_nr + nr_events < aio_nr) {
+               spin_unlock(&aio_nr_lock);
                goto out_cleanup;
+       }
+       aio_nr += ctx->max_reqs;
+       spin_unlock(&aio_nr_lock);
 
        /* now link into global list. */
        spin_lock(&mm->ioctx_lock);
@@ -310,16 +296,13 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
        return ctx;
 
 out_cleanup:
-       __put_ioctx(ctx);
-       return ERR_PTR(-EAGAIN);
-
+       err = -EAGAIN;
+       aio_free_ring(ctx);
 out_freectx:
        mmdrop(mm);
        kmem_cache_free(kioctx_cachep, ctx);
-       ctx = ERR_PTR(-ENOMEM);
-
-       dprintk("aio: error allocating ioctx %p\n", ctx);
-       return ctx;
+       dprintk("aio: error allocating ioctx %d\n", err);
+       return ERR_PTR(err);
 }
 
 /* aio_cancel_all
@@ -407,10 +390,6 @@ void exit_aio(struct mm_struct *mm)
                aio_cancel_all(ctx);
 
                wait_for_all_aios(ctx);
-               /*
-                * Ensure we don't leave the ctx on the aio_wq
-                */
-               cancel_work_sync(&ctx->wq.work);
 
                if (1 != atomic_read(&ctx->users))
                        printk(KERN_DEBUG
@@ -920,7 +899,7 @@ static void aio_kick_handler(struct work_struct *work)
        unuse_mm(mm);
        set_fs(oldfs);
        /*
-        * we're in a worker thread already, don't use queue_delayed_work,
+        * we're in a worker thread already; no point using non-zero delay
         */
        if (requeue)
                queue_delayed_work(aio_wq, &ctx->wq, 0);
index f11e43e..28d39fb 100644 (file)
@@ -39,19 +39,6 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
        .d_dname        = anon_inodefs_dname,
 };
 
-static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
-                               int flags, const char *dev_name, void *data)
-{
-       return mount_pseudo(fs_type, "anon_inode:", NULL,
-                       &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
-}
-
-static struct file_system_type anon_inode_fs_type = {
-       .name           = "anon_inodefs",
-       .mount          = anon_inodefs_mount,
-       .kill_sb        = kill_anon_super,
-};
-
 /*
  * nop .set_page_dirty method so that people can use .page_mkwrite on
  * anon inodes.
@@ -65,6 +52,62 @@ static const struct address_space_operations anon_aops = {
        .set_page_dirty = anon_set_page_dirty,
 };
 
+/*
+ * A single inode exists for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes have no associated per-instance data, so we need
+ * only allocate one of them.
+ */
+static struct inode *anon_inode_mkinode(struct super_block *s)
+{
+       struct inode *inode = new_inode_pseudo(s);
+
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       inode->i_ino = get_next_ino();
+       inode->i_fop = &anon_inode_fops;
+
+       inode->i_mapping->a_ops = &anon_aops;
+
+       /*
+        * Mark the inode dirty from the very beginning,
+        * that way it will never be moved to the dirty
+        * list because mark_inode_dirty() will think
+        * that it already _is_ on the dirty list.
+        */
+       inode->i_state = I_DIRTY;
+       inode->i_mode = S_IRUSR | S_IWUSR;
+       inode->i_uid = current_fsuid();
+       inode->i_gid = current_fsgid();
+       inode->i_flags |= S_PRIVATE;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       return inode;
+}
+
+static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
+                               int flags, const char *dev_name, void *data)
+{
+       struct dentry *root;
+       root = mount_pseudo(fs_type, "anon_inode:", NULL,
+                       &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
+       if (!IS_ERR(root)) {
+               struct super_block *s = root->d_sb;
+               anon_inode_inode = anon_inode_mkinode(s);
+               if (IS_ERR(anon_inode_inode)) {
+                       dput(root);
+                       deactivate_locked_super(s);
+                       root = ERR_CAST(anon_inode_inode);
+               }
+       }
+       return root;
+}
+
+static struct file_system_type anon_inode_fs_type = {
+       .name           = "anon_inodefs",
+       .mount          = anon_inodefs_mount,
+       .kill_sb        = kill_anon_super,
+};
+
 /**
  * anon_inode_getfile - creates a new file instance by hooking it up to an
  *                      anonymous inode, and a dentry that describe the "class"
@@ -180,38 +223,6 @@ err_put_unused_fd:
 }
 EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
-/*
- * A single inode exists for all anon_inode files. Contrary to pipes,
- * anon_inode inodes have no associated per-instance data, so we need
- * only allocate one of them.
- */
-static struct inode *anon_inode_mkinode(void)
-{
-       struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb);
-
-       if (!inode)
-               return ERR_PTR(-ENOMEM);
-
-       inode->i_ino = get_next_ino();
-       inode->i_fop = &anon_inode_fops;
-
-       inode->i_mapping->a_ops = &anon_aops;
-
-       /*
-        * Mark the inode dirty from the very beginning,
-        * that way it will never be moved to the dirty
-        * list because mark_inode_dirty() will think
-        * that it already _is_ on the dirty list.
-        */
-       inode->i_state = I_DIRTY;
-       inode->i_mode = S_IRUSR | S_IWUSR;
-       inode->i_uid = current_fsuid();
-       inode->i_gid = current_fsgid();
-       inode->i_flags |= S_PRIVATE;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       return inode;
-}
-
 static int __init anon_inode_init(void)
 {
        int error;
@@ -224,16 +235,8 @@ static int __init anon_inode_init(void)
                error = PTR_ERR(anon_inode_mnt);
                goto err_unregister_filesystem;
        }
-       anon_inode_inode = anon_inode_mkinode();
-       if (IS_ERR(anon_inode_inode)) {
-               error = PTR_ERR(anon_inode_inode);
-               goto err_mntput;
-       }
-
        return 0;
 
-err_mntput:
-       kern_unmount(anon_inode_mnt);
 err_unregister_filesystem:
        unregister_filesystem(&anon_inode_fs_type);
 err_exit:
index c038727..cddc74b 100644 (file)
@@ -31,11 +31,11 @@ static int __init init_autofs4_fs(void)
 {
        int err;
 
+       autofs_dev_ioctl_init();
+
        err = register_filesystem(&autofs_fs_type);
        if (err)
-               return err;
-
-       autofs_dev_ioctl_init();
+               autofs_dev_ioctl_exit();
 
        return err;
 }
index 06858d9..d8dc002 100644 (file)
@@ -247,12 +247,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        if (!ino)
                goto fail_free;
        root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
-       if (!root_inode)
-               goto fail_ino;
-
-       root = d_alloc_root(root_inode);
+       root = d_make_root(root_inode);
        if (!root)
-               goto fail_iput;
+               goto fail_ino;
        pipe = NULL;
 
        root->d_fsdata = ino;
@@ -317,9 +314,6 @@ fail_fput:
 fail_dput:
        dput(root);
        goto fail_free;
-fail_iput:
-       printk("autofs: get root dentry failed\n");
-       iput(root_inode);
 fail_ino:
        kfree(ino);
 fail_free:
index 6e6d536..e18da23 100644 (file)
@@ -852,9 +852,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
                ret = PTR_ERR(root);
                goto unacquire_priv_sbp;
        }
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
-               iput(root);
                befs_error(sb, "get root inode failed");
                goto unacquire_priv_sbp;
        }
index b0391bc..e23dc7c 100644 (file)
@@ -367,9 +367,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
                ret = PTR_ERR(inode);
                goto out2;
        }
-       s->s_root = d_alloc_root(inode);
+       s->s_root = d_make_root(inode);
        if (!s->s_root) {
-               iput(inode);
                ret = -ENOMEM;
                goto out2;
        }
index 1ff9405..4d5e6d2 100644 (file)
@@ -267,7 +267,6 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        }
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
 
        if (N_MAGIC(ex) == OMAGIC) {
                unsigned long text_addr, map_size;
@@ -454,7 +453,8 @@ out:
 
 static int __init init_aout_binfmt(void)
 {
-       return register_binfmt(&aout_format);
+       register_binfmt(&aout_format);
+       return 0;
 }
 
 static void __exit exit_aout_binfmt(void)
index 07d096c..81878b7 100644 (file)
@@ -712,7 +712,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto out_free_dentry;
 
        /* OK, This is the point of no return */
-       current->flags &= ~PF_FORKNOEXEC;
        current->mm->def_flags = def_flags;
 
        /* Do this immediately, since STACK_TOP as used in setup_arg_pages
@@ -934,7 +933,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
        retval = create_elf_tables(bprm, &loc->elf_ex,
                          load_addr, interp_load_addr);
        if (retval < 0) {
@@ -2077,7 +2075,8 @@ out:
 
 static int __init init_elf_binfmt(void)
 {
-       return register_binfmt(&elf_format);
+       register_binfmt(&elf_format);
+       return 0;
 }
 
 static void __exit exit_elf_binfmt(void)
index 30745f4..c64bf5e 100644 (file)
@@ -91,7 +91,8 @@ static struct linux_binfmt elf_fdpic_format = {
 
 static int __init init_elf_fdpic_binfmt(void)
 {
-       return register_binfmt(&elf_fdpic_format);
+       register_binfmt(&elf_fdpic_format);
+       return 0;
 }
 
 static void __exit exit_elf_fdpic_binfmt(void)
@@ -334,8 +335,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
        current->mm->context.exec_fdpic_loadmap = 0;
        current->mm->context.interp_fdpic_loadmap = 0;
 
-       current->flags &= ~PF_FORKNOEXEC;
-
 #ifdef CONFIG_MMU
        elf_fdpic_arch_lay_out_mm(&exec_params,
                                  &interp_params,
@@ -413,7 +412,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
 #endif
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
        if (create_elf_fdpic_tables(bprm, current->mm,
                                    &exec_params, &interp_params) < 0)
                goto error_kill;
index b8e8b0a..2790c7e 100644 (file)
@@ -100,7 +100,8 @@ static struct linux_binfmt em86_format = {
 
 static int __init init_em86_binfmt(void)
 {
-       return register_binfmt(&em86_format);
+       register_binfmt(&em86_format);
+       return 0;
 }
 
 static void __exit exit_em86_binfmt(void)
index 1bffbe0..04f61f0 100644 (file)
@@ -902,7 +902,6 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                                                libinfo.lib_list[j].start_data:UNLOADED_LIB;
 
        install_exec_creds(bprm);
-       current->flags &= ~PF_FORKNOEXEC;
 
        set_binfmt(&flat_format);
 
@@ -950,7 +949,8 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
 static int __init init_flat_binfmt(void)
 {
-       return register_binfmt(&flat_format);
+       register_binfmt(&flat_format);
+       return 0;
 }
 
 /****************************************************************************/
index a9198df..1ffb603 100644 (file)
@@ -726,11 +726,8 @@ static struct file_system_type bm_fs_type = {
 static int __init init_misc_binfmt(void)
 {
        int err = register_filesystem(&bm_fs_type);
-       if (!err) {
-               err = insert_binfmt(&misc_format);
-               if (err)
-                       unregister_filesystem(&bm_fs_type);
-       }
+       if (!err)
+               insert_binfmt(&misc_format);
        return err;
 }
 
index 396a988..d3b8c1f 100644 (file)
@@ -105,7 +105,8 @@ static struct linux_binfmt script_format = {
 
 static int __init init_script_binfmt(void)
 {
-       return register_binfmt(&script_format);
+       register_binfmt(&script_format);
+       return 0;
 }
 
 static void __exit exit_script_binfmt(void)
index cc8560f..e4fc746 100644 (file)
@@ -225,7 +225,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                goto out_free;
 
        /* OK, This is the point of no return */
-       current->flags &= ~PF_FORKNOEXEC;
        current->personality = PER_HPUX;
        setup_new_exec(bprm);
 
@@ -289,7 +288,8 @@ static int load_som_library(struct file *f)
 
 static int __init init_som_binfmt(void)
 {
-       return register_binfmt(&som_format);
+       register_binfmt(&som_format);
+       return 0;
 }
 
 static void __exit exit_som_binfmt(void)
index 3ce97b2..81df3fe 100644 (file)
@@ -629,7 +629,6 @@ static int btrfs_fill_super(struct super_block *sb,
                            void *data, int silent)
 {
        struct inode *inode;
-       struct dentry *root_dentry;
        struct btrfs_fs_info *fs_info = btrfs_sb(sb);
        struct btrfs_key key;
        int err;
@@ -660,15 +659,12 @@ static int btrfs_fill_super(struct super_block *sb,
                goto fail_close;
        }
 
-       root_dentry = d_alloc_root(inode);
-       if (!root_dentry) {
-               iput(inode);
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root) {
                err = -ENOMEM;
                goto fail_close;
        }
 
-       sb->s_root = root_dentry;
-
        save_mount_options(sb, data);
        cleancache_init_fs(sb);
        sb->s_flags |= MS_ACTIVE;
index a0358c2..7f0771d 100644 (file)
@@ -646,7 +646,8 @@ lookup_again:
                 * (this is used to keep track of culling, and atimes are only
                 * updated by read, write and readdir but not lookup or
                 * open) */
-               touch_atime(cache->mnt, next);
+               path.dentry = next;
+               touch_atime(&path);
        }
 
        /* open a file interface onto a data file */
index 00de2c9..256f852 100644 (file)
@@ -655,9 +655,8 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                dout("open_root_inode success\n");
                if (ceph_ino(inode) == CEPH_INO_ROOT &&
                    fsc->sb->s_root == NULL) {
-                       root = d_alloc_root(inode);
+                       root = d_make_root(inode);
                        if (!root) {
-                               iput(inode);
                                root = ERR_PTR(-ENOMEM);
                                goto out;
                        }
index c1b2544..3cc1b25 100644 (file)
@@ -556,6 +556,7 @@ init_cifs_idmap(void)
 
        /* instruct request_key() to use this special keyring as a cache for
         * the results it looks up */
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        root_cred = cred;
index b1fd382..418fc42 100644 (file)
@@ -119,12 +119,10 @@ cifs_read_super(struct super_block *sb)
 
        if (IS_ERR(inode)) {
                rc = PTR_ERR(inode);
-               inode = NULL;
                goto out_no_root;
        }
 
-       sb->s_root = d_alloc_root(inode);
-
+       sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                rc = -ENOMEM;
                goto out_no_root;
@@ -147,9 +145,6 @@ cifs_read_super(struct super_block *sb)
 
 out_no_root:
        cERROR(1, "cifs_read_super: get root inode failed");
-       if (inode)
-               iput(inode);
-
        return rc;
 }
 
index 5e2e1b3..05156c1 100644 (file)
@@ -208,13 +208,12 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
         if (IS_ERR(root)) {
                error = PTR_ERR(root);
                printk("Failure of coda_cnode_make for root: error %d\n", error);
-               root = NULL;
                goto error;
        } 
 
        printk("coda_read_super: rootinode is %ld dev %s\n", 
               root->i_ino, root->i_sb->s_id);
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                error = -EINVAL;
                goto error;
@@ -222,9 +221,6 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 
 error:
-       if (root)
-               iput(root);
-
        mutex_lock(&vc->vc_mutex);
        bdi_destroy(&vc->bdi);
        vc->vc_sb = NULL;
index ede857d..b5f0a3b 100644 (file)
@@ -58,12 +58,11 @@ struct configfs_dirent {
 extern struct mutex configfs_symlink_mutex;
 extern spinlock_t configfs_dirent_lock;
 
-extern struct vfsmount * configfs_mount;
 extern struct kmem_cache *configfs_dir_cachep;
 
 extern int configfs_is_root(struct config_item *item);
 
-extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *);
+extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, struct super_block *);
 extern int configfs_create(struct dentry *, umode_t mode, int (*init)(struct inode *));
 extern int configfs_inode_init(void);
 extern void configfs_inode_exit(void);
@@ -80,15 +79,15 @@ extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
 extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
 extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
 
-extern int configfs_pin_fs(void);
+extern struct dentry *configfs_pin_fs(void);
 extern void configfs_release_fs(void);
 
 extern struct rw_semaphore configfs_rename_sem;
-extern struct super_block * configfs_sb;
 extern const struct file_operations configfs_dir_operations;
 extern const struct file_operations configfs_file_operations;
 extern const struct file_operations bin_fops;
 extern const struct inode_operations configfs_dir_inode_operations;
+extern const struct inode_operations configfs_root_inode_operations;
 extern const struct inode_operations configfs_symlink_inode_operations;
 extern const struct dentry_operations configfs_dentry_ops;
 
index 5ddd7eb..7e6c52d 100644 (file)
@@ -264,11 +264,13 @@ static int init_symlink(struct inode * inode)
        return 0;
 }
 
-static int create_dir(struct config_item * k, struct dentry * p,
-                     struct dentry * d)
+static int create_dir(struct config_item *k, struct dentry *d)
 {
        int error;
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+       struct dentry *p = d->d_parent;
+
+       BUG_ON(!k);
 
        error = configfs_dirent_exists(p->d_fsdata, d->d_name.name);
        if (!error)
@@ -304,19 +306,7 @@ static int create_dir(struct config_item * k, struct dentry * p,
 
 static int configfs_create_dir(struct config_item * item, struct dentry *dentry)
 {
-       struct dentry * parent;
-       int error = 0;
-
-       BUG_ON(!item);
-
-       if (item->ci_parent)
-               parent = item->ci_parent->ci_dentry;
-       else if (configfs_mount)
-               parent = configfs_mount->mnt_root;
-       else
-               return -EFAULT;
-
-       error = create_dir(item,parent,dentry);
+       int error = create_dir(item, dentry);
        if (!error)
                item->ci_dentry = dentry;
        return error;
@@ -1079,23 +1069,24 @@ int configfs_depend_item(struct configfs_subsystem *subsys,
        int ret;
        struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
        struct config_item *s_item = &subsys->su_group.cg_item;
+       struct dentry *root;
 
        /*
         * Pin the configfs filesystem.  This means we can safely access
         * the root of the configfs filesystem.
         */
-       ret = configfs_pin_fs();
-       if (ret)
-               return ret;
+       root = configfs_pin_fs();
+       if (IS_ERR(root))
+               return PTR_ERR(root);
 
        /*
         * Next, lock the root directory.  We're going to check that the
         * subsystem is really registered, and so we need to lock out
         * configfs_[un]register_subsystem().
         */
-       mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
+       mutex_lock(&root->d_inode->i_mutex);
 
-       root_sd = configfs_sb->s_root->d_fsdata;
+       root_sd = root->d_fsdata;
 
        list_for_each_entry(p, &root_sd->s_children, s_sibling) {
                if (p->s_type & CONFIGFS_DIR) {
@@ -1129,7 +1120,7 @@ int configfs_depend_item(struct configfs_subsystem *subsys,
 out_unlock_dirent_lock:
        spin_unlock(&configfs_dirent_lock);
 out_unlock_fs:
-       mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+       mutex_unlock(&root->d_inode->i_mutex);
 
        /*
         * If we succeeded, the fs is pinned via other methods.  If not,
@@ -1183,11 +1174,6 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        struct module *subsys_owner = NULL, *new_item_owner = NULL;
        char *name;
 
-       if (dentry->d_parent == configfs_sb->s_root) {
-               ret = -EPERM;
-               goto out;
-       }
-
        sd = dentry->d_parent->d_fsdata;
 
        /*
@@ -1359,9 +1345,6 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
        struct module *subsys_owner = NULL, *dead_item_owner = NULL;
        int ret;
 
-       if (dentry->d_parent == configfs_sb->s_root)
-               return -EPERM;
-
        sd = dentry->d_fsdata;
        if (sd->s_type & CONFIGFS_USET_DEFAULT)
                return -EPERM;
@@ -1459,6 +1442,11 @@ const struct inode_operations configfs_dir_inode_operations = {
        .setattr        = configfs_setattr,
 };
 
+const struct inode_operations configfs_root_inode_operations = {
+       .lookup         = configfs_lookup,
+       .setattr        = configfs_setattr,
+};
+
 #if 0
 int configfs_rename_dir(struct config_item * item, const char *new_name)
 {
@@ -1546,6 +1534,7 @@ static inline unsigned char dt_type(struct configfs_dirent *sd)
 static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_path.dentry;
+       struct super_block *sb = dentry->d_sb;
        struct configfs_dirent * parent_sd = dentry->d_fsdata;
        struct configfs_dirent *cursor = filp->private_data;
        struct list_head *p, *q = &cursor->s_sibling;
@@ -1608,7 +1597,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
                                        ino = inode->i_ino;
                                spin_unlock(&configfs_dirent_lock);
                                if (!inode)
-                                       ino = iunique(configfs_sb, 2);
+                                       ino = iunique(sb, 2);
 
                                if (filldir(dirent, name, len, filp->f_pos, ino,
                                                 dt_type(next)) < 0)
@@ -1680,27 +1669,27 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
        struct config_group *group = &subsys->su_group;
        struct qstr name;
        struct dentry *dentry;
+       struct dentry *root;
        struct configfs_dirent *sd;
 
-       err = configfs_pin_fs();
-       if (err)
-               return err;
+       root = configfs_pin_fs();
+       if (IS_ERR(root))
+               return PTR_ERR(root);
 
        if (!group->cg_item.ci_name)
                group->cg_item.ci_name = group->cg_item.ci_namebuf;
 
-       sd = configfs_sb->s_root->d_fsdata;
+       sd = root->d_fsdata;
        link_group(to_config_group(sd->s_element), group);
 
-       mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
-                       I_MUTEX_PARENT);
+       mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
 
        name.name = group->cg_item.ci_name;
        name.len = strlen(name.name);
        name.hash = full_name_hash(name.name, name.len);
 
        err = -ENOMEM;
-       dentry = d_alloc(configfs_sb->s_root, &name);
+       dentry = d_alloc(root, &name);
        if (dentry) {
                d_add(dentry, NULL);
 
@@ -1717,7 +1706,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                }
        }
 
-       mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+       mutex_unlock(&root->d_inode->i_mutex);
 
        if (err) {
                unlink_group(group);
@@ -1731,13 +1720,14 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
 {
        struct config_group *group = &subsys->su_group;
        struct dentry *dentry = group->cg_item.ci_dentry;
+       struct dentry *root = dentry->d_sb->s_root;
 
-       if (dentry->d_parent != configfs_sb->s_root) {
+       if (dentry->d_parent != root) {
                printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n");
                return;
        }
 
-       mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,
+       mutex_lock_nested(&root->d_inode->i_mutex,
                          I_MUTEX_PARENT);
        mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
        mutex_lock(&configfs_symlink_mutex);
@@ -1754,7 +1744,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
 
        d_delete(dentry);
 
-       mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+       mutex_unlock(&root->d_inode->i_mutex);
 
        dput(dentry);
 
index 3ee36d4..0074362 100644 (file)
@@ -44,8 +44,6 @@
 static struct lock_class_key default_group_class[MAX_LOCK_DEPTH];
 #endif
 
-extern struct super_block * configfs_sb;
-
 static const struct address_space_operations configfs_aops = {
        .readpage       = simple_readpage,
        .write_begin    = simple_write_begin,
@@ -132,9 +130,10 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
        inode->i_ctime = iattr->ia_ctime;
 }
 
-struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent * sd)
+struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd,
+                                struct super_block *s)
 {
-       struct inode * inode = new_inode(configfs_sb);
+       struct inode * inode = new_inode(s);
        if (inode) {
                inode->i_ino = get_next_ino();
                inode->i_mapping->a_ops = &configfs_aops;
@@ -188,36 +187,35 @@ static void configfs_set_inode_lock_class(struct configfs_dirent *sd,
 int configfs_create(struct dentry * dentry, umode_t mode, int (*init)(struct inode *))
 {
        int error = 0;
-       struct inode * inode = NULL;
-       if (dentry) {
-               if (!dentry->d_inode) {
-                       struct configfs_dirent *sd = dentry->d_fsdata;
-                       if ((inode = configfs_new_inode(mode, sd))) {
-                               if (dentry->d_parent && dentry->d_parent->d_inode) {
-                                       struct inode *p_inode = dentry->d_parent->d_inode;
-                                       p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
-                               }
-                               configfs_set_inode_lock_class(sd, inode);
-                               goto Proceed;
-                       }
-                       else
-                               error = -ENOMEM;
-               } else
-                       error = -EEXIST;
-       } else
-               error = -ENOENT;
-       goto Done;
+       struct inode *inode = NULL;
+       struct configfs_dirent *sd;
+       struct inode *p_inode;
+
+       if (!dentry)
+               return -ENOENT;
+
+       if (dentry->d_inode)
+               return -EEXIST;
 
- Proceed:
-       if (init)
+       sd = dentry->d_fsdata;
+       inode = configfs_new_inode(mode, sd, dentry->d_sb);
+       if (!inode)
+               return -ENOMEM;
+
+       p_inode = dentry->d_parent->d_inode;
+       p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
+       configfs_set_inode_lock_class(sd, inode);
+
+       if (init) {
                error = init(inode);
-       if (!error) {
-               d_instantiate(dentry, inode);
-               if (S_ISDIR(mode) || S_ISLNK(mode))
-                       dget(dentry);  /* pin link and directory dentries in core */
-       } else
-               iput(inode);
- Done:
+               if (error) {
+                       iput(inode);
+                       return error;
+               }
+       }
+       d_instantiate(dentry, inode);
+       if (S_ISDIR(mode) || S_ISLNK(mode))
+               dget(dentry);  /* pin link and directory dentries in core */
        return error;
 }
 
index 276e15c..aee0a7e 100644 (file)
@@ -37,8 +37,7 @@
 /* Random magic number */
 #define CONFIGFS_MAGIC 0x62656570
 
-struct vfsmount * configfs_mount = NULL;
-struct super_block * configfs_sb = NULL;
+static struct vfsmount *configfs_mount = NULL;
 struct kmem_cache *configfs_dir_cachep;
 static int configfs_mnt_count = 0;
 
@@ -77,12 +76,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = CONFIGFS_MAGIC;
        sb->s_op = &configfs_ops;
        sb->s_time_gran = 1;
-       configfs_sb = sb;
 
        inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
-                                  &configfs_root);
+                                  &configfs_root, sb);
        if (inode) {
-               inode->i_op = &configfs_dir_inode_operations;
+               inode->i_op = &configfs_root_inode_operations;
                inode->i_fop = &configfs_dir_operations;
                /* directory inodes start off with i_nlink == 2 (for "." entry) */
                inc_nlink(inode);
@@ -91,10 +89,9 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        }
 
-       root = d_alloc_root(inode);
+       root = d_make_root(inode);
        if (!root) {
                pr_debug("%s: could not get root dentry!\n",__func__);
-               iput(inode);
                return -ENOMEM;
        }
        config_group_init(&configfs_root_group);
@@ -118,10 +115,11 @@ static struct file_system_type configfs_fs_type = {
        .kill_sb        = kill_litter_super,
 };
 
-int configfs_pin_fs(void)
+struct dentry *configfs_pin_fs(void)
 {
-       return simple_pin_fs(&configfs_fs_type, &configfs_mount,
+       int err = simple_pin_fs(&configfs_fs_type, &configfs_mount,
                             &configfs_mnt_count);
+       return err ? ERR_PTR(err) : configfs_mount->mnt_root;
 }
 
 void configfs_release_fs(void)
index 0f3eb41..cc9f254 100644 (file)
@@ -110,13 +110,13 @@ out:
 
 
 static int get_target(const char *symname, struct path *path,
-                     struct config_item **target)
+                     struct config_item **target, struct super_block *sb)
 {
        int ret;
 
        ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
        if (!ret) {
-               if (path->dentry->d_sb == configfs_sb) {
+               if (path->dentry->d_sb == sb) {
                        *target = configfs_get_config_item(path->dentry);
                        if (!*target) {
                                ret = -ENOENT;
@@ -141,10 +141,6 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
        struct config_item *target_item = NULL;
        struct config_item_type *type;
 
-       ret = -EPERM;  /* What lack-of-symlink returns */
-       if (dentry->d_parent == configfs_sb->s_root)
-               goto out;
-
        sd = dentry->d_parent->d_fsdata;
        /*
         * Fake invisibility if dir belongs to a group/default groups hierarchy
@@ -162,7 +158,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
            !type->ct_item_ops->allow_link)
                goto out_put;
 
-       ret = get_target(symname, &path, &target_item);
+       ret = get_target(symname, &path, &target_item, dentry->d_sb);
        if (ret)
                goto out_put;
 
@@ -198,8 +194,6 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry)
        if (!(sd->s_type & CONFIGFS_ITEM_LINK))
                goto out;
 
-       BUG_ON(dentry->d_parent == configfs_sb->s_root);
-
        sl = sd->s_element;
 
        parent_item = configfs_get_config_item(dentry->d_parent);
index 04d51f9..d013c46 100644 (file)
@@ -318,11 +318,9 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
        root = get_cramfs_inode(sb, &super.root, 0);
        if (IS_ERR(root))
                goto out;
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
+       sb->s_root = d_make_root(root);
+       if (!sb->s_root)
                goto out;
-       }
        return 0;
 out:
        kfree(sbi);
index 11828de..e441941 100644 (file)
@@ -1466,30 +1466,6 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
 
 EXPORT_SYMBOL(d_instantiate_unique);
 
-/**
- * d_alloc_root - allocate root dentry
- * @root_inode: inode to allocate the root for
- *
- * Allocate a root ("/") dentry for the inode given. The inode is
- * instantiated and returned. %NULL is returned if there is insufficient
- * memory or the inode passed is %NULL.
- */
-struct dentry * d_alloc_root(struct inode * root_inode)
-{
-       struct dentry *res = NULL;
-
-       if (root_inode) {
-               static const struct qstr name = { .name = "/", .len = 1 };
-
-               res = __d_alloc(root_inode->i_sb, &name);
-               if (res)
-                       d_instantiate(res, root_inode);
-       }
-       return res;
-}
-EXPORT_SYMBOL(d_alloc_root);
-
 struct dentry *d_make_root(struct inode *root_inode)
 {
        struct dentry *res = NULL;
index ef023ee..21e9360 100644 (file)
@@ -611,7 +611,7 @@ static const struct file_operations fops_regset32 = {
  * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
-struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
                                       struct dentry *parent,
                                       struct debugfs_regset32 *regset)
 {
index 1c6f908..10f5e0b 100644 (file)
@@ -374,12 +374,11 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        inode->i_fop = &simple_dir_operations;
        set_nlink(inode, 2);
 
-       s->s_root = d_alloc_root(inode);
+       s->s_root = d_make_root(inode);
        if (s->s_root)
                return 0;
 
        printk(KERN_ERR "devpts: get root dentry failed\n");
-       iput(inode);
 
 fail:
        return -ENOMEM;
index 8364157..dc5eb59 100644 (file)
@@ -351,11 +351,28 @@ int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
 static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
 {
        struct dlm_rsb *r;
+       uint32_t hash, bucket;
+       int rv;
+
+       hash = jhash(name, len, 0);
+       bucket = hash & (ls->ls_rsbtbl_size - 1);
+
+       spin_lock(&ls->ls_rsbtbl[bucket].lock);
+       rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, 0, &r);
+       if (rv)
+               rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss,
+                                        name, len, 0, &r);
+       spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+
+       if (!rv)
+               return r;
 
        down_read(&ls->ls_root_sem);
        list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
                if (len == r->res_length && !memcmp(name, r->res_name, len)) {
                        up_read(&ls->ls_root_sem);
+                       log_error(ls, "find_rsb_root revert to root_list %s",
+                                 r->res_name);
                        return r;
                }
        }
index d471830..fa5c07d 100644 (file)
@@ -411,8 +411,8 @@ static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen)
        return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN);
 }
 
-static int search_rsb_tree(struct rb_root *tree, char *name, int len,
-                          unsigned int flags, struct dlm_rsb **r_ret)
+int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
+                       unsigned int flags, struct dlm_rsb **r_ret)
 {
        struct rb_node *node = tree->rb_node;
        struct dlm_rsb *r;
@@ -474,12 +474,12 @@ static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
        struct dlm_rsb *r;
        int error;
 
-       error = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
+       error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
        if (!error) {
                kref_get(&r->res_ref);
                goto out;
        }
-       error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+       error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
        if (error)
                goto out;
 
index 265017a..1a25530 100644 (file)
@@ -28,6 +28,9 @@ void dlm_scan_waiters(struct dlm_ls *ls);
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
 
+int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
+                       unsigned int flags, struct dlm_rsb **r_ret);
+
 int dlm_purge_locks(struct dlm_ls *ls);
 void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
 void dlm_grant_after_purge(struct dlm_ls *ls);
index ca0c59a..133ef6d 100644 (file)
@@ -1076,7 +1076,7 @@ static void init_local(void)
        int i;
 
        dlm_local_count = 0;
-       for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+       for (i = 0; i < DLM_MAX_ADDR_COUNT; i++) {
                if (dlm_our_addr(&sas, i))
                        break;
 
index d3f95f9..2b17f2f 100644 (file)
@@ -48,8 +48,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
                                unsigned long nr_segs, loff_t pos)
 {
        ssize_t rc;
-       struct dentry *lower_dentry;
-       struct vfsmount *lower_vfsmount;
+       struct path lower;
        struct file *file = iocb->ki_filp;
 
        rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
@@ -60,9 +59,9 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
        if (-EIOCBQUEUED == rc)
                rc = wait_on_sync_kiocb(iocb);
        if (rc >= 0) {
-               lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
-               lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
-               touch_atime(lower_vfsmount, lower_dentry);
+               lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
+               lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
+               touch_atime(&lower);
        }
        return rc;
 }
index b4a6bef..6895493 100644 (file)
@@ -550,9 +550,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
        if (IS_ERR(inode))
                goto out_free;
 
-       s->s_root = d_alloc_root(inode);
+       s->s_root = d_make_root(inode);
        if (!s->s_root) {
-               iput(inode);
                rc = -ENOMEM;
                goto out_free;
        }
@@ -795,15 +794,10 @@ static int __init ecryptfs_init(void)
                       "Failed to allocate one or more kmem_cache objects\n");
                goto out;
        }
-       rc = register_filesystem(&ecryptfs_fs_type);
-       if (rc) {
-               printk(KERN_ERR "Failed to register filesystem\n");
-               goto out_free_kmem_caches;
-       }
        rc = do_sysfs_registration();
        if (rc) {
                printk(KERN_ERR "sysfs registration failed\n");
-               goto out_unregister_filesystem;
+               goto out_free_kmem_caches;
        }
        rc = ecryptfs_init_kthread();
        if (rc) {
@@ -824,19 +818,24 @@ static int __init ecryptfs_init(void)
                       "rc = [%d]\n", rc);
                goto out_release_messaging;
        }
+       rc = register_filesystem(&ecryptfs_fs_type);
+       if (rc) {
+               printk(KERN_ERR "Failed to register filesystem\n");
+               goto out_destroy_crypto;
+       }
        if (ecryptfs_verbosity > 0)
                printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "
                        "will be written to the syslog!\n", ecryptfs_verbosity);
 
        goto out;
+out_destroy_crypto:
+       ecryptfs_destroy_crypto();
 out_release_messaging:
        ecryptfs_release_messaging();
 out_destroy_kthread:
        ecryptfs_destroy_kthread();
 out_do_sysfs_unregistration:
        do_sysfs_unregistration();
-out_unregister_filesystem:
-       unregister_filesystem(&ecryptfs_fs_type);
 out_free_kmem_caches:
        ecryptfs_free_kmem_caches();
 out:
index cf15282..2dd946b 100644 (file)
@@ -184,7 +184,6 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root)
 const struct super_operations ecryptfs_sops = {
        .alloc_inode = ecryptfs_alloc_inode,
        .destroy_inode = ecryptfs_destroy_inode,
-       .drop_inode = generic_drop_inode,
        .statfs = ecryptfs_statfs,
        .remount_fs = NULL,
        .evict_inode = ecryptfs_evict_inode,
index 9811064..e755ec7 100644 (file)
@@ -317,10 +317,9 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
                goto out_no_fs;
        }
 
-       s->s_root = d_alloc_root(root);
+       s->s_root = d_make_root(root);
        if (!(s->s_root)) {
                printk(KERN_ERR "EFS: get root dentry failed\n");
-               iput(root);
                ret = -ENOMEM;
                goto out_no_fs;
        }
index 6ed164d..23559c2 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -81,15 +81,13 @@ static atomic_t call_count = ATOMIC_INIT(1);
 static LIST_HEAD(formats);
 static DEFINE_RWLOCK(binfmt_lock);
 
-int __register_binfmt(struct linux_binfmt * fmt, int insert)
+void __register_binfmt(struct linux_binfmt * fmt, int insert)
 {
-       if (!fmt)
-               return -EINVAL;
+       BUG_ON(!fmt);
        write_lock(&binfmt_lock);
        insert ? list_add(&fmt->lh, &formats) :
                 list_add_tail(&fmt->lh, &formats);
        write_unlock(&binfmt_lock);
-       return 0;       
 }
 
 EXPORT_SYMBOL(__register_binfmt);
@@ -1115,7 +1113,7 @@ int flush_old_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;                /* We're using it now */
 
        set_fs(USER_DS);
-       current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD);
+       current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD);
        flush_thread();
        current->personality &= ~bprm->per_clear;
 
index 9dbf0c3..fc7161d 100644 (file)
@@ -143,9 +143,6 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir,
 {
        struct inode *inode = old_dentry->d_inode;
 
-       if (inode->i_nlink >= EXOFS_LINK_MAX)
-               return -EMLINK;
-
        inode->i_ctime = CURRENT_TIME;
        inode_inc_link_count(inode);
        ihold(inode);
@@ -156,10 +153,7 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir,
 static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        struct inode *inode;
-       int err = -EMLINK;
-
-       if (dir->i_nlink >= EXOFS_LINK_MAX)
-               goto out;
+       int err;
 
        inode_inc_link_count(dir);
 
@@ -275,11 +269,6 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (err)
                        goto out_dir;
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= EXOFS_LINK_MAX)
-                               goto out_dir;
-               }
                err = exofs_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index d22cd16..7f2b590 100644 (file)
@@ -754,6 +754,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_blocksize = EXOFS_BLKSIZE;
        sb->s_blocksize_bits = EXOFS_BLKSHIFT;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
+       sb->s_max_links = EXOFS_LINK_MAX;
        atomic_set(&sbi->s_curr_pending, 0);
        sb->s_bdev = NULL;
        sb->s_dev = 0;
@@ -818,9 +819,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                ret = PTR_ERR(root);
                goto free_sbi;
        }
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
-               iput(root);
                EXOFS_ERR("ERROR: get root inode failed\n");
                ret = -ENOMEM;
                goto free_sbi;
index 0804198..dffb865 100644 (file)
@@ -195,9 +195,6 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
        struct inode *inode = old_dentry->d_inode;
        int err;
 
-       if (inode->i_nlink >= EXT2_LINK_MAX)
-               return -EMLINK;
-
        dquot_initialize(dir);
 
        inode->i_ctime = CURRENT_TIME_SEC;
@@ -217,10 +214,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
 static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
        struct inode * inode;
-       int err = -EMLINK;
-
-       if (dir->i_nlink >= EXT2_LINK_MAX)
-               goto out;
+       int err;
 
        dquot_initialize(dir);
 
@@ -346,11 +340,6 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                        drop_nlink(new_inode);
                inode_dec_link_count(new_inode);
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= EXT2_LINK_MAX)
-                               goto out_dir;
-               }
                err = ext2_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index 0090595..e1025c7 100644 (file)
@@ -919,6 +919,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
+       sb->s_max_links = EXT2_LINK_MAX;
 
        if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
                sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
@@ -1087,9 +1088,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount3;
        }
 
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
-               iput(root);
                ext2_msg(sb, KERN_ERR, "error: get root inode failed");
                ret = -ENOMEM;
                goto failed_mount3;
index 726c7ef..e0b45b9 100644 (file)
@@ -2046,10 +2046,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck");
                goto failed_mount3;
        }
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                ext3_msg(sb, KERN_ERR, "error: get root dentry failed");
-               iput(root);
                ret = -ENOMEM;
                goto failed_mount3;
        }
index 502c61f..9339009 100644 (file)
@@ -3735,9 +3735,8 @@ no_journal:
                iput(root);
                goto failed_mount4;
        }
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
-               iput(root);
                ext4_msg(sb, KERN_ERR, "get root dentry failed");
                ret = -ENOMEM;
                goto failed_mount4;
@@ -5056,6 +5055,9 @@ static int __init ext4_init_fs(void)
 {
        int i, err;
 
+       ext4_li_info = NULL;
+       mutex_init(&ext4_li_mtx);
+
        ext4_check_flag_values();
 
        for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
@@ -5094,8 +5096,6 @@ static int __init ext4_init_fs(void)
        if (err)
                goto out;
 
-       ext4_li_info = NULL;
-       mutex_init(&ext4_li_mtx);
        return 0;
 out:
        unregister_as_ext2();
index 3ab8410..21687e3 100644 (file)
@@ -1496,11 +1496,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        root_inode->i_ino = MSDOS_ROOT_INO;
        root_inode->i_version = 1;
        error = fat_read_root(root_inode);
-       if (error < 0)
+       if (error < 0) {
+               iput(root_inode);
                goto out_fail;
+       }
        error = -ENOMEM;
        insert_inode_hash(root_inode);
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (!sb->s_root) {
                fat_msg(sb, KERN_ERR, "get root inode failed");
                goto out_fail;
@@ -1516,8 +1518,6 @@ out_invalid:
 out_fail:
        if (fat_inode)
                iput(fat_inode);
-       if (root_inode)
-               iput(root_inode);
        unload_nls(sbi->nls_io);
        unload_nls(sbi->nls_disk);
        if (sbi->options.iocharset != fat_default_iocharset)
index 20002e3..70f2a0f 100644 (file)
@@ -204,7 +204,7 @@ EXPORT_SYMBOL(alloc_file);
  * to write to @file, along with access to write through
  * its vfsmount.
  */
-void drop_file_write_access(struct file *file)
+static void drop_file_write_access(struct file *file)
 {
        struct vfsmount *mnt = file->f_path.mnt;
        struct dentry *dentry = file->f_path.dentry;
@@ -219,7 +219,6 @@ void drop_file_write_access(struct file *file)
        mnt_drop_write(mnt);
        file_release_write(file);
 }
-EXPORT_SYMBOL_GPL(drop_file_write_access);
 
 /* the real guts of fput() - releasing the last reference to file
  */
index 9d1c995..d4fabd2 100644 (file)
@@ -224,9 +224,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
                ret = PTR_ERR(root);
                goto out;
        }
-       sbp->s_root = d_alloc_root(root);
+       sbp->s_root = d_make_root(root);
        if (!sbp->s_root) {
-               iput(root);
                printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
                goto out_free_ilist;
        }
index 78b519c..6324c42 100644 (file)
@@ -26,11 +26,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
 {
        struct path old_root;
 
+       path_get_longterm(path);
        spin_lock(&fs->lock);
        write_seqcount_begin(&fs->seq);
        old_root = fs->root;
        fs->root = *path;
-       path_get_longterm(path);
        write_seqcount_end(&fs->seq);
        spin_unlock(&fs->lock);
        if (old_root.dentry)
@@ -45,11 +45,11 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
 {
        struct path old_pwd;
 
+       path_get_longterm(path);
        spin_lock(&fs->lock);
        write_seqcount_begin(&fs->seq);
        old_pwd = fs->pwd;
        fs->pwd = *path;
-       path_get_longterm(path);
        write_seqcount_end(&fs->seq);
        spin_unlock(&fs->lock);
 
@@ -57,6 +57,14 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
                path_put_longterm(&old_pwd);
 }
 
+static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
+{
+       if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
+               return 0;
+       *p = *new;
+       return 1;
+}
+
 void chroot_fs_refs(struct path *old_root, struct path *new_root)
 {
        struct task_struct *g, *p;
@@ -68,21 +76,16 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
                task_lock(p);
                fs = p->fs;
                if (fs) {
+                       int hits = 0;
                        spin_lock(&fs->lock);
                        write_seqcount_begin(&fs->seq);
-                       if (fs->root.dentry == old_root->dentry
-                           && fs->root.mnt == old_root->mnt) {
-                               path_get_longterm(new_root);
-                               fs->root = *new_root;
+                       hits += replace_path(&fs->root, old_root, new_root);
+                       hits += replace_path(&fs->pwd, old_root, new_root);
+                       write_seqcount_end(&fs->seq);
+                       while (hits--) {
                                count++;
-                       }
-                       if (fs->pwd.dentry == old_root->dentry
-                           && fs->pwd.mnt == old_root->mnt) {
                                path_get_longterm(new_root);
-                               fs->pwd = *new_root;
-                               count++;
                        }
-                       write_seqcount_end(&fs->seq);
                        spin_unlock(&fs->lock);
                }
                task_unlock(p);
@@ -107,10 +110,8 @@ void exit_fs(struct task_struct *tsk)
                int kill;
                task_lock(tsk);
                spin_lock(&fs->lock);
-               write_seqcount_begin(&fs->seq);
                tsk->fs = NULL;
                kill = !--fs->users;
-               write_seqcount_end(&fs->seq);
                spin_unlock(&fs->lock);
                task_unlock(tsk);
                if (kill)
index 64cf8d0..4aec599 100644 (file)
@@ -988,14 +988,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -ENOMEM;
        root = fuse_get_root_inode(sb, d.rootmode);
-       if (!root)
+       root_dentry = d_make_root(root);
+       if (!root_dentry)
                goto err_put_conn;
-
-       root_dentry = d_alloc_root(root);
-       if (!root_dentry) {
-               iput(root);
-               goto err_put_conn;
-       }
        /* only now - we want root dentry with NULL ->d_op */
        sb->s_d_op = &fuse_dentry_operations;
 
index 14a7040..197c5c4 100644 (file)
@@ -60,7 +60,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
        int release = 0;
 
        if (!page || page->index) {
-               page = grab_cache_page(inode->i_mapping, 0);
+               page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
                if (!page)
                        return -ENOMEM;
                release = 1;
@@ -930,7 +930,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
        struct page *page;
        int err;
 
-       page = grab_cache_page(mapping, index);
+       page = find_or_create_page(mapping, index, GFP_NOFS);
        if (!page)
                return 0;
 
index c5fb359..7683458 100644 (file)
@@ -313,6 +313,8 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return gfs2_get_flags(filp, (u32 __user *)arg);
        case FS_IOC_SETFLAGS:
                return gfs2_set_flags(filp, (u32 __user *)arg);
+       case FITRIM:
+               return gfs2_fitrim(filp, (void __user *)arg);
        }
        return -ENOTTY;
 }
@@ -674,6 +676,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct buffer_head *dibh;
        int error;
+       loff_t size = len;
        unsigned int nr_blks;
        sector_t lblock = offset >> inode->i_blkbits;
 
@@ -707,8 +710,8 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                        goto out;
                }
        }
-       if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
-               i_size_write(inode, offset + len);
+       if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
+               i_size_write(inode, offset + size);
 
        mark_inode_dirty(inode);
 
@@ -777,12 +780,14 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
        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;
+               if (!gfs2_write_alloc_required(ip, offset, bytes)) {
+                       len -= bytes;
+                       offset += bytes;
+                       continue;
+               }
                qa = gfs2_qadata_get(ip);
                if (!qa) {
                        error = -ENOMEM;
index 351a3e7..dab2526 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/rcupdate.h>
 #include <linux/rculist_bl.h>
 #include <linux/bit_spinlock.h>
+#include <linux/percpu.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -543,6 +544,11 @@ __acquires(&gl->gl_spin)
                do_error(gl, 0); /* Fail queued try locks */
        }
        gl->gl_req = target;
+       set_bit(GLF_BLOCKING, &gl->gl_flags);
+       if ((gl->gl_req == LM_ST_UNLOCKED) ||
+           (gl->gl_state == LM_ST_EXCLUSIVE) ||
+           (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
+               clear_bit(GLF_BLOCKING, &gl->gl_flags);
        spin_unlock(&gl->gl_spin);
        if (glops->go_xmote_th)
                glops->go_xmote_th(gl);
@@ -744,6 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
                return -ENOMEM;
 
        atomic_inc(&sdp->sd_glock_disposal);
+       gl->gl_sbd = sdp;
        gl->gl_flags = 0;
        gl->gl_name = name;
        atomic_set(&gl->gl_ref, 1);
@@ -752,12 +759,17 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        gl->gl_demote_state = LM_ST_EXCLUSIVE;
        gl->gl_hash = hash;
        gl->gl_ops = glops;
-       snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number);
+       gl->gl_dstamp = ktime_set(0, 0);
+       preempt_disable();
+       /* We use the global stats to estimate the initial per-glock stats */
+       gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type];
+       preempt_enable();
+       gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0;
+       gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0;
        memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
        gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
        gl->gl_tchange = jiffies;
        gl->gl_object = NULL;
-       gl->gl_sbd = sdp;
        gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
        INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
        INIT_WORK(&gl->gl_delete, delete_work_func);
@@ -999,6 +1011,8 @@ fail:
        }
        set_bit(GLF_QUEUED, &gl->gl_flags);
        trace_gfs2_glock_queue(gh, 1);
+       gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
+       gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
        if (likely(insert_pt == NULL)) {
                list_add_tail(&gh->gh_list, &gl->gl_holders);
                if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
@@ -1658,6 +1672,8 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
                *p++ = 'L';
        if (gl->gl_object)
                *p++ = 'o';
+       if (test_bit(GLF_BLOCKING, gflags))
+               *p++ = 'b';
        *p = 0;
        return buf;
 }
@@ -1714,8 +1730,78 @@ out:
        return error;
 }
 
+static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+       struct gfs2_glock *gl = iter_ptr;
+
+       seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n",
+                  gl->gl_name.ln_type,
+                  (unsigned long long)gl->gl_name.ln_number,
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SRTT],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SIRT],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT],
+                  (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]);
+       return 0;
+}
+
+static const char *gfs2_gltype[] = {
+       "type",
+       "reserved",
+       "nondisk",
+       "inode",
+       "rgrp",
+       "meta",
+       "iopen",
+       "flock",
+       "plock",
+       "quota",
+       "journal",
+};
+
+static const char *gfs2_stype[] = {
+       [GFS2_LKS_SRTT]         = "srtt",
+       [GFS2_LKS_SRTTVAR]      = "srttvar",
+       [GFS2_LKS_SRTTB]        = "srttb",
+       [GFS2_LKS_SRTTVARB]     = "srttvarb",
+       [GFS2_LKS_SIRT]         = "sirt",
+       [GFS2_LKS_SIRTVAR]      = "sirtvar",
+       [GFS2_LKS_DCOUNT]       = "dlm",
+       [GFS2_LKS_QCOUNT]       = "queue",
+};
+
+#define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype))
+
+static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr)
+{
+       struct gfs2_glock_iter *gi = seq->private;
+       struct gfs2_sbd *sdp = gi->sdp;
+       unsigned index = gi->hash >> 3;
+       unsigned subindex = gi->hash & 0x07;
+       s64 value;
+       int i;
+
+       if (index == 0 && subindex != 0)
+               return 0;
 
+       seq_printf(seq, "%-10s %8s:", gfs2_gltype[index],
+                  (index == 0) ? "cpu": gfs2_stype[subindex]);
 
+       for_each_possible_cpu(i) {
+                const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i);
+               if (index == 0) {
+                       value = i;
+               } else {
+                       value = lkstats->lkstats[index - 1].stats[subindex];
+               }
+               seq_printf(seq, " %15lld", (long long)value);
+       }
+       seq_putc(seq, '\n');
+       return 0;
+}
 
 int __init gfs2_glock_init(void)
 {
@@ -1828,6 +1914,35 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
        return dump_glock(seq, iter_ptr);
 }
 
+static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct gfs2_glock_iter *gi = seq->private;
+
+       gi->hash = *pos;
+       if (*pos >= GFS2_NR_SBSTATS)
+               return NULL;
+       preempt_disable();
+       return SEQ_START_TOKEN;
+}
+
+static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr,
+                                  loff_t *pos)
+{
+       struct gfs2_glock_iter *gi = seq->private;
+       (*pos)++;
+       gi->hash++;
+       if (gi->hash >= GFS2_NR_SBSTATS) {
+               preempt_enable();
+               return NULL;
+       }
+       return SEQ_START_TOKEN;
+}
+
+static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr)
+{
+       preempt_enable();
+}
+
 static const struct seq_operations gfs2_glock_seq_ops = {
        .start = gfs2_glock_seq_start,
        .next  = gfs2_glock_seq_next,
@@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = {
        .show  = gfs2_glock_seq_show,
 };
 
-static int gfs2_debugfs_open(struct inode *inode, struct file *file)
+static const struct seq_operations gfs2_glstats_seq_ops = {
+       .start = gfs2_glock_seq_start,
+       .next  = gfs2_glock_seq_next,
+       .stop  = gfs2_glock_seq_stop,
+       .show  = gfs2_glstats_seq_show,
+};
+
+static const struct seq_operations gfs2_sbstats_seq_ops = {
+       .start = gfs2_sbstats_seq_start,
+       .next  = gfs2_sbstats_seq_next,
+       .stop  = gfs2_sbstats_seq_stop,
+       .show  = gfs2_sbstats_seq_show,
+};
+
+static int gfs2_glocks_open(struct inode *inode, struct file *file)
 {
        int ret = seq_open_private(file, &gfs2_glock_seq_ops,
                                   sizeof(struct gfs2_glock_iter));
@@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file)
        return ret;
 }
 
-static const struct file_operations gfs2_debug_fops = {
+static int gfs2_glstats_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open_private(file, &gfs2_glstats_seq_ops,
+                                  sizeof(struct gfs2_glock_iter));
+       if (ret == 0) {
+               struct seq_file *seq = file->private_data;
+               struct gfs2_glock_iter *gi = seq->private;
+               gi->sdp = inode->i_private;
+       }
+       return ret;
+}
+
+static int gfs2_sbstats_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open_private(file, &gfs2_sbstats_seq_ops,
+                                  sizeof(struct gfs2_glock_iter));
+       if (ret == 0) {
+               struct seq_file *seq = file->private_data;
+               struct gfs2_glock_iter *gi = seq->private;
+               gi->sdp = inode->i_private;
+       }
+       return ret;
+}
+
+static const struct file_operations gfs2_glocks_fops = {
+       .owner   = THIS_MODULE,
+       .open    = gfs2_glocks_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_private,
+};
+
+static const struct file_operations gfs2_glstats_fops = {
        .owner   = THIS_MODULE,
-       .open    = gfs2_debugfs_open,
+       .open    = gfs2_glstats_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_private,
+};
+
+static const struct file_operations gfs2_sbstats_fops = {
+       .owner   = THIS_MODULE,
+       .open    = gfs2_sbstats_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
        .release = seq_release_private,
@@ -1863,20 +2032,45 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
        sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
                                                         S_IFREG | S_IRUGO,
                                                         sdp->debugfs_dir, sdp,
-                                                        &gfs2_debug_fops);
+                                                        &gfs2_glocks_fops);
        if (!sdp->debugfs_dentry_glocks)
-               return -ENOMEM;
+               goto fail;
+
+       sdp->debugfs_dentry_glstats = debugfs_create_file("glstats",
+                                                       S_IFREG | S_IRUGO,
+                                                       sdp->debugfs_dir, sdp,
+                                                       &gfs2_glstats_fops);
+       if (!sdp->debugfs_dentry_glstats)
+               goto fail;
+
+       sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats",
+                                                       S_IFREG | S_IRUGO,
+                                                       sdp->debugfs_dir, sdp,
+                                                       &gfs2_sbstats_fops);
+       if (!sdp->debugfs_dentry_sbstats)
+               goto fail;
 
        return 0;
+fail:
+       gfs2_delete_debugfs_file(sdp);
+       return -ENOMEM;
 }
 
 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
 {
-       if (sdp && sdp->debugfs_dir) {
+       if (sdp->debugfs_dir) {
                if (sdp->debugfs_dentry_glocks) {
                        debugfs_remove(sdp->debugfs_dentry_glocks);
                        sdp->debugfs_dentry_glocks = NULL;
                }
+               if (sdp->debugfs_dentry_glstats) {
+                       debugfs_remove(sdp->debugfs_dentry_glstats);
+                       sdp->debugfs_dentry_glstats = NULL;
+               }
+               if (sdp->debugfs_dentry_sbstats) {
+                       debugfs_remove(sdp->debugfs_dentry_sbstats);
+                       sdp->debugfs_dentry_sbstats = NULL;
+               }
                debugfs_remove(sdp->debugfs_dir);
                sdp->debugfs_dir = NULL;
        }
index 97742a7..47d0bda 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/rculist_bl.h>
 #include <linux/completion.h>
 #include <linux/rbtree.h>
+#include <linux/ktime.h>
+#include <linux/percpu.h>
 
 #define DIO_WAIT       0x00000010
 #define DIO_METADATA   0x00000020
@@ -204,6 +206,22 @@ struct gfs2_glock_operations {
 #define GLOF_ASPACE 1
 };
 
+enum {
+       GFS2_LKS_SRTT = 0,      /* Non blocking smoothed round trip time */
+       GFS2_LKS_SRTTVAR = 1,   /* Non blocking smoothed variance */
+       GFS2_LKS_SRTTB = 2,     /* Blocking smoothed round trip time */
+       GFS2_LKS_SRTTVARB = 3,  /* Blocking smoothed variance */
+       GFS2_LKS_SIRT = 4,      /* Smoothed Inter-request time */
+       GFS2_LKS_SIRTVAR = 5,   /* Smoothed Inter-request variance */
+       GFS2_LKS_DCOUNT = 6,    /* Count of dlm requests */
+       GFS2_LKS_QCOUNT = 7,    /* Count of gfs2_holder queues */
+       GFS2_NR_LKSTATS
+};
+
+struct gfs2_lkstats {
+       s64 stats[GFS2_NR_LKSTATS];
+};
+
 enum {
        /* States */
        HIF_HOLDER              = 6,  /* Set for gh that "holds" the glock */
@@ -238,10 +256,12 @@ enum {
        GLF_QUEUED                      = 12,
        GLF_LRU                         = 13,
        GLF_OBJECT                      = 14, /* Used only for tracing */
+       GLF_BLOCKING                    = 15,
 };
 
 struct gfs2_glock {
        struct hlist_bl_node gl_list;
+       struct gfs2_sbd *gl_sbd;
        unsigned long gl_flags;         /* GLF_... */
        struct lm_lockname gl_name;
        atomic_t gl_ref;
@@ -261,16 +281,14 @@ struct gfs2_glock {
        struct list_head gl_holders;
 
        const struct gfs2_glock_operations *gl_ops;
-       char gl_strname[GDLM_STRNAME_BYTES];
+       ktime_t gl_dstamp;
+       struct gfs2_lkstats gl_stats;
        struct dlm_lksb gl_lksb;
        char gl_lvb[32];
        unsigned long gl_tchange;
        void *gl_object;
 
        struct list_head gl_lru;
-
-       struct gfs2_sbd *gl_sbd;
-
        struct list_head gl_ail_list;
        atomic_t gl_ail_count;
        atomic_t gl_revokes;
@@ -560,8 +578,14 @@ struct lm_lockstruct {
        uint32_t *ls_recover_result; /* result of last jid recovery */
 };
 
+struct gfs2_pcpu_lkstats {
+       /* One struct for each glock type */
+       struct gfs2_lkstats lkstats[10];
+};
+
 struct gfs2_sbd {
        struct super_block *sd_vfs;
+       struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
        struct kobject sd_kobj;
        unsigned long sd_flags; /* SDF_... */
        struct gfs2_sb_host sd_sb;
@@ -620,7 +644,6 @@ struct gfs2_sbd {
 
        int sd_rindex_uptodate;
        spinlock_t sd_rindex_spin;
-       struct mutex sd_rindex_mutex;
        struct rb_root sd_rindex_tree;
        unsigned int sd_rgrps;
        unsigned int sd_max_rg_data;
@@ -725,8 +748,23 @@ struct gfs2_sbd {
 
        unsigned long sd_last_warning;
        struct dentry *debugfs_dir;    /* debugfs directory */
-       struct dentry *debugfs_dentry_glocks; /* for debugfs */
+       struct dentry *debugfs_dentry_glocks;
+       struct dentry *debugfs_dentry_glstats;
+       struct dentry *debugfs_dentry_sbstats;
 };
 
+static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which)
+{
+       gl->gl_stats.stats[which]++;
+}
+
+static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which)
+{
+       const struct gfs2_sbd *sdp = gl->gl_sbd;
+       preempt_disable();
+       this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++;
+       preempt_enable();
+}
+
 #endif /* __INCORE_DOT_H__ */
 
index 5698746..c98a60e 100644 (file)
@@ -1036,7 +1036,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
        gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
        gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);
 
-       rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
+       rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
        if (!rgd)
                goto out_inodes;
 
@@ -1255,7 +1255,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                 * this is the case of the target file already existing
                 * so we unlink before doing the rename
                 */
-               nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr);
+               nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1);
                if (nrgd)
                        gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
        }
index 8944d1e..f8411bd 100644 (file)
 #include "glock.h"
 #include "util.h"
 #include "sys.h"
+#include "trace_gfs2.h"
 
 extern struct workqueue_struct *gfs2_control_wq;
 
+/**
+ * gfs2_update_stats - Update time based stats
+ * @mv: Pointer to mean/variance structure to update
+ * @sample: New data to include
+ *
+ * @delta is the difference between the current rtt sample and the
+ * running average srtt. We add 1/8 of that to the srtt in order to
+ * update the current srtt estimate. The varience estimate is a bit
+ * more complicated. We subtract the abs value of the @delta from
+ * the current variance estimate and add 1/4 of that to the running
+ * total.
+ *
+ * Note that the index points at the array entry containing the smoothed
+ * mean value, and the variance is always in the following entry
+ *
+ * Reference: TCP/IP Illustrated, vol 2, p. 831,832
+ * All times are in units of integer nanoseconds. Unlike the TCP/IP case,
+ * they are not scaled fixed point.
+ */
+
+static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
+                                    s64 sample)
+{
+       s64 delta = sample - s->stats[index];
+       s->stats[index] += (delta >> 3);
+       index++;
+       s->stats[index] += ((abs64(delta) - s->stats[index]) >> 2);
+}
+
+/**
+ * gfs2_update_reply_times - Update locking statistics
+ * @gl: The glock to update
+ *
+ * This assumes that gl->gl_dstamp has been set earlier.
+ *
+ * The rtt (lock round trip time) is an estimate of the time
+ * taken to perform a dlm lock request. We update it on each
+ * reply from the dlm.
+ *
+ * The blocking flag is set on the glock for all dlm requests
+ * which may potentially block due to lock requests from other nodes.
+ * DLM requests where the current lock state is exclusive, the
+ * requested state is null (or unlocked) or where the TRY or
+ * TRY_1CB flags are set are classified as non-blocking. All
+ * other DLM requests are counted as (potentially) blocking.
+ */
+static inline void gfs2_update_reply_times(struct gfs2_glock *gl)
+{
+       struct gfs2_pcpu_lkstats *lks;
+       const unsigned gltype = gl->gl_name.ln_type;
+       unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ?
+                        GFS2_LKS_SRTTB : GFS2_LKS_SRTT;
+       s64 rtt;
+
+       preempt_disable();
+       rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp));
+       lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
+       gfs2_update_stats(&gl->gl_stats, index, rtt);           /* Local */
+       gfs2_update_stats(&lks->lkstats[gltype], index, rtt);   /* Global */
+       preempt_enable();
+
+       trace_gfs2_glock_lock_time(gl, rtt);
+}
+
+/**
+ * gfs2_update_request_times - Update locking statistics
+ * @gl: The glock to update
+ *
+ * The irt (lock inter-request times) measures the average time
+ * between requests to the dlm. It is updated immediately before
+ * each dlm call.
+ */
+
+static inline void gfs2_update_request_times(struct gfs2_glock *gl)
+{
+       struct gfs2_pcpu_lkstats *lks;
+       const unsigned gltype = gl->gl_name.ln_type;
+       ktime_t dstamp;
+       s64 irt;
+
+       preempt_disable();
+       dstamp = gl->gl_dstamp;
+       gl->gl_dstamp = ktime_get_real();
+       irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp));
+       lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
+       gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt);           /* Local */
+       gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt);   /* Global */
+       preempt_enable();
+}
 static void gdlm_ast(void *arg)
 {
        struct gfs2_glock *gl = arg;
        unsigned ret = gl->gl_state;
 
+       gfs2_update_reply_times(gl);
        BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
 
        if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
@@ -111,7 +203,7 @@ static int make_mode(const unsigned int lmstate)
 static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
                      const int req)
 {
-       u32 lkf = 0;
+       u32 lkf = DLM_LKF_VALBLK;
 
        if (gfs_flags & LM_FLAG_TRY)
                lkf |= DLM_LKF_NOQUEUE;
@@ -138,26 +230,43 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
        if (lkid != 0) 
                lkf |= DLM_LKF_CONVERT;
 
-       lkf |= DLM_LKF_VALBLK;
-
        return lkf;
 }
 
+static void gfs2_reverse_hex(char *c, u64 value)
+{
+       while (value) {
+               *c-- = hex_asc[value & 0x0f];
+               value >>= 4;
+       }
+}
+
 static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
                     unsigned int flags)
 {
        struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
        int req;
        u32 lkf;
+       char strname[GDLM_STRNAME_BYTES] = "";
 
        req = make_mode(req_state);
        lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
-
+       gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
+       gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
+       if (gl->gl_lksb.sb_lkid) {
+               gfs2_update_request_times(gl);
+       } else {
+               memset(strname, ' ', GDLM_STRNAME_BYTES - 1);
+               strname[GDLM_STRNAME_BYTES - 1] = '\0';
+               gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type);
+               gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number);
+               gl->gl_dstamp = ktime_get_real();
+       }
        /*
         * Submit the actual lock request.
         */
 
-       return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
+       return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
                        GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
 }
 
@@ -172,6 +281,10 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
                return;
        }
 
+       clear_bit(GLF_BLOCKING, &gl->gl_flags);
+       gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
+       gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
+       gfs2_update_request_times(gl);
        error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
                           NULL, gl);
        if (error) {
index 756fae9..4752ead 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/freezer.h>
 #include <linux/bio.h>
 #include <linux/writeback.h>
+#include <linux/list_sort.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -358,7 +359,7 @@ retry:
        return 0;
 }
 
-static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
 {
        struct gfs2_journal_extent *je;
 
@@ -467,8 +468,8 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
 
 void gfs2_log_incr_head(struct gfs2_sbd *sdp)
 {
-       if (sdp->sd_log_flush_head == sdp->sd_log_tail)
-               BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
+       BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
+              (sdp->sd_log_flush_head != sdp->sd_log_head));
 
        if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
                sdp->sd_log_flush_head = 0;
@@ -476,99 +477,6 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp)
        }
 }
 
-/**
- * gfs2_log_write_endio - End of I/O for a log buffer
- * @bh: The buffer head
- * @uptodate: I/O Status
- *
- */
-
-static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
-{
-       struct gfs2_sbd *sdp = bh->b_private;
-       bh->b_private = NULL;
-
-       end_buffer_write_sync(bh, uptodate);
-       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
-               wake_up(&sdp->sd_log_flush_wait);
-}
-
-/**
- * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
- * @sdp: The GFS2 superblock
- *
- * Returns: the buffer_head
- */
-
-struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
-{
-       u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-       struct buffer_head *bh;
-
-       bh = sb_getblk(sdp->sd_vfs, blkno);
-       lock_buffer(bh);
-       memset(bh->b_data, 0, bh->b_size);
-       set_buffer_uptodate(bh);
-       clear_buffer_dirty(bh);
-       gfs2_log_incr_head(sdp);
-       atomic_inc(&sdp->sd_log_in_flight);
-       bh->b_private = sdp;
-       bh->b_end_io = gfs2_log_write_endio;
-
-       return bh;
-}
-
-/**
- * gfs2_fake_write_endio - 
- * @bh: The buffer head
- * @uptodate: The I/O Status
- *
- */
-
-static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
-{
-       struct buffer_head *real_bh = bh->b_private;
-       struct gfs2_bufdata *bd = real_bh->b_private;
-       struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
-
-       end_buffer_write_sync(bh, uptodate);
-       free_buffer_head(bh);
-       unlock_buffer(real_bh);
-       brelse(real_bh);
-       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
-               wake_up(&sdp->sd_log_flush_wait);
-}
-
-/**
- * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
- * @sdp: the filesystem
- * @data: the data the buffer_head should point to
- *
- * Returns: the log buffer descriptor
- */
-
-struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
-                                     struct buffer_head *real)
-{
-       u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-       struct buffer_head *bh;
-
-       bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
-       atomic_set(&bh->b_count, 1);
-       bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
-       set_bh_page(bh, real->b_page, bh_offset(real));
-       bh->b_blocknr = blkno;
-       bh->b_size = sdp->sd_sb.sb_bsize;
-       bh->b_bdev = sdp->sd_vfs->s_bdev;
-       bh->b_private = real;
-       bh->b_end_io = gfs2_fake_write_endio;
-
-       gfs2_log_incr_head(sdp);
-       atomic_inc(&sdp->sd_log_in_flight);
-
-       return bh;
-}
-
 static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
 {
        unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
@@ -583,66 +491,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
        sdp->sd_log_tail = new_tail;
 }
 
-/**
- * log_write_header - Get and initialize a journal header buffer
- * @sdp: The GFS2 superblock
- *
- * Returns: the initialized log buffer descriptor
- */
 
-static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
-{
-       u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-       struct buffer_head *bh;
-       struct gfs2_log_header *lh;
-       unsigned int tail;
-       u32 hash;
-
-       bh = sb_getblk(sdp->sd_vfs, blkno);
-       lock_buffer(bh);
-       memset(bh->b_data, 0, bh->b_size);
-       set_buffer_uptodate(bh);
-       clear_buffer_dirty(bh);
-
-       gfs2_ail1_empty(sdp);
-       tail = current_tail(sdp);
-
-       lh = (struct gfs2_log_header *)bh->b_data;
-       memset(lh, 0, sizeof(struct gfs2_log_header));
-       lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-       lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
-       lh->lh_header.__pad0 = cpu_to_be64(0);
-       lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
-       lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
-       lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
-       lh->lh_flags = cpu_to_be32(flags);
-       lh->lh_tail = cpu_to_be32(tail);
-       lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
-       hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
-       lh->lh_hash = cpu_to_be32(hash);
-
-       bh->b_end_io = end_buffer_write_sync;
-       get_bh(bh);
-       if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
-               submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
-       else
-               submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
-       wait_on_buffer(bh);
-
-       if (!buffer_uptodate(bh))
-               gfs2_io_error_bh(sdp, bh);
-       brelse(bh);
-
-       if (sdp->sd_log_tail != tail)
-               log_pull_tail(sdp, tail);
-       else
-               gfs2_assert_withdraw(sdp, !pull);
-
-       sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
-       gfs2_log_incr_head(sdp);
-}
-
-static void log_flush_commit(struct gfs2_sbd *sdp)
+static void log_flush_wait(struct gfs2_sbd *sdp)
 {
        DEFINE_WAIT(wait);
 
@@ -655,8 +505,20 @@ static void log_flush_commit(struct gfs2_sbd *sdp)
                } while(atomic_read(&sdp->sd_log_in_flight));
                finish_wait(&sdp->sd_log_flush_wait, &wait);
        }
+}
+
+static int bd_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+       struct gfs2_bufdata *bda, *bdb;
 
-       log_write_header(sdp, 0, 0);
+       bda = list_entry(a, struct gfs2_bufdata, bd_le.le_list);
+       bdb = list_entry(b, struct gfs2_bufdata, bd_le.le_list);
+
+       if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr)
+               return -1;
+       if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr)
+               return 1;
+       return 0;
 }
 
 static void gfs2_ordered_write(struct gfs2_sbd *sdp)
@@ -666,6 +528,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
        LIST_HEAD(written);
 
        gfs2_log_lock(sdp);
+       list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp);
        while (!list_empty(&sdp->sd_log_le_ordered)) {
                bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
                list_move(&bd->bd_le.le_list, &written);
@@ -710,6 +573,68 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
        gfs2_log_unlock(sdp);
 }
 
+/**
+ * log_write_header - Get and initialize a journal header buffer
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the initialized log buffer descriptor
+ */
+
+static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
+{
+       u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+       struct buffer_head *bh;
+       struct gfs2_log_header *lh;
+       unsigned int tail;
+       u32 hash;
+
+       bh = sb_getblk(sdp->sd_vfs, blkno);
+       lock_buffer(bh);
+       memset(bh->b_data, 0, bh->b_size);
+       set_buffer_uptodate(bh);
+       clear_buffer_dirty(bh);
+
+       gfs2_ail1_empty(sdp);
+       tail = current_tail(sdp);
+
+       lh = (struct gfs2_log_header *)bh->b_data;
+       memset(lh, 0, sizeof(struct gfs2_log_header));
+       lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+       lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+       lh->lh_header.__pad0 = cpu_to_be64(0);
+       lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+       lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
+       lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
+       lh->lh_flags = cpu_to_be32(flags);
+       lh->lh_tail = cpu_to_be32(tail);
+       lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
+       hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+       lh->lh_hash = cpu_to_be32(hash);
+
+       bh->b_end_io = end_buffer_write_sync;
+       get_bh(bh);
+       if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
+               gfs2_ordered_wait(sdp);
+               log_flush_wait(sdp);
+               submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
+       } else {
+               submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
+       }
+       wait_on_buffer(bh);
+
+       if (!buffer_uptodate(bh))
+               gfs2_io_error_bh(sdp, bh);
+       brelse(bh);
+
+       if (sdp->sd_log_tail != tail)
+               log_pull_tail(sdp, tail);
+       else
+               gfs2_assert_withdraw(sdp, !pull);
+
+       sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
+       gfs2_log_incr_head(sdp);
+}
+
 /**
  * gfs2_log_flush - flush incore transaction(s)
  * @sdp: the filesystem
@@ -753,11 +678,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
 
        gfs2_ordered_write(sdp);
        lops_before_commit(sdp);
-       gfs2_ordered_wait(sdp);
 
-       if (sdp->sd_log_head != sdp->sd_log_flush_head)
-               log_flush_commit(sdp);
-       else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
+       if (sdp->sd_log_head != sdp->sd_log_flush_head) {
+               log_write_header(sdp, 0, 0);
+       else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
                gfs2_log_lock(sdp);
                atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
                trace_gfs2_log_blocks(sdp, -1);
index ab06216..ff07454 100644 (file)
@@ -53,10 +53,7 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
 
 extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
 extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
-
-extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
-extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
-                                     struct buffer_head *real);
+extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn);
 extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
 extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
 extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
index df7c6e8..6b1efb5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
+#include <linux/mempool.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/bio.h>
 #include <linux/fs.h>
@@ -76,7 +77,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
        if (bi->bi_clone == 0)
                return;
        if (sdp->sd_args.ar_discard)
-               gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
+               gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
        memcpy(bi->bi_clone + bi->bi_offset,
               bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
        clear_bit(GBF_FULL, &bi->bi_flags);
@@ -143,6 +144,98 @@ static inline __be64 *bh_ptr_end(struct buffer_head *bh)
        return (__force __be64 *)(bh->b_data + bh->b_size);
 }
 
+/**
+ * gfs2_log_write_endio - End of I/O for a log buffer
+ * @bh: The buffer head
+ * @uptodate: I/O Status
+ *
+ */
+
+static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
+{
+       struct gfs2_sbd *sdp = bh->b_private;
+       bh->b_private = NULL;
+
+       end_buffer_write_sync(bh, uptodate);
+       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+               wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
+ * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
+ * @sdp: The GFS2 superblock
+ *
+ * tReturns: the buffer_head
+ */
+
+static struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
+{
+       u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+       struct buffer_head *bh;
+
+       bh = sb_getblk(sdp->sd_vfs, blkno);
+       lock_buffer(bh);
+       memset(bh->b_data, 0, bh->b_size);
+       set_buffer_uptodate(bh);
+       clear_buffer_dirty(bh);
+       gfs2_log_incr_head(sdp);
+       atomic_inc(&sdp->sd_log_in_flight);
+       bh->b_private = sdp;
+       bh->b_end_io = gfs2_log_write_endio;
+
+       return bh;
+}
+
+/**
+ * gfs2_fake_write_endio - 
+ * @bh: The buffer head
+ * @uptodate: The I/O Status
+ *
+ */
+
+static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
+{
+       struct buffer_head *real_bh = bh->b_private;
+       struct gfs2_bufdata *bd = real_bh->b_private;
+       struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
+
+       end_buffer_write_sync(bh, uptodate);
+       mempool_free(bh, gfs2_bh_pool);
+       unlock_buffer(real_bh);
+       brelse(real_bh);
+       if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+               wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
+ * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
+ * @sdp: the filesystem
+ * @data: the data the buffer_head should point to
+ *
+ * Returns: the log buffer descriptor
+ */
+
+static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+                                     struct buffer_head *real)
+{
+       u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
+       struct buffer_head *bh;
+
+       bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS);
+       atomic_set(&bh->b_count, 1);
+       bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
+       set_bh_page(bh, real->b_page, bh_offset(real));
+       bh->b_blocknr = blkno;
+       bh->b_size = sdp->sd_sb.sb_bsize;
+       bh->b_bdev = sdp->sd_vfs->s_bdev;
+       bh->b_private = real;
+       bh->b_end_io = gfs2_fake_write_endio;
+
+       gfs2_log_incr_head(sdp);
+       atomic_inc(&sdp->sd_log_in_flight);
+
+       return bh;
+}
 
 static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
 {
index a8d9bcd..754426b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/rcupdate.h>
 #include <linux/rculist_bl.h>
 #include <linux/atomic.h>
+#include <linux/mempool.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -69,6 +70,16 @@ static void gfs2_init_gl_aspace_once(void *foo)
        address_space_init_once(mapping);
 }
 
+static void *gfs2_bh_alloc(gfp_t mask, void *data)
+{
+       return alloc_buffer_head(mask);
+}
+
+static void gfs2_bh_free(void *ptr, void *data)
+{
+       return free_buffer_head(ptr);
+}
+
 /**
  * init_gfs2_fs - Register GFS2 as a filesystem
  *
@@ -151,6 +162,10 @@ static int __init init_gfs2_fs(void)
        gfs2_control_wq = alloc_workqueue("gfs2_control",
                               WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
        if (!gfs2_control_wq)
+               goto fail_recovery;
+
+       gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL);
+       if (!gfs2_bh_pool)
                goto fail_control;
 
        gfs2_register_debugfs();
@@ -160,6 +175,8 @@ static int __init init_gfs2_fs(void)
        return 0;
 
 fail_control:
+       destroy_workqueue(gfs2_control_wq);
+fail_recovery:
        destroy_workqueue(gfs_recovery_wq);
 fail_wq:
        unregister_filesystem(&gfs2meta_fs_type);
@@ -208,6 +225,7 @@ static void __exit exit_gfs2_fs(void)
 
        rcu_barrier();
 
+       mempool_destroy(gfs2_bh_pool);
        kmem_cache_destroy(gfs2_quotad_cachep);
        kmem_cache_destroy(gfs2_rgrpd_cachep);
        kmem_cache_destroy(gfs2_bufdata_cachep);
index 24f609c..6f3a18f 100644 (file)
@@ -68,6 +68,12 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        sb->s_fs_info = sdp;
        sdp->sd_vfs = sb;
+       sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
+       if (!sdp->sd_lkstats) {
+               kfree(sdp);
+               return NULL;
+       }
+
        set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
        gfs2_tune_init(&sdp->sd_tune);
 
@@ -77,7 +83,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
        spin_lock_init(&sdp->sd_statfs_spin);
 
        spin_lock_init(&sdp->sd_rindex_spin);
-       mutex_init(&sdp->sd_rindex_mutex);
        sdp->sd_rindex_tree.rb_node = NULL;
 
        INIT_LIST_HEAD(&sdp->sd_jindex_list);
@@ -431,10 +436,9 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr,
                fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode));
                return PTR_ERR(inode);
        }
-       dentry = d_alloc_root(inode);
+       dentry = d_make_root(inode);
        if (!dentry) {
                fs_err(sdp, "can't alloc %s dentry\n", name);
-               iput(inode);
                return -ENOMEM;
        }
        *dptr = dentry;
@@ -1221,6 +1225,7 @@ fail_sys:
        gfs2_sys_fs_del(sdp);
 fail:
        gfs2_delete_debugfs_file(sdp);
+       free_percpu(sdp->sd_lkstats);
        kfree(sdp);
        sb->s_fs_info = NULL;
        return error;
@@ -1393,6 +1398,7 @@ static void gfs2_kill_sb(struct super_block *sb)
        shrink_dcache_sb(sb);
        kill_block_super(sb);
        gfs2_delete_debugfs_file(sdp);
+       free_percpu(sdp->sd_lkstats);
        kfree(sdp);
 }
 
index c0f8904..6019da3 100644 (file)
@@ -681,7 +681,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        ptr = qp;
        nbytes = sizeof(struct gfs2_quota);
 get_a_page:
-       page = grab_cache_page(mapping, index);
+       page = find_or_create_page(mapping, index, GFP_NOFS);
        if (!page)
                return -ENOMEM;
 
index 49ada95..19bde40 100644 (file)
@@ -327,23 +327,34 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
  * Returns: The resource group, or NULL if not found
  */
 
-struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact)
 {
-       struct rb_node **newn;
+       struct rb_node *n, *next;
        struct gfs2_rgrpd *cur;
 
+       if (gfs2_rindex_update(sdp))
+               return NULL;
+
        spin_lock(&sdp->sd_rindex_spin);
-       newn = &sdp->sd_rindex_tree.rb_node;
-       while (*newn) {
-               cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
+       n = sdp->sd_rindex_tree.rb_node;
+       while (n) {
+               cur = rb_entry(n, struct gfs2_rgrpd, rd_node);
+               next = NULL;
                if (blk < cur->rd_addr)
-                       newn = &((*newn)->rb_left);
+                       next = n->rb_left;
                else if (blk >= cur->rd_data0 + cur->rd_data)
-                       newn = &((*newn)->rb_right);
-               else {
+                       next = n->rb_right;
+               if (next == NULL) {
                        spin_unlock(&sdp->sd_rindex_spin);
+                       if (exact) {
+                               if (blk < cur->rd_addr)
+                                       return NULL;
+                               if (blk >= cur->rd_data0 + cur->rd_data)
+                                       return NULL;
+                       }
                        return cur;
                }
+               n = next;
        }
        spin_unlock(&sdp->sd_rindex_spin);
 
@@ -532,7 +543,6 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
        struct file_ra_state ra_state;
        int error, rgrps;
 
-       mutex_lock(&sdp->sd_rindex_mutex);
        file_ra_state_init(&ra_state, inode->i_mapping);
        for (rgrps = 0;; rgrps++) {
                loff_t pos = rgrps * sizeof(struct gfs2_rindex);
@@ -545,11 +555,10 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
                        break;
                total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data);
        }
-       mutex_unlock(&sdp->sd_rindex_mutex);
        return total_data;
 }
 
-static void rgd_insert(struct gfs2_rgrpd *rgd)
+static int rgd_insert(struct gfs2_rgrpd *rgd)
 {
        struct gfs2_sbd *sdp = rgd->rd_sbd;
        struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
@@ -565,11 +574,13 @@ static void rgd_insert(struct gfs2_rgrpd *rgd)
                else if (rgd->rd_addr > cur->rd_addr)
                        newn = &((*newn)->rb_right);
                else
-                       return;
+                       return -EEXIST;
        }
 
        rb_link_node(&rgd->rd_node, parent, newn);
        rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
+       sdp->sd_rgrps++;
+       return 0;
 }
 
 /**
@@ -623,10 +634,12 @@ static int read_rindex_entry(struct gfs2_inode *ip,
        if (rgd->rd_data > sdp->sd_max_rg_data)
                sdp->sd_max_rg_data = rgd->rd_data;
        spin_lock(&sdp->sd_rindex_spin);
-       rgd_insert(rgd);
-       sdp->sd_rgrps++;
+       error = rgd_insert(rgd);
        spin_unlock(&sdp->sd_rindex_spin);
-       return error;
+       if (!error)
+               return 0;
+
+       error = 0; /* someone else read in the rgrp; free it and ignore it */
 
 fail:
        kfree(rgd->rd_bits);
@@ -687,7 +700,6 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp)
 
        /* Read new copy from disk if we don't have the latest */
        if (!sdp->sd_rindex_uptodate) {
-               mutex_lock(&sdp->sd_rindex_mutex);
                if (!gfs2_glock_is_locked_by_me(gl)) {
                        error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
                        if (error)
@@ -698,10 +710,8 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp)
                        error = gfs2_ri_update(ip);
                if (unlock_required)
                        gfs2_glock_dq_uninit(&ri_gh);
-               mutex_unlock(&sdp->sd_rindex_mutex);
        }
 
-
        return error;
 }
 
@@ -810,9 +820,9 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
 
 }
 
-void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                             struct buffer_head *bh,
-                            const struct gfs2_bitmap *bi)
+                            const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
 {
        struct super_block *sb = sdp->sd_vfs;
        struct block_device *bdev = sb->s_bdev;
@@ -823,11 +833,19 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
        sector_t nr_sects = 0;
        int rv;
        unsigned int x;
+       u32 trimmed = 0;
+       u8 diff;
 
        for (x = 0; x < bi->bi_len; x++) {
-               const u8 *orig = bh->b_data + bi->bi_offset + x;
-               const u8 *clone = bi->bi_clone + bi->bi_offset + x;
-               u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
+               const u8 *clone = bi->bi_clone ? bi->bi_clone : bi->bi_bh->b_data;
+               clone += bi->bi_offset;
+               clone += x;
+               if (bh) {
+                       const u8 *orig = bh->b_data + bi->bi_offset + x;
+                       diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
+               } else {
+                       diff = ~(*clone | (*clone >> 1));
+               }
                diff &= 0x55;
                if (diff == 0)
                        continue;
@@ -838,11 +856,14 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                                if (nr_sects == 0)
                                        goto start_new_extent;
                                if ((start + nr_sects) != blk) {
-                                       rv = blkdev_issue_discard(bdev, start,
-                                                           nr_sects, GFP_NOFS,
-                                                           0);
-                                       if (rv)
-                                               goto fail;
+                                       if (nr_sects >= minlen) {
+                                               rv = blkdev_issue_discard(bdev,
+                                                       start, nr_sects,
+                                                       GFP_NOFS, 0);
+                                               if (rv)
+                                                       goto fail;
+                                               trimmed += nr_sects;
+                                       }
                                        nr_sects = 0;
 start_new_extent:
                                        start = blk;
@@ -853,15 +874,104 @@ start_new_extent:
                        blk += sects_per_blk;
                }
        }
-       if (nr_sects) {
+       if (nr_sects >= minlen) {
                rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
                if (rv)
                        goto fail;
+               trimmed += nr_sects;
        }
-       return;
+       if (ptrimmed)
+               *ptrimmed = trimmed;
+       return 0;
+
 fail:
-       fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
+       if (sdp->sd_args.ar_discard)
+               fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
        sdp->sd_args.ar_discard = 0;
+       return -EIO;
+}
+
+/**
+ * gfs2_fitrim - Generate discard requests for unused bits of the filesystem
+ * @filp: Any file on the filesystem
+ * @argp: Pointer to the arguments (also used to pass result)
+ *
+ * Returns: 0 on success, otherwise error code
+ */
+
+int gfs2_fitrim(struct file *filp, void __user *argp)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct request_queue *q = bdev_get_queue(sdp->sd_vfs->s_bdev);
+       struct buffer_head *bh;
+       struct gfs2_rgrpd *rgd;
+       struct gfs2_rgrpd *rgd_end;
+       struct gfs2_holder gh;
+       struct fstrim_range r;
+       int ret = 0;
+       u64 amt;
+       u64 trimmed = 0;
+       unsigned int x;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!blk_queue_discard(q))
+               return -EOPNOTSUPP;
+
+       if (argp == NULL) {
+               r.start = 0;
+               r.len = ULLONG_MAX;
+               r.minlen = 0;
+       } else if (copy_from_user(&r, argp, sizeof(r)))
+               return -EFAULT;
+
+       rgd = gfs2_blk2rgrpd(sdp, r.start, 0);
+       rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0);
+
+       while (1) {
+
+               ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &gh);
+               if (ret)
+                       goto out;
+
+               if (!(rgd->rd_flags & GFS2_RGF_TRIMMED)) {
+                       /* Trim each bitmap in the rgrp */
+                       for (x = 0; x < rgd->rd_length; x++) {
+                               struct gfs2_bitmap *bi = rgd->rd_bits + x;
+                               ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt);
+                               if (ret) {
+                                       gfs2_glock_dq_uninit(&gh);
+                                       goto out;
+                               }
+                               trimmed += amt;
+                       }
+
+                       /* Mark rgrp as having been trimmed */
+                       ret = gfs2_trans_begin(sdp, RES_RG_HDR, 0);
+                       if (ret == 0) {
+                               bh = rgd->rd_bits[0].bi_bh;
+                               rgd->rd_flags |= GFS2_RGF_TRIMMED;
+                               gfs2_trans_add_bh(rgd->rd_gl, bh, 1);
+                               gfs2_rgrp_out(rgd, bh->b_data);
+                               gfs2_trans_end(sdp);
+                       }
+               }
+               gfs2_glock_dq_uninit(&gh);
+
+               if (rgd == rgd_end)
+                       break;
+
+               rgd = gfs2_rgrpd_get_next(rgd);
+       }
+
+out:
+       r.len = trimmed << 9;
+       if (argp && copy_to_user(argp, &r, sizeof(r)))
+               return -EFAULT;
+
+       return ret;
 }
 
 /**
@@ -1008,7 +1118,7 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
        if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
                rgd = begin = ip->i_rgd;
        else
-               rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
+               rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
 
        if (rgd == NULL)
                return -EBADSLT;
@@ -1293,7 +1403,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
        u32 length, rgrp_blk, buf_blk;
        unsigned int buf;
 
-       rgd = gfs2_blk2rgrpd(sdp, bstart);
+       rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
        if (!rgd) {
                if (gfs2_consist(sdp))
                        fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
@@ -1474,7 +1584,7 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
                return;
        trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
        rgd->rd_free += blen;
-
+       rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
        gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
        gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
 
@@ -1560,14 +1670,9 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
 {
        struct gfs2_rgrpd *rgd;
        struct gfs2_holder rgd_gh;
-       int error;
-
-       error = gfs2_rindex_update(sdp);
-       if (error)
-               return error;
+       int error = -EINVAL;
 
-       error = -EINVAL;
-       rgd = gfs2_blk2rgrpd(sdp, no_addr);
+       rgd = gfs2_blk2rgrpd(sdp, no_addr, 1);
        if (!rgd)
                goto fail;
 
@@ -1610,7 +1715,7 @@ void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
        if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
                rgd = ip->i_rgd;
        else
-               rgd = gfs2_blk2rgrpd(sdp, block);
+               rgd = gfs2_blk2rgrpd(sdp, block, 1);
        if (!rgd) {
                fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
                return;
index ceec910..b4b10f4 100644 (file)
@@ -11,6 +11,7 @@
 #define __RGRP_DOT_H__
 
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 struct gfs2_rgrpd;
 struct gfs2_sbd;
@@ -18,7 +19,7 @@ struct gfs2_holder;
 
 extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
 
-extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
+extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact);
 extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
 extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
 
@@ -62,8 +63,9 @@ extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
 extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
 extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
 extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
-extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
-                                   struct buffer_head *bh,
-                                   const struct gfs2_bitmap *bi);
+extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
+                                  struct buffer_head *bh,
+                                  const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
+extern int gfs2_fitrim(struct file *filp, void __user *argp);
 
 #endif /* __RGRP_DOT_H__ */
index 4553ce5..6172fa7 100644 (file)
@@ -1417,7 +1417,7 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
        if (error)
                goto out;
 
-       rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
+       rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
        if (!rgd) {
                gfs2_consist_inode(ip);
                error = -EIO;
@@ -1557,6 +1557,7 @@ out:
        end_writeback(inode);
        gfs2_dir_hash_inval(ip);
        ip->i_gl->gl_object = NULL;
+       flush_delayed_work_sync(&ip->i_gl->gl_work);
        gfs2_glock_add_to_lru(ip->i_gl);
        gfs2_glock_put(ip->i_gl);
        ip->i_gl = NULL;
index 5d07609..dfa89cd 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/dlmconstants.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/writeback.h>
+#include <linux/ktime.h>
 #include "incore.h"
 #include "glock.h"
 
@@ -43,7 +44,8 @@
        {(1UL << GLF_FROZEN),                   "F" },          \
        {(1UL << GLF_QUEUED),                   "q" },          \
        {(1UL << GLF_LRU),                      "L" },          \
-       {(1UL << GLF_OBJECT),                   "o" })
+       {(1UL << GLF_OBJECT),                   "o" },          \
+       {(1UL << GLF_BLOCKING),                 "b" })
 
 #ifndef NUMPTY
 #define NUMPTY
@@ -236,6 +238,62 @@ TRACE_EVENT(gfs2_glock_queue,
                  glock_trace_name(__entry->state))
 );
 
+/* DLM sends a reply to GFS2 */
+TRACE_EVENT(gfs2_glock_lock_time,
+
+       TP_PROTO(const struct gfs2_glock *gl, s64 tdiff),
+
+       TP_ARGS(gl, tdiff),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev             )
+               __field(        u64,    glnum           )
+               __field(        u32,    gltype          )
+               __field(        int,    status          )
+               __field(        char,   flags           )
+               __field(        s64,    tdiff           )
+               __field(        s64,    srtt            )
+               __field(        s64,    srttvar         )
+               __field(        s64,    srttb           )
+               __field(        s64,    srttvarb        )
+               __field(        s64,    sirt            )
+               __field(        s64,    sirtvar         )
+               __field(        s64,    dcount          )
+               __field(        s64,    qcount          )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = gl->gl_sbd->sd_vfs->s_dev;
+               __entry->glnum          = gl->gl_name.ln_number;
+               __entry->gltype         = gl->gl_name.ln_type;
+               __entry->status         = gl->gl_lksb.sb_status;
+               __entry->flags          = gl->gl_lksb.sb_flags;
+               __entry->tdiff          = tdiff;
+               __entry->srtt           = gl->gl_stats.stats[GFS2_LKS_SRTT];
+               __entry->srttvar        = gl->gl_stats.stats[GFS2_LKS_SRTTVAR];
+               __entry->srttb          = gl->gl_stats.stats[GFS2_LKS_SRTTB];
+               __entry->srttvarb       = gl->gl_stats.stats[GFS2_LKS_SRTTVARB];
+               __entry->sirt           = gl->gl_stats.stats[GFS2_LKS_SIRT];
+               __entry->sirtvar        = gl->gl_stats.stats[GFS2_LKS_SIRTVAR];
+               __entry->dcount         = gl->gl_stats.stats[GFS2_LKS_DCOUNT];
+               __entry->qcount         = gl->gl_stats.stats[GFS2_LKS_QCOUNT];
+       ),
+
+       TP_printk("%u,%u glock %d:%lld status:%d flags:%02x tdiff:%lld srtt:%lld/%lld srttb:%lld/%lld sirt:%lld/%lld dcnt:%lld qcnt:%lld",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
+                 (unsigned long long)__entry->glnum,
+                 __entry->status, __entry->flags,
+                 (long long)__entry->tdiff,
+                 (long long)__entry->srtt,
+                 (long long)__entry->srttvar,
+                 (long long)__entry->srttb,
+                 (long long)__entry->srttvarb,
+                 (long long)__entry->sirt,
+                 (long long)__entry->sirtvar,
+                 (long long)__entry->dcount,
+                 (long long)__entry->qcount)
+);
+
 /* Section 2 - Log/journal
  *
  * Objectives:
index 5351129..9e7765e 100644 (file)
@@ -25,6 +25,7 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly;
 struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
 struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
 struct kmem_cache *gfs2_quotad_cachep __read_mostly;
+mempool_t *gfs2_bh_pool __read_mostly;
 
 void gfs2_assert_i(struct gfs2_sbd *sdp)
 {
index b432e04..a4ce76c 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef __UTIL_DOT_H__
 #define __UTIL_DOT_H__
 
+#include <linux/mempool.h>
+
 #include "incore.h"
 
 #define fs_printk(level, fs, fmt, arg...) \
@@ -150,6 +152,7 @@ extern struct kmem_cache *gfs2_inode_cachep;
 extern struct kmem_cache *gfs2_bufdata_cachep;
 extern struct kmem_cache *gfs2_rgrpd_cachep;
 extern struct kmem_cache *gfs2_quotad_cachep;
+extern mempool_t *gfs2_bh_pool;
 
 static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
                                           unsigned int *p)
index e963659..2e5ba42 100644 (file)
@@ -251,7 +251,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
        if (!blks)
                return 0;
 
-       rgd = gfs2_blk2rgrpd(sdp, bn);
+       rgd = gfs2_blk2rgrpd(sdp, bn, 1);
        if (!rgd) {
                gfs2_consist_inode(ip);
                return -EIO;
@@ -1439,7 +1439,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip)
        struct gfs2_holder gh;
        int error;
 
-       rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr);
+       rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1);
        if (!rgd) {
                gfs2_consist_inode(ip);
                return -EIO;
index 8137fb3..7b4c537 100644 (file)
@@ -430,15 +430,13 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
 
        sb->s_d_op = &hfs_dentry_operations;
        res = -ENOMEM;
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (!sb->s_root)
-               goto bail_iput;
+               goto bail_no_root;
 
        /* everything's okay */
        return 0;
 
-bail_iput:
-       iput(root_inode);
 bail_no_root:
        printk(KERN_ERR "hfs: get root inode failed.\n");
 bail:
index 21a5b7f..4e75ac6 100644 (file)
@@ -316,6 +316,11 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
 #define HFSPLUS_IOC_EXT2_SETFLAGS      FS_IOC_SETFLAGS
 
 
+/*
+ * hfs+-specific ioctl for making the filesystem bootable
+ */
+#define HFSPLUS_IOC_BLESS _IO('h', 0x80)
+
 /*
  * Functions in any *.c used in other files
  */
index 927cdd6..921967e 100644 (file)
@@ -117,7 +117,7 @@ struct hfsplus_vh {
        __be32 write_count;
        __be64 encodings_bmp;
 
-       u8 finder_info[32];
+       u32 finder_info[8];
 
        struct hfsplus_fork_raw alloc_file;
        struct hfsplus_fork_raw ext_file;
index 6643b24..82b69ee 100644 (file)
@@ -193,6 +193,7 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir,
        mutex_init(&hip->extents_lock);
        hip->extent_state = 0;
        hip->flags = 0;
+       hip->userflags = 0;
        set_bit(HFSPLUS_I_RSRC, &hip->flags);
 
        err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
@@ -400,6 +401,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
        atomic_set(&hip->opencnt, 0);
        hip->extent_state = 0;
        hip->flags = 0;
+       hip->userflags = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
        hip->alloc_blocks = 0;
index f66c765..c640ba5 100644 (file)
 #include <asm/uaccess.h>
 #include "hfsplus_fs.h"
 
+/*
+ * "Blessing" an HFS+ filesystem writes metadata to the superblock informing
+ * the platform firmware which file to boot from
+ */
+static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+       struct hfsplus_vh *vh = sbi->s_vhdr;
+       struct hfsplus_vh *bvh = sbi->s_backup_vhdr;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       mutex_lock(&sbi->vh_mutex);
+
+       /* Directory containing the bootable system */
+       vh->finder_info[0] = bvh->finder_info[0] =
+               cpu_to_be32(parent_ino(dentry));
+
+       /* Bootloader */
+       vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(inode->i_ino);
+
+       /* Per spec, the OS X system folder - same as finder_info[0] here */
+       vh->finder_info[5] = bvh->finder_info[5] =
+               cpu_to_be32(parent_ino(dentry));
+
+       mutex_unlock(&sbi->vh_mutex);
+       return 0;
+}
+
 static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
@@ -108,6 +140,8 @@ long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return hfsplus_ioctl_getflags(file, argp);
        case HFSPLUS_IOC_EXT2_SETFLAGS:
                return hfsplus_ioctl_setflags(file, argp);
+       case HFSPLUS_IOC_BLESS:
+               return hfsplus_ioctl_bless(file, argp);
        default:
                return -ENOTTY;
        }
index 427682c..ceb1c28 100644 (file)
@@ -465,6 +465,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                goto out_put_alloc_file;
        }
 
+       sb->s_d_op = &hfsplus_dentry_operations;
+       sb->s_root = d_make_root(root);
+       if (!sb->s_root) {
+               err = -ENOMEM;
+               goto out_put_alloc_file;
+       }
+
        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
        str.name = HFSP_HIDDENDIR_NAME;
        err = hfs_find_init(sbi->cat_tree, &fd);
@@ -515,13 +522,6 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       sb->s_d_op = &hfsplus_dentry_operations;
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               err = -ENOMEM;
-               goto out_put_hidden_dir;
-       }
-
        unload_nls(sbi->nls);
        sbi->nls = nls;
        return 0;
@@ -529,7 +529,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 out_put_hidden_dir:
        iput(sbi->hidden_dir);
 out_put_root:
-       iput(root);
+       dput(sb->s_root);
+       sb->s_root = NULL;
 out_put_alloc_file:
        iput(sbi->alloc_file);
 out_close_cat_tree:
index e130bd4..588d458 100644 (file)
@@ -966,9 +966,9 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
        }
 
        err = -ENOMEM;
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (sb->s_root == NULL)
-               goto out_put;
+               goto out;
 
        return 0;
 
index 3690467..54f6ecc 100644 (file)
@@ -625,11 +625,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
        hpfs_init_inode(root);
        hpfs_read_inode(root);
        unlock_new_inode(root);
-       s->s_root = d_alloc_root(root);
-       if (!s->s_root) {
-               iput(root);
+       s->s_root = d_make_root(root);
+       if (!s->s_root)
                goto bail0;
-       }
 
        /*
         * find the root directory's . pointer & finish filling in the inode
index d92f4ce..a80e45a 100644 (file)
@@ -726,17 +726,12 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
 
        err = -ENOMEM;
        root_inode = get_inode(sb, dget(proc_mnt->mnt_root));
-       if (!root_inode)
-               goto out_mntput;
-
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (!sb->s_root)
-               goto out_iput;
+               goto out_mntput;
 
        return 0;
 
- out_iput:
-       iput(root_inode);
  out_mntput:
        mntput(proc_mnt);
  out:
index 2691633..ea25174 100644 (file)
@@ -860,8 +860,6 @@ bad_val:
 static int
 hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
 {
-       struct inode * inode;
-       struct dentry * root;
        int ret;
        struct hugetlbfs_config config;
        struct hugetlbfs_sb_info *sbinfo;
@@ -898,16 +896,9 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = HUGETLBFS_MAGIC;
        sb->s_op = &hugetlbfs_ops;
        sb->s_time_gran = 1;
-       inode = hugetlbfs_get_root(sb, &config);
-       if (!inode)
-               goto out_free;
-
-       root = d_alloc_root(inode);
-       if (!root) {
-               iput(inode);
+       sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config));
+       if (!sb->s_root)
                goto out_free;
-       }
-       sb->s_root = root;
        return 0;
 out_free:
        if (sbinfo->spool)
index 83ab215..9f4f5fe 100644 (file)
@@ -2,29 +2,19 @@
  * (C) 1997 Linus Torvalds
  * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
  */
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/dcache.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/writeback.h>
-#include <linux/module.h>
 #include <linux/backing-dev.h>
-#include <linux/wait.h>
-#include <linux/rwsem.h>
 #include <linux/hash.h>
 #include <linux/swap.h>
 #include <linux/security.h>
-#include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
 #include <linux/fsnotify.h>
 #include <linux/mount.h>
-#include <linux/async.h>
 #include <linux/posix_acl.h>
 #include <linux/prefetch.h>
-#include <linux/ima.h>
-#include <linux/cred.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
 #include "internal.h"
@@ -1368,17 +1358,6 @@ int generic_delete_inode(struct inode *inode)
 }
 EXPORT_SYMBOL(generic_delete_inode);
 
-/*
- * Normal UNIX filesystem behaviour: delete the
- * inode when the usage count drops to zero, and
- * i_nlink is zero.
- */
-int generic_drop_inode(struct inode *inode)
-{
-       return !inode->i_nlink || inode_unhashed(inode);
-}
-EXPORT_SYMBOL_GPL(generic_drop_inode);
-
 /*
  * Called when we're dropping the last reference
  * to an inode.
@@ -1510,9 +1489,10 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
  *     This function automatically handles read only file systems and media,
  *     as well as the "noatime" flag and inode specific "noatime" markers.
  */
-void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
+void touch_atime(struct path *path)
 {
-       struct inode *inode = dentry->d_inode;
+       struct vfsmount *mnt = path->mnt;
+       struct inode *inode = path->dentry->d_inode;
        struct timespec now;
 
        if (inode->i_flags & S_NOATIME)
index bd62c76..29037c3 100644 (file)
@@ -947,9 +947,8 @@ root_found:
        s->s_d_op = &isofs_dentry_ops[table];
 
        /* get the root dentry */
-       s->s_root = d_alloc_root(inode);
+       s->s_root = d_make_root(inode);
        if (!(s->s_root)) {
-               iput(inode);
                error = -ENOMEM;
                goto out_no_inode;
        }
index 2e01238..c0d5c9d 100644 (file)
@@ -561,9 +561,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        ret = -ENOMEM;
 
        D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
-       sb->s_root = d_alloc_root(root_i);
+       sb->s_root = d_make_root(root_i);
        if (!sb->s_root)
-               goto out_root_i;
+               goto out_root;
 
        sb->s_maxbytes = 0xFFFFFFFF;
        sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -573,8 +573,6 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
                jffs2_start_garbage_collect_thread(c);
        return 0;
 
- out_root_i:
-       iput(root_i);
 out_root:
        jffs2_free_ino_caches(c);
        jffs2_free_raw_node_refs(c);
index 5f7c160..07c91ca 100644 (file)
@@ -220,12 +220,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
 
        dquot_initialize(dip);
 
-       /* link count overflow on parent directory ? */
-       if (dip->i_nlink == JFS_LINK_MAX) {
-               rc = -EMLINK;
-               goto out1;
-       }
-
        /*
         * search parent directory for entry/freespace
         * (dtSearch() returns parent directory page pinned)
@@ -806,9 +800,6 @@ static int jfs_link(struct dentry *old_dentry,
        jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
                 dentry->d_name.name);
 
-       if (ip->i_nlink == JFS_LINK_MAX)
-               return -EMLINK;
-
        dquot_initialize(dir);
 
        tid = txBegin(ip->i_sb, 0);
@@ -1138,10 +1129,6 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                rc = -ENOTEMPTY;
                                goto out3;
                        }
-               } else if ((new_dir != old_dir) &&
-                          (new_dir->i_nlink == JFS_LINK_MAX)) {
-                       rc = -EMLINK;
-                       goto out3;
                }
        } else if (new_ip) {
                IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
index 682bca6..4a82950 100644 (file)
@@ -441,6 +441,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
 
        sb->s_fs_info = sbi;
+       sb->s_max_links = JFS_LINK_MAX;
        sbi->sb = sb;
        sbi->uid = sbi->gid = sbi->umask = -1;
 
@@ -521,7 +522,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
                ret = PTR_ERR(inode);
                goto out_no_rw;
        }
-       sb->s_root = d_alloc_root(inode);
+       sb->s_root = d_make_root(inode);
        if (!sb->s_root)
                goto out_no_root;
 
@@ -539,7 +540,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
 
 out_no_root:
        jfs_err("jfs_read_super: get root dentry failed");
-       iput(inode);
 
 out_no_rw:
        rc = jfs_umount(sb);
@@ -860,8 +860,14 @@ static int __init init_jfs_fs(void)
        jfs_proc_init();
 #endif
 
-       return register_filesystem(&jfs_fs_type);
+       rc = register_filesystem(&jfs_fs_type);
+       if (!rc)
+               return 0;
 
+#ifdef PROC_FS_JFS
+       jfs_proc_clean();
+#endif
+       kthread_stop(jfsSyncThread);
 kill_committask:
        for (i = 0; i < commit_threads; i++)
                kthread_stop(jfsCommitThread[i]);
index 5b2dbb3..722e0d5 100644 (file)
@@ -491,11 +491,9 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        set_nlink(inode, 2);
-       root = d_alloc_root(inode);
-       if (!root) {
-               iput(inode);
+       root = d_make_root(inode);
+       if (!root)
                return -ENOMEM;
-       }
        for (i = 0; !files->name || files->name[0]; i++, files++) {
                if (!files->name)
                        continue;
@@ -536,7 +534,7 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *c
        spin_lock(&pin_fs_lock);
        if (unlikely(!*mount)) {
                spin_unlock(&pin_fs_lock);
-               mnt = vfs_kern_mount(type, 0, type->name, NULL);
+               mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL);
                if (IS_ERR(mnt))
                        return PTR_ERR(mnt);
                spin_lock(&pin_fs_lock);
index 1b6e21d..bea5d1b 100644 (file)
@@ -558,9 +558,6 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir,
 {
        struct inode *inode = old_dentry->d_inode;
 
-       if (inode->i_nlink >= LOGFS_LINK_MAX)
-               return -EMLINK;
-
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        ihold(inode);
        inc_nlink(inode);
index c9ee7f5..97bca62 100644 (file)
@@ -315,11 +315,9 @@ static int logfs_get_sb_final(struct super_block *sb)
        if (IS_ERR(rootdir))
                goto fail;
 
-       sb->s_root = d_alloc_root(rootdir);
-       if (!sb->s_root) {
-               iput(rootdir);
+       sb->s_root = d_make_root(rootdir);
+       if (!sb->s_root)
                goto fail;
-       }
 
        /* at that point we know that ->put_super() will be called */
        super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
@@ -542,6 +540,7 @@ static struct dentry *logfs_get_sb_device(struct logfs_super *super,
         * the filesystem incompatible with 32bit systems.
         */
        sb->s_maxbytes  = (1ull << 43) - 1;
+       sb->s_max_links = LOGFS_LINK_MAX;
        sb->s_op        = &logfs_super_operations;
        sb->s_flags     = flags | MS_NOATIME;
 
@@ -627,7 +626,10 @@ static int __init logfs_init(void)
        if (ret)
                goto out2;
 
-       return register_filesystem(&logfs_fs_type);
+       ret = register_filesystem(&logfs_fs_type);
+       if (!ret)
+               return 0;
+       logfs_destroy_inode_cache();
 out2:
        logfs_compr_exit();
 out1:
index fa8b612..fcb05d2 100644 (file)
@@ -190,24 +190,24 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
                sbi->s_version = MINIX_V1;
                sbi->s_dirsize = 16;
                sbi->s_namelen = 14;
-               sbi->s_link_max = MINIX_LINK_MAX;
+               s->s_max_links = MINIX_LINK_MAX;
        } else if (s->s_magic == MINIX_SUPER_MAGIC2) {
                sbi->s_version = MINIX_V1;
                sbi->s_dirsize = 32;
                sbi->s_namelen = 30;
-               sbi->s_link_max = MINIX_LINK_MAX;
+               s->s_max_links = MINIX_LINK_MAX;
        } else if (s->s_magic == MINIX2_SUPER_MAGIC) {
                sbi->s_version = MINIX_V2;
                sbi->s_nzones = ms->s_zones;
                sbi->s_dirsize = 16;
                sbi->s_namelen = 14;
-               sbi->s_link_max = MINIX2_LINK_MAX;
+               s->s_max_links = MINIX2_LINK_MAX;
        } else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
                sbi->s_version = MINIX_V2;
                sbi->s_nzones = ms->s_zones;
                sbi->s_dirsize = 32;
                sbi->s_namelen = 30;
-               sbi->s_link_max = MINIX2_LINK_MAX;
+               s->s_max_links = MINIX2_LINK_MAX;
        } else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) {
                m3s = (struct minix3_super_block *) bh->b_data;
                s->s_magic = m3s->s_magic;
@@ -221,9 +221,9 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
                sbi->s_dirsize = 64;
                sbi->s_namelen = 60;
                sbi->s_version = MINIX_V3;
-               sbi->s_link_max = MINIX2_LINK_MAX;
                sbi->s_mount_state = MINIX_VALID_FS;
                sb_set_blocksize(s, m3s->s_blocksize);
+               s->s_max_links = MINIX2_LINK_MAX;
        } else
                goto out_no_fs;
 
@@ -254,14 +254,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
        minix_set_bit(0,sbi->s_imap[0]->b_data);
        minix_set_bit(0,sbi->s_zmap[0]->b_data);
 
-       /* set up enough so that it can read an inode */
-       s->s_op = &minix_sops;
-       root_inode = minix_iget(s, MINIX_ROOT_INO);
-       if (IS_ERR(root_inode)) {
-               ret = PTR_ERR(root_inode);
-               goto out_no_root;
-       }
-
        /* Apparently minix can create filesystems that allocate more blocks for
         * the bitmaps than needed.  We simply ignore that, but verify it didn't
         * create one with not enough blocks and bail out if so.
@@ -270,7 +262,7 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
        if (sbi->s_imap_blocks < block) {
                printk("MINIX-fs: file system does not have enough "
                                "imap blocks allocated.  Refusing to mount\n");
-               goto out_iput;
+               goto out_no_bitmap;
        }
 
        block = minix_blocks_needed(
@@ -279,13 +271,21 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
        if (sbi->s_zmap_blocks < block) {
                printk("MINIX-fs: file system does not have enough "
                                "zmap blocks allocated.  Refusing to mount.\n");
-               goto out_iput;
+               goto out_no_bitmap;
+       }
+
+       /* set up enough so that it can read an inode */
+       s->s_op = &minix_sops;
+       root_inode = minix_iget(s, MINIX_ROOT_INO);
+       if (IS_ERR(root_inode)) {
+               ret = PTR_ERR(root_inode);
+               goto out_no_root;
        }
 
        ret = -ENOMEM;
-       s->s_root = d_alloc_root(root_inode);
+       s->s_root = d_make_root(root_inode);
        if (!s->s_root)
-               goto out_iput;
+               goto out_no_root;
 
        if (!(s->s_flags & MS_RDONLY)) {
                if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
@@ -301,10 +301,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
 
        return 0;
 
-out_iput:
-       iput(root_inode);
-       goto out_freemap;
-
 out_no_root:
        if (!silent)
                printk("MINIX-fs: get root inode failed\n");
index c889ef0..1ebd118 100644 (file)
@@ -34,7 +34,6 @@ struct minix_sb_info {
        unsigned long s_max_size;
        int s_dirsize;
        int s_namelen;
-       int s_link_max;
        struct buffer_head ** s_imap;
        struct buffer_head ** s_zmap;
        struct buffer_head * s_sbh;
index 2f76e38..2d0ee17 100644 (file)
@@ -94,9 +94,6 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
 {
        struct inode *inode = old_dentry->d_inode;
 
-       if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max)
-               return -EMLINK;
-
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
        ihold(inode);
@@ -106,10 +103,7 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir,
 static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 {
        struct inode * inode;
-       int err = -EMLINK;
-
-       if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
-               goto out;
+       int err;
 
        inode_inc_link_count(dir);
 
@@ -181,7 +175,6 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
 static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                           struct inode * new_dir, struct dentry *new_dentry)
 {
-       struct minix_sb_info * info = minix_sb(old_dir->i_sb);
        struct inode * old_inode = old_dentry->d_inode;
        struct inode * new_inode = new_dentry->d_inode;
        struct page * dir_page = NULL;
@@ -219,11 +212,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                        drop_nlink(new_inode);
                inode_dec_link_count(new_inode);
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= info->s_link_max)
-                               goto out_dir;
-               }
                err = minix_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index 561db47..a94a7f9 100644 (file)
@@ -642,7 +642,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        cond_resched();
        current->total_link_count++;
 
-       touch_atime(link->mnt, dentry);
+       touch_atime(link);
        nd_set_link(nd, NULL);
 
        error = security_inode_follow_link(link->dentry, nd);
@@ -2697,6 +2697,7 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
 int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        int error = may_create(dir, dentry);
+       unsigned max_links = dir->i_sb->s_max_links;
 
        if (error)
                return error;
@@ -2709,6 +2710,9 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        if (error)
                return error;
 
+       if (max_links && dir->i_nlink >= max_links)
+               return -EMLINK;
+
        error = dir->i_op->mkdir(dir, dentry, mode);
        if (!error)
                fsnotify_mkdir(dir, dentry);
@@ -3039,6 +3043,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
 int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
        struct inode *inode = old_dentry->d_inode;
+       unsigned max_links = dir->i_sb->s_max_links;
        int error;
 
        if (!inode)
@@ -3069,6 +3074,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        /* Make sure we don't allow creating hardlink to an unlinked file */
        if (inode->i_nlink == 0)
                error =  -ENOENT;
+       else if (max_links && inode->i_nlink >= max_links)
+               error = -EMLINK;
        else
                error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&inode->i_mutex);
@@ -3178,6 +3185,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
 {
        int error = 0;
        struct inode *target = new_dentry->d_inode;
+       unsigned max_links = new_dir->i_sb->s_max_links;
 
        /*
         * If we are going to change the parent - check write permissions,
@@ -3201,6 +3209,11 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
                goto out;
 
+       error = -EMLINK;
+       if (max_links && !target && new_dir != old_dir &&
+           new_dir->i_nlink >= max_links)
+               goto out;
+
        if (target)
                shrink_dcache_parent(new_dentry);
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
index 3d1e34f..49df0e7 100644 (file)
@@ -716,13 +716,11 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
         if (!root_inode)
                goto out_disconnect;
        DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
         if (!sb->s_root)
-               goto out_no_root;
+               goto out_disconnect;
        return 0;
 
-out_no_root:
-       iput(root_inode);
 out_disconnect:
        ncp_lock_server(server);
        ncp_disconnect(server);
index 31778f7..d4f772e 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/inet.h>
 #include <linux/in6.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 #include <net/ipv6.h>
 #include <linux/nfs_xdr.h>
 #include <linux/sunrpc/bc_xprt.h>
index dcb6154..801d6d8 100644 (file)
@@ -49,11 +49,9 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
 {
        /* The mntroot acts as the dummy root dentry for this superblock */
        if (sb->s_root == NULL) {
-               sb->s_root = d_alloc_root(inode);
-               if (sb->s_root == NULL) {
-                       iput(inode);
+               sb->s_root = d_make_root(inode);
+               if (sb->s_root == NULL)
                        return -ENOMEM;
-               }
                ihold(inode);
                /*
                 * Ensure that this dentry is invisible to d_find_alias().
index 2c05f19..a1bbf77 100644 (file)
@@ -198,6 +198,7 @@ int nfs_idmap_init(void)
        if (ret < 0)
                goto failed_put_key;
 
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        id_resolver_cache = cred;
index ce7f075..9559ce4 100644 (file)
@@ -72,7 +72,7 @@ int nfsd_fault_inject_init(void)
 {
        unsigned int i;
        struct nfsd_fault_inject_op *op;
-       mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+       umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
 
        debug_dir = debugfs_create_dir("nfsd", NULL);
        if (!debug_dir)
index edf6d3e..e59f71d 100644 (file)
@@ -1541,30 +1541,31 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 __be32
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 {
-       struct dentry   *dentry;
        struct inode    *inode;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
+       struct path path;
 
        err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP);
        if (err)
                goto out;
 
-       dentry = fhp->fh_dentry;
-       inode = dentry->d_inode;
+       path.mnt = fhp->fh_export->ex_path.mnt;
+       path.dentry = fhp->fh_dentry;
+       inode = path.dentry->d_inode;
 
        err = nfserr_inval;
        if (!inode->i_op->readlink)
                goto out;
 
-       touch_atime(fhp->fh_export->ex_path.mnt, dentry);
+       touch_atime(&path);
        /* N.B. Why does this call need a get_fs()??
         * Remove the set_fs and watch the fireworks:-) --okir
         */
 
        oldfs = get_fs(); set_fs(KERNEL_DS);
-       host_err = inode->i_op->readlink(dentry, buf, *lenp);
+       host_err = inode->i_op->readlink(path.dentry, buf, *lenp);
        set_fs(oldfs);
 
        if (host_err < 0)
index 1cd3f62..fce2bbe 100644 (file)
@@ -193,9 +193,6 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
        struct nilfs_transaction_info ti;
        int err;
 
-       if (inode->i_nlink >= NILFS_LINK_MAX)
-               return -EMLINK;
-
        err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
        if (err)
                return err;
@@ -219,9 +216,6 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct nilfs_transaction_info ti;
        int err;
 
-       if (dir->i_nlink >= NILFS_LINK_MAX)
-               return -EMLINK;
-
        err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
        if (err)
                return err;
@@ -400,11 +394,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                drop_nlink(new_inode);
                nilfs_mark_inode_dirty(new_inode);
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= NILFS_LINK_MAX)
-                               goto out_dir;
-               }
                err = nilfs_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index 08e3d4f..1099a76 100644 (file)
@@ -917,9 +917,8 @@ static int nilfs_get_root_dentry(struct super_block *sb,
        if (root->cno == NILFS_CPTREE_CURRENT_CNO) {
                dentry = d_find_alias(inode);
                if (!dentry) {
-                       dentry = d_alloc_root(inode);
+                       dentry = d_make_root(inode);
                        if (!dentry) {
-                               iput(inode);
                                ret = -ENOMEM;
                                goto failed_dentry;
                        }
@@ -1059,6 +1058,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_export_op = &nilfs_export_ops;
        sb->s_root = NULL;
        sb->s_time_gran = 1;
+       sb->s_max_links = NILFS_LINK_MAX;
 
        bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
        sb->s_bdi = bdi ? : &default_backing_dev_info;
index 28d4e6a..b341492 100644 (file)
@@ -2908,9 +2908,10 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
                ntfs_error(sb, "Failed to load system files.");
                goto unl_upcase_iput_tmp_ino_err_out_now;
        }
-       if ((sb->s_root = d_alloc_root(vol->root_ino))) {
-               /* We grab a reference, simulating an ntfs_iget(). */
-               ihold(vol->root_ino);
+
+       /* We grab a reference, simulating an ntfs_iget(). */
+       ihold(vol->root_ino);
+       if ((sb->s_root = d_make_root(vol->root_ino))) {
                ntfs_debug("Exiting, status successful.");
                /* Release the default upcase if it has no users. */
                mutex_lock(&ntfs_lock);
@@ -3158,6 +3159,8 @@ static int __init init_ntfs_fs(void)
        }
        printk(KERN_CRIT "NTFS: Failed to register NTFS filesystem driver!\n");
 
+       /* Unregister the ntfs sysctls. */
+       ntfs_sysctl(0);
 sysctl_err_out:
        kmem_cache_destroy(ntfs_big_inode_cache);
 big_inode_err_out:
index abfac0d..3b5825e 100644 (file)
@@ -582,24 +582,14 @@ static int dlmfs_fill_super(struct super_block * sb,
                            void * data,
                            int silent)
 {
-       struct inode * inode;
-       struct dentry * root;
-
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = DLMFS_MAGIC;
        sb->s_op = &dlmfs_ops;
-       inode = dlmfs_get_root_inode(sb);
-       if (!inode)
-               return -ENOMEM;
-
-       root = d_alloc_root(inode);
-       if (!root) {
-               iput(inode);
+       sb->s_root = d_make_root(dlmfs_get_root_inode(sb));
+       if (!sb->s_root)
                return -ENOMEM;
-       }
-       sb->s_root = root;
        return 0;
 }
 
index 604e12c..68f4541 100644 (file)
@@ -1154,19 +1154,19 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        status = ocfs2_mount_volume(sb);
-       if (osb->root_inode)
-               inode = igrab(osb->root_inode);
-
        if (status < 0)
                goto read_super_error;
 
+       if (osb->root_inode)
+               inode = igrab(osb->root_inode);
+
        if (!inode) {
                status = -EIO;
                mlog_errno(status);
                goto read_super_error;
        }
 
-       root = d_alloc_root(inode);
+       root = d_make_root(inode);
        if (!root) {
                status = -ENOMEM;
                mlog_errno(status);
@@ -1220,9 +1220,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 read_super_error:
        brelse(bh);
 
-       if (inode)
-               iput(inode);
-
        if (osb) {
                atomic_set(&osb->vol_state, VOLUME_DISABLED);
                wake_up(&osb->osb_mount_event);
@@ -1627,21 +1624,17 @@ static int __init ocfs2_init(void)
                init_waitqueue_head(&ocfs2__ioend_wq[i]);
 
        status = init_ocfs2_uptodate_cache();
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       if (status < 0)
+               goto out1;
 
        status = ocfs2_initialize_mem_caches();
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       if (status < 0)
+               goto out2;
 
        ocfs2_wq = create_singlethread_workqueue("ocfs2_wq");
        if (!ocfs2_wq) {
                status = -ENOMEM;
-               goto leave;
+               goto out3;
        }
 
        ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
@@ -1653,17 +1646,23 @@ static int __init ocfs2_init(void)
        ocfs2_set_locking_protocol();
 
        status = register_quota_format(&ocfs2_quota_format);
-leave:
-       if (status < 0) {
-               ocfs2_free_mem_caches();
-               exit_ocfs2_uptodate_cache();
-               mlog_errno(status);
-       }
+       if (status < 0)
+               goto out4;
+       status = register_filesystem(&ocfs2_fs_type);
+       if (!status)
+               return 0;
 
-       if (status >= 0) {
-               return register_filesystem(&ocfs2_fs_type);
-       } else
-               return -1;
+       unregister_quota_format(&ocfs2_quota_format);
+out4:
+       destroy_workqueue(ocfs2_wq);
+       debugfs_remove(ocfs2_debugfs_root);
+out3:
+       ocfs2_free_mem_caches();
+out2:
+       exit_ocfs2_uptodate_cache();
+out1:
+       mlog_errno(status);
+       return status;
 }
 
 static void __exit ocfs2_exit(void)
index 6065bb0..dbc8422 100644 (file)
@@ -539,11 +539,9 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
                goto out_brelse_bh2;
        }
 
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
+       sb->s_root = d_make_root(root);
+       if (!sb->s_root)
                goto out_brelse_bh2;
-       }
        printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name);
 
        ret = 0;
index a88c03b..bc49c97 100644 (file)
@@ -408,13 +408,12 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent)
        oi->type = op_inode_node;
        oi->u.node = of_find_node_by_path("/");
 
-       s->s_root = d_alloc_root(root_inode);
+       s->s_root = d_make_root(root_inode);
        if (!s->s_root)
                goto out_no_root_dentry;
        return 0;
 
 out_no_root_dentry:
-       iput(root_inode);
        ret = -ENOMEM;
 out_no_root:
        printk("openprom_fill_super: get root inode failed\n");
index 84fd323..8461a7b 100644 (file)
@@ -486,8 +486,6 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 
 int proc_fill_super(struct super_block *s)
 {
-       struct inode * root_inode;
-
        s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
@@ -496,19 +494,11 @@ int proc_fill_super(struct super_block *s)
        s->s_time_gran = 1;
        
        pde_get(&proc_root);
-       root_inode = proc_get_inode(s, &proc_root);
-       if (!root_inode)
-               goto out_no_root;
-       root_inode->i_uid = 0;
-       root_inode->i_gid = 0;
-       s->s_root = d_alloc_root(root_inode);
-       if (!s->s_root)
-               goto out_no_root;
-       return 0;
+       s->s_root = d_make_root(proc_get_inode(s, &proc_root));
+       if (s->s_root)
+               return 0;
 
-out_no_root:
        printk("proc_read_super: get root inode failed\n");
-       iput(root_inode);
        pde_put(&proc_root);
        return -ENOMEM;
 }
index a6b6217..67bbf6e 100644 (file)
@@ -6,7 +6,9 @@
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
+#include <linux/sched.h>
 #include <linux/namei.h>
+#include <linux/mm.h>
 #include "internal.h"
 
 static const struct dentry_operations proc_sys_dentry_operations;
index b0f450a..0d5071d 100644 (file)
@@ -700,3 +700,26 @@ static int __init vmcore_init(void)
        return 0;
 }
 module_init(vmcore_init)
+
+/* Cleanup function for vmcore module. */
+void vmcore_cleanup(void)
+{
+       struct list_head *pos, *next;
+
+       if (proc_vmcore) {
+               remove_proc_entry(proc_vmcore->name, proc_vmcore->parent);
+               proc_vmcore = NULL;
+       }
+
+       /* clear the vmcore list. */
+       list_for_each_safe(pos, next, &vmcore_list) {
+               struct vmcore *m;
+
+               m = list_entry(pos, struct vmcore, list);
+               list_del(&m->list);
+               kfree(m);
+       }
+       kfree(elfcorebuf);
+       elfcorebuf = NULL;
+}
+EXPORT_SYMBOL_GPL(vmcore_cleanup);
index b3b426e..f37c32b 100644 (file)
@@ -278,9 +278,7 @@ fail:
 
 int pstore_fill_super(struct super_block *sb, void *data, int silent)
 {
-       struct inode *inode = NULL;
-       struct dentry *root;
-       int err;
+       struct inode *inode;
 
        save_mount_options(sb, data);
 
@@ -296,26 +294,17 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent)
        parse_options(data);
 
        inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0);
-       if (!inode) {
-               err = -ENOMEM;
-               goto fail;
-       }
-       /* override ramfs "dir" options so we catch unlink(2) */
-       inode->i_op = &pstore_dir_inode_operations;
-
-       root = d_alloc_root(inode);
-       sb->s_root = root;
-       if (!root) {
-               err = -ENOMEM;
-               goto fail;
+       if (inode) {
+               /* override ramfs "dir" options so we catch unlink(2) */
+               inode->i_op = &pstore_dir_inode_operations;
        }
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
+               return -ENOMEM;
 
        pstore_get_records(0);
 
        return 0;
-fail:
-       iput(inode);
-       return err;
 }
 
 static struct dentry *pstore_mount(struct file_system_type *fs_type,
index 6b00954..552e994 100644 (file)
@@ -52,38 +52,6 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
-static struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
-                                      int create)
-{
-       struct buffer_head *result = NULL;
-
-       if ( nr >= 0 )
-               nr = qnx4_block_map( inode, nr );
-       if (nr) {
-               result = sb_getblk(inode->i_sb, nr);
-               return result;
-       }
-       return NULL;
-}
-
-struct buffer_head *qnx4_bread(struct inode *inode, int block, int create)
-{
-       struct buffer_head *bh;
-
-       bh = qnx4_getblk(inode, block, create);
-       if (!bh || buffer_uptodate(bh)) {
-               return bh;
-       }
-       ll_rw_block(READ, 1, &bh);
-       wait_on_buffer(bh);
-       if (buffer_uptodate(bh)) {
-               return bh;
-       }
-       brelse(bh);
-
-       return NULL;
-}
-
 static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
 {
        unsigned long phys;
@@ -98,23 +66,31 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h
        return 0;
 }
 
+static inline u32 try_extent(qnx4_xtnt_t *extent, u32 *offset)
+{
+       u32 size = le32_to_cpu(extent->xtnt_size);
+       if (*offset < size)
+               return le32_to_cpu(extent->xtnt_blk) + *offset - 1;
+       *offset -= size;
+       return 0;
+}
+
 unsigned long qnx4_block_map( struct inode *inode, long iblock )
 {
        int ix;
-       long offset, i_xblk;
-       unsigned long block = 0;
+       long i_xblk;
        struct buffer_head *bh = NULL;
        struct qnx4_xblk *xblk = NULL;
        struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
        u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
+       u32 offset = iblock;
+       u32 block = try_extent(&qnx4_inode->di_first_xtnt, &offset);
 
-       if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
+       if (block) {
                // iblock is in the first extent. This is easy.
-               block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
        } else {
                // iblock is beyond first extent. We have to follow the extent chain.
                i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
-               offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
                ix = 0;
                while ( --nxtnt > 0 ) {
                        if ( ix == 0 ) {
@@ -130,12 +106,11 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
                                        return -EIO;
                                }
                        }
-                       if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) {
+                       block = try_extent(&xblk->xblk_xtnts[ix], &offset);
+                       if (block) {
                                // got it!
-                               block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1;
                                break;
                        }
-                       offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size);
                        if ( ++ix >= xblk->xblk_num_xtnts ) {
                                i_xblk = le32_to_cpu(xblk->xblk_next_xblk);
                                ix = 0;
@@ -260,15 +235,13 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        }
 
        ret = -ENOMEM;
-       s->s_root = d_alloc_root(root);
+       s->s_root = d_make_root(root);
        if (s->s_root == NULL)
-               goto outi;
+               goto outb;
 
        brelse(bh);
        return 0;
 
-      outi:
-       iput(root);
       outb:
        kfree(qs->BitMap);
       out:
@@ -288,44 +261,17 @@ static void qnx4_put_super(struct super_block *sb)
        return;
 }
 
-static int qnx4_writepage(struct page *page, struct writeback_control *wbc)
-{
-       return block_write_full_page(page,qnx4_get_block, wbc);
-}
-
 static int qnx4_readpage(struct file *file, struct page *page)
 {
        return block_read_full_page(page,qnx4_get_block);
 }
 
-static int qnx4_write_begin(struct file *file, struct address_space *mapping,
-                       loff_t pos, unsigned len, unsigned flags,
-                       struct page **pagep, void **fsdata)
-{
-       struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host);
-       int ret;
-
-       *pagep = NULL;
-       ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               qnx4_get_block,
-                               &qnx4_inode->mmu_private);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
-
-       return ret;
-}
 static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 {
        return generic_block_bmap(mapping,block,qnx4_get_block);
 }
 static const struct address_space_operations qnx4_aops = {
        .readpage       = qnx4_readpage,
-       .writepage      = qnx4_writepage,
-       .write_begin    = qnx4_write_begin,
-       .write_end      = generic_write_end,
        .bmap           = qnx4_bmap
 };
 
index 275327b..a512c0b 100644 (file)
@@ -39,10 +39,6 @@ static int qnx4_match(int len, const char *name,
        } else {
                namelen = QNX4_SHORT_NAME_MAX;
        }
-       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-       if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) {
-               return 1;
-       }
        thislen = strlen( de->di_fname );
        if ( thislen > namelen )
                thislen = namelen;
@@ -72,7 +68,9 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
        block = offset = blkofs = 0;
        while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
                if (!bh) {
-                       bh = qnx4_bread(dir, blkofs, 0);
+                       block = qnx4_block_map(dir, blkofs);
+                       if (block)
+                               bh = sb_bread(dir->i_sb, block);
                        if (!bh) {
                                blkofs++;
                                continue;
@@ -80,7 +78,6 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
                }
                *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
                if (qnx4_match(len, name, bh, &offset)) {
-                       block = qnx4_block_map( dir, blkofs );
                        *ino = block * QNX4_INODES_PER_BLOCK +
                            (offset / QNX4_DIR_ENTRY_SIZE) - 1;
                        return bh;
index 33a6085..244d462 100644 (file)
@@ -27,8 +27,6 @@ extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, stru
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
-extern struct buffer_head *qnx4_bread(struct inode *, int, int);
-
 extern const struct inode_operations qnx4_dir_inode_operations;
 extern const struct file_operations qnx4_dir_operations;
 extern int qnx4_is_free(struct super_block *sb, long block);
diff --git a/fs/qnx6/Kconfig b/fs/qnx6/Kconfig
new file mode 100644 (file)
index 0000000..edbba5c
--- /dev/null
@@ -0,0 +1,26 @@
+config QNX6FS_FS
+       tristate "QNX6 file system support (read only)"
+       depends on BLOCK && CRC32
+       help
+         This is the file system used by the real-time operating systems
+         QNX 6 (also called QNX RTP).
+         Further information is available at <http://www.qnx.com/>.
+         Say Y if you intend to mount QNX hard disks or floppies formatted
+          with a mkqnx6fs.
+         However, keep in mind that this currently is a readonly driver!
+
+         To compile this file system support as a module, choose M here: the
+         module will be called qnx6.
+
+         If you don't know whether you need it, then you don't need it:
+         answer N.
+
+config QNX6FS_DEBUG
+       bool "QNX6 debugging information"
+       depends on QNX6FS_FS
+       help
+         Turns on extended debugging output.
+
+         If you are not a developer working on the QNX6FS, you probably don't
+         want this:
+         answer N.
diff --git a/fs/qnx6/Makefile b/fs/qnx6/Makefile
new file mode 100644 (file)
index 0000000..9dd0619
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux qnx4-filesystem routines.
+#
+
+obj-$(CONFIG_QNX6FS_FS) += qnx6.o
+
+qnx6-objs := inode.o dir.o namei.o super_mmi.o
diff --git a/fs/qnx6/README b/fs/qnx6/README
new file mode 100644 (file)
index 0000000..116d622
--- /dev/null
@@ -0,0 +1,8 @@
+
+  This is a snapshot of the QNX6 filesystem for Linux.
+  Please send diffs and remarks to <chaosman@ontika.net> .
+
+Credits :
+
+Al Viro                <viro@ZenIV.linux.org.uk> (endless patience with me & support ;))
+Kai Bankett    <chaosman@ontika.net> (Maintainer)
diff --git a/fs/qnx6/dir.c b/fs/qnx6/dir.c
new file mode 100644 (file)
index 0000000..dc59735
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include "qnx6.h"
+
+static unsigned qnx6_lfile_checksum(char *name, unsigned size)
+{
+       unsigned crc = 0;
+       char *end = name + size;
+       while (name < end) {
+               crc = ((crc >> 1) + *(name++)) ^
+                       ((crc & 0x00000001) ? 0x80000000 : 0);
+       }
+       return crc;
+}
+
+static struct page *qnx6_get_page(struct inode *dir, unsigned long n)
+{
+       struct address_space *mapping = dir->i_mapping;
+       struct page *page = read_mapping_page(mapping, n, NULL);
+       if (!IS_ERR(page))
+               kmap(page);
+       return page;
+}
+
+static inline unsigned long dir_pages(struct inode *inode)
+{
+       return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
+
+static unsigned last_entry(struct inode *inode, unsigned long page_nr)
+{
+       unsigned long last_byte = inode->i_size;
+       last_byte -= page_nr << PAGE_CACHE_SHIFT;
+       if (last_byte > PAGE_CACHE_SIZE)
+               last_byte = PAGE_CACHE_SIZE;
+       return last_byte / QNX6_DIR_ENTRY_SIZE;
+}
+
+static struct qnx6_long_filename *qnx6_longname(struct super_block *sb,
+                                        struct qnx6_long_dir_entry *de,
+                                        struct page **p)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+       u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */
+       u32 n = s >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); /* in pages */
+       /* within page */
+       u32 offs = (s << sb->s_blocksize_bits) & ~PAGE_CACHE_MASK;
+       struct address_space *mapping = sbi->longfile->i_mapping;
+       struct page *page = read_mapping_page(mapping, n, NULL);
+       if (IS_ERR(page))
+               return ERR_CAST(page);
+       kmap(*p = page);
+       return (struct qnx6_long_filename *)(page_address(page) + offs);
+}
+
+static int qnx6_dir_longfilename(struct inode *inode,
+                       struct qnx6_long_dir_entry *de,
+                       void *dirent, loff_t pos,
+                       unsigned de_inode, filldir_t filldir)
+{
+       struct qnx6_long_filename *lf;
+       struct super_block *s = inode->i_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       struct page *page;
+       int lf_size;
+
+       if (de->de_size != 0xff) {
+               /* error - long filename entries always have size 0xff
+                  in direntry */
+               printk(KERN_ERR "qnx6: invalid direntry size (%i).\n",
+                               de->de_size);
+               return 0;
+       }
+       lf = qnx6_longname(s, de, &page);
+       if (IS_ERR(lf)) {
+               printk(KERN_ERR "qnx6:Error reading longname\n");
+               return 0;
+       }
+
+       lf_size = fs16_to_cpu(sbi, lf->lf_size);
+
+       if (lf_size > QNX6_LONG_NAME_MAX) {
+               QNX6DEBUG((KERN_INFO "file %s\n", lf->lf_fname));
+               printk(KERN_ERR "qnx6:Filename too long (%i)\n", lf_size);
+               qnx6_put_page(page);
+               return 0;
+       }
+
+       /* calc & validate longfilename checksum
+          mmi 3g filesystem does not have that checksum */
+       if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) !=
+                       qnx6_lfile_checksum(lf->lf_fname, lf_size))
+               printk(KERN_INFO "qnx6: long filename checksum error.\n");
+
+       QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s inode:%u\n",
+                                       lf_size, lf->lf_fname, de_inode));
+       if (filldir(dirent, lf->lf_fname, lf_size, pos, de_inode,
+                       DT_UNKNOWN) < 0) {
+               qnx6_put_page(page);
+               return 0;
+       }
+
+       qnx6_put_page(page);
+       /* success */
+       return 1;
+}
+
+static int qnx6_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct super_block *s = inode->i_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       loff_t pos = filp->f_pos & (QNX6_DIR_ENTRY_SIZE - 1);
+       unsigned long npages = dir_pages(inode);
+       unsigned long n = pos >> PAGE_CACHE_SHIFT;
+       unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE;
+       bool done = false;
+
+       if (filp->f_pos >= inode->i_size)
+               return 0;
+
+       for ( ; !done && n < npages; n++, start = 0) {
+               struct page *page = qnx6_get_page(inode, n);
+               int limit = last_entry(inode, n);
+               struct qnx6_dir_entry *de;
+               int i = start;
+
+               if (IS_ERR(page)) {
+                       printk(KERN_ERR "qnx6_readdir: read failed\n");
+                       filp->f_pos = (n + 1) << PAGE_CACHE_SHIFT;
+                       return PTR_ERR(page);
+               }
+               de = ((struct qnx6_dir_entry *)page_address(page)) + start;
+               for (; i < limit; i++, de++, pos += QNX6_DIR_ENTRY_SIZE) {
+                       int size = de->de_size;
+                       u32 no_inode = fs32_to_cpu(sbi, de->de_inode);
+
+                       if (!no_inode || !size)
+                               continue;
+
+                       if (size > QNX6_SHORT_NAME_MAX) {
+                               /* long filename detected
+                                  get the filename from long filename
+                                  structure / block */
+                               if (!qnx6_dir_longfilename(inode,
+                                       (struct qnx6_long_dir_entry *)de,
+                                       dirent, pos, no_inode,
+                                       filldir)) {
+                                       done = true;
+                                       break;
+                               }
+                       } else {
+                               QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s"
+                                  " inode:%u\n", size, de->de_fname,
+                                                       no_inode));
+                               if (filldir(dirent, de->de_fname, size,
+                                     pos, no_inode, DT_UNKNOWN)
+                                       < 0) {
+                                       done = true;
+                                       break;
+                               }
+                       }
+               }
+               qnx6_put_page(page);
+       }
+       filp->f_pos = pos;
+       return 0;
+}
+
+/*
+ * check if the long filename is correct.
+ */
+static unsigned qnx6_long_match(int len, const char *name,
+                       struct qnx6_long_dir_entry *de, struct inode *dir)
+{
+       struct super_block *s = dir->i_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       struct page *page;
+       int thislen;
+       struct qnx6_long_filename *lf = qnx6_longname(s, de, &page);
+
+       if (IS_ERR(lf))
+               return 0;
+
+       thislen = fs16_to_cpu(sbi, lf->lf_size);
+       if (len != thislen) {
+               qnx6_put_page(page);
+               return 0;
+       }
+       if (memcmp(name, lf->lf_fname, len) == 0) {
+               qnx6_put_page(page);
+               return fs32_to_cpu(sbi, de->de_inode);
+       }
+       qnx6_put_page(page);
+       return 0;
+}
+
+/*
+ * check if the filename is correct.
+ */
+static unsigned qnx6_match(struct super_block *s, int len, const char *name,
+                       struct qnx6_dir_entry *de)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       if (memcmp(name, de->de_fname, len) == 0)
+               return fs32_to_cpu(sbi, de->de_inode);
+       return 0;
+}
+
+
+unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
+                        struct page **res_page)
+{
+       struct super_block *s = dir->i_sb;
+       struct qnx6_inode_info *ei = QNX6_I(dir);
+       struct page *page = NULL;
+       unsigned long start, n;
+       unsigned long npages = dir_pages(dir);
+       unsigned ino;
+       struct qnx6_dir_entry *de;
+       struct qnx6_long_dir_entry *lde;
+
+       *res_page = NULL;
+
+       if (npages == 0)
+               return 0;
+       start = ei->i_dir_start_lookup;
+       if (start >= npages)
+               start = 0;
+       n = start;
+
+       do {
+               page = qnx6_get_page(dir, n);
+               if (!IS_ERR(page)) {
+                       int limit = last_entry(dir, n);
+                       int i;
+
+                       de = (struct qnx6_dir_entry *)page_address(page);
+                       for (i = 0; i < limit; i++, de++) {
+                               if (len <= QNX6_SHORT_NAME_MAX) {
+                                       /* short filename */
+                                       if (len != de->de_size)
+                                               continue;
+                                       ino = qnx6_match(s, len, name, de);
+                                       if (ino)
+                                               goto found;
+                               } else if (de->de_size == 0xff) {
+                                       /* deal with long filename */
+                                       lde = (struct qnx6_long_dir_entry *)de;
+                                       ino = qnx6_long_match(len,
+                                                               name, lde, dir);
+                                       if (ino)
+                                               goto found;
+                               } else
+                                       printk(KERN_ERR "qnx6: undefined "
+                                               "filename size in inode.\n");
+                       }
+                       qnx6_put_page(page);
+               }
+
+               if (++n >= npages)
+                       n = 0;
+       } while (n != start);
+       return 0;
+
+found:
+       *res_page = page;
+       ei->i_dir_start_lookup = n;
+       return ino;
+}
+
+const struct file_operations qnx6_dir_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .readdir        = qnx6_readdir,
+       .fsync          = generic_file_fsync,
+};
+
+const struct inode_operations qnx6_dir_inode_operations = {
+       .lookup         = qnx6_lookup,
+};
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
new file mode 100644 (file)
index 0000000..e44012d
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+#include <linux/statfs.h>
+#include <linux/parser.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/crc32.h>
+#include <linux/mpage.h>
+#include "qnx6.h"
+
+static const struct super_operations qnx6_sops;
+
+static void qnx6_put_super(struct super_block *sb);
+static struct inode *qnx6_alloc_inode(struct super_block *sb);
+static void qnx6_destroy_inode(struct inode *inode);
+static int qnx6_remount(struct super_block *sb, int *flags, char *data);
+static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf);
+static int qnx6_show_options(struct seq_file *seq, struct dentry *root);
+
+static const struct super_operations qnx6_sops = {
+       .alloc_inode    = qnx6_alloc_inode,
+       .destroy_inode  = qnx6_destroy_inode,
+       .put_super      = qnx6_put_super,
+       .statfs         = qnx6_statfs,
+       .remount_fs     = qnx6_remount,
+       .show_options   = qnx6_show_options,
+};
+
+static int qnx6_show_options(struct seq_file *seq, struct dentry *root)
+{
+       struct super_block *sb = root->d_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+
+       if (sbi->s_mount_opt & QNX6_MOUNT_MMI_FS)
+               seq_puts(seq, ",mmi_fs");
+       return 0;
+}
+
+static int qnx6_remount(struct super_block *sb, int *flags, char *data)
+{
+       *flags |= MS_RDONLY;
+       return 0;
+}
+
+static unsigned qnx6_get_devblock(struct super_block *sb, __fs32 block)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+       return fs32_to_cpu(sbi, block) + sbi->s_blks_off;
+}
+
+static unsigned qnx6_block_map(struct inode *inode, unsigned iblock);
+
+static int qnx6_get_block(struct inode *inode, sector_t iblock,
+                       struct buffer_head *bh, int create)
+{
+       unsigned phys;
+
+       QNX6DEBUG((KERN_INFO "qnx6: qnx6_get_block inode=[%ld] iblock=[%ld]\n",
+                       inode->i_ino, (unsigned long)iblock));
+
+       phys = qnx6_block_map(inode, iblock);
+       if (phys) {
+               /* logical block is before EOF */
+               map_bh(bh, inode->i_sb, phys);
+       }
+       return 0;
+}
+
+static int qnx6_check_blockptr(__fs32 ptr)
+{
+       if (ptr == ~(__fs32)0) {
+               printk(KERN_ERR "qnx6: hit unused blockpointer.\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int qnx6_readpage(struct file *file, struct page *page)
+{
+       return mpage_readpage(page, qnx6_get_block);
+}
+
+static int qnx6_readpages(struct file *file, struct address_space *mapping,
+                  struct list_head *pages, unsigned nr_pages)
+{
+       return mpage_readpages(mapping, pages, nr_pages, qnx6_get_block);
+}
+
+/*
+ * returns the block number for the no-th element in the tree
+ * inodebits requred as there are multiple inodes in one inode block
+ */
+static unsigned qnx6_block_map(struct inode *inode, unsigned no)
+{
+       struct super_block *s = inode->i_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       struct qnx6_inode_info *ei = QNX6_I(inode);
+       unsigned block = 0;
+       struct buffer_head *bh;
+       __fs32 ptr;
+       int levelptr;
+       int ptrbits = sbi->s_ptrbits;
+       int bitdelta;
+       u32 mask = (1 << ptrbits) - 1;
+       int depth = ei->di_filelevels;
+       int i;
+
+       bitdelta = ptrbits * depth;
+       levelptr = no >> bitdelta;
+
+       if (levelptr > QNX6_NO_DIRECT_POINTERS - 1) {
+               printk(KERN_ERR "qnx6:Requested file block number (%u) too big.",
+                               no);
+               return 0;
+       }
+
+       block = qnx6_get_devblock(s, ei->di_block_ptr[levelptr]);
+
+       for (i = 0; i < depth; i++) {
+               bh = sb_bread(s, block);
+               if (!bh) {
+                       printk(KERN_ERR "qnx6:Error reading block (%u)\n",
+                                       block);
+                       return 0;
+               }
+               bitdelta -= ptrbits;
+               levelptr = (no >> bitdelta) & mask;
+               ptr = ((__fs32 *)bh->b_data)[levelptr];
+
+               if (!qnx6_check_blockptr(ptr))
+                       return 0;
+
+               block = qnx6_get_devblock(s, ptr);
+               brelse(bh);
+       }
+       return block;
+}
+
+static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct super_block *sb = dentry->d_sb;
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+
+       buf->f_type    = sb->s_magic;
+       buf->f_bsize   = sb->s_blocksize;
+       buf->f_blocks  = fs32_to_cpu(sbi, sbi->sb->sb_num_blocks);
+       buf->f_bfree   = fs32_to_cpu(sbi, sbi->sb->sb_free_blocks);
+       buf->f_files   = fs32_to_cpu(sbi, sbi->sb->sb_num_inodes);
+       buf->f_ffree   = fs32_to_cpu(sbi, sbi->sb->sb_free_inodes);
+       buf->f_bavail  = buf->f_bfree;
+       buf->f_namelen = QNX6_LONG_NAME_MAX;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+
+       return 0;
+}
+
+/*
+ * Check the root directory of the filesystem to make sure
+ * it really _is_ a qnx6 filesystem, and to check the size
+ * of the directory entry.
+ */
+static const char *qnx6_checkroot(struct super_block *s)
+{
+       static char match_root[2][3] = {".\0\0", "..\0"};
+       int i, error = 0;
+       struct qnx6_dir_entry *dir_entry;
+       struct inode *root = s->s_root->d_inode;
+       struct address_space *mapping = root->i_mapping;
+       struct page *page = read_mapping_page(mapping, 0, NULL);
+       if (IS_ERR(page))
+               return "error reading root directory";
+       kmap(page);
+       dir_entry = page_address(page);
+       for (i = 0; i < 2; i++) {
+               /* maximum 3 bytes - due to match_root limitation */
+               if (strncmp(dir_entry[i].de_fname, match_root[i], 3))
+                       error = 1;
+       }
+       qnx6_put_page(page);
+       if (error)
+               return "error reading root directory.";
+       return NULL;
+}
+
+#ifdef CONFIG_QNX6FS_DEBUG
+void qnx6_superblock_debug(struct qnx6_super_block *sb, struct super_block *s)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+
+       QNX6DEBUG((KERN_INFO "magic: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_magic)));
+       QNX6DEBUG((KERN_INFO "checksum: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_checksum)));
+       QNX6DEBUG((KERN_INFO "serial: %llx\n",
+                               fs64_to_cpu(sbi, sb->sb_serial)));
+       QNX6DEBUG((KERN_INFO "flags: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_flags)));
+       QNX6DEBUG((KERN_INFO "blocksize: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_blocksize)));
+       QNX6DEBUG((KERN_INFO "num_inodes: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_num_inodes)));
+       QNX6DEBUG((KERN_INFO "free_inodes: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_free_inodes)));
+       QNX6DEBUG((KERN_INFO "num_blocks: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_num_blocks)));
+       QNX6DEBUG((KERN_INFO "free_blocks: %08x\n",
+                               fs32_to_cpu(sbi, sb->sb_free_blocks)));
+       QNX6DEBUG((KERN_INFO "inode_levels: %02x\n",
+                               sb->Inode.levels));
+}
+#endif
+
+enum {
+       Opt_mmifs,
+       Opt_err
+};
+
+static const match_table_t tokens = {
+       {Opt_mmifs, "mmi_fs"},
+       {Opt_err, NULL}
+};
+
+static int qnx6_parse_options(char *options, struct super_block *sb)
+{
+       char *p;
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+       substring_t args[MAX_OPT_ARGS];
+
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_mmifs:
+                       set_opt(sbi->s_mount_opt, MMI_FS);
+                       break;
+               default:
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static struct buffer_head *qnx6_check_first_superblock(struct super_block *s,
+                               int offset, int silent)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(s);
+       struct buffer_head *bh;
+       struct qnx6_super_block *sb;
+
+       /* Check the superblock signatures
+          start with the first superblock */
+       bh = sb_bread(s, offset);
+       if (!bh) {
+               printk(KERN_ERR "qnx6: unable to read the first superblock\n");
+               return NULL;
+       }
+       sb = (struct qnx6_super_block *)bh->b_data;
+       if (fs32_to_cpu(sbi, sb->sb_magic) != QNX6_SUPER_MAGIC) {
+               sbi->s_bytesex = BYTESEX_BE;
+               if (fs32_to_cpu(sbi, sb->sb_magic) == QNX6_SUPER_MAGIC) {
+                       /* we got a big endian fs */
+                       QNX6DEBUG((KERN_INFO "qnx6: fs got different"
+                                       " endianess.\n"));
+                       return bh;
+               } else
+                       sbi->s_bytesex = BYTESEX_LE;
+               if (!silent) {
+                       if (offset == 0) {
+                               printk(KERN_ERR "qnx6: wrong signature (magic)"
+                                       " in superblock #1.\n");
+                       } else {
+                               printk(KERN_INFO "qnx6: wrong signature (magic)"
+                                       " at position (0x%lx) - will try"
+                                       " alternative position (0x0000).\n",
+                                               offset * s->s_blocksize);
+                       }
+               }
+               brelse(bh);
+               return NULL;
+       }
+       return bh;
+}
+
+static struct inode *qnx6_private_inode(struct super_block *s,
+                                       struct qnx6_root_node *p);
+
+static int qnx6_fill_super(struct super_block *s, void *data, int silent)
+{
+       struct buffer_head *bh1 = NULL, *bh2 = NULL;
+       struct qnx6_super_block *sb1 = NULL, *sb2 = NULL;
+       struct qnx6_sb_info *sbi;
+       struct inode *root;
+       const char *errmsg;
+       struct qnx6_sb_info *qs;
+       int ret = -EINVAL;
+       u64 offset;
+       int bootblock_offset = QNX6_BOOTBLOCK_SIZE;
+
+       qs = kzalloc(sizeof(struct qnx6_sb_info), GFP_KERNEL);
+       if (!qs)
+               return -ENOMEM;
+       s->s_fs_info = qs;
+
+       /* Superblock always is 512 Byte long */
+       if (!sb_set_blocksize(s, QNX6_SUPERBLOCK_SIZE)) {
+               printk(KERN_ERR "qnx6: unable to set blocksize\n");
+               goto outnobh;
+       }
+
+       /* parse the mount-options */
+       if (!qnx6_parse_options((char *) data, s)) {
+               printk(KERN_ERR "qnx6: invalid mount options.\n");
+               goto outnobh;
+       }
+       if (test_opt(s, MMI_FS)) {
+               sb1 = qnx6_mmi_fill_super(s, silent);
+               if (sb1)
+                       goto mmi_success;
+               else
+                       goto outnobh;
+       }
+       sbi = QNX6_SB(s);
+       sbi->s_bytesex = BYTESEX_LE;
+       /* Check the superblock signatures
+          start with the first superblock */
+       bh1 = qnx6_check_first_superblock(s,
+               bootblock_offset / QNX6_SUPERBLOCK_SIZE, silent);
+       if (!bh1) {
+               /* try again without bootblock offset */
+               bh1 = qnx6_check_first_superblock(s, 0, silent);
+               if (!bh1) {
+                       printk(KERN_ERR "qnx6: unable to read the first superblock\n");
+                       goto outnobh;
+               }
+               /* seems that no bootblock at partition start */
+               bootblock_offset = 0;
+       }
+       sb1 = (struct qnx6_super_block *)bh1->b_data;
+
+#ifdef CONFIG_QNX6FS_DEBUG
+       qnx6_superblock_debug(sb1, s);
+#endif
+
+       /* checksum check - start at byte 8 and end at byte 512 */
+       if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
+                       crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
+               printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+               goto out;
+       }
+
+       /* set new blocksize */
+       if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
+               printk(KERN_ERR "qnx6: unable to set blocksize\n");
+               goto out;
+       }
+       /* blocksize invalidates bh - pull it back in */
+       brelse(bh1);
+       bh1 = sb_bread(s, bootblock_offset >> s->s_blocksize_bits);
+       if (!bh1)
+               goto outnobh;
+       sb1 = (struct qnx6_super_block *)bh1->b_data;
+
+       /* calculate second superblock blocknumber */
+       offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) +
+               (bootblock_offset >> s->s_blocksize_bits) +
+               (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
+
+       /* set bootblock offset */
+       sbi->s_blks_off = (bootblock_offset >> s->s_blocksize_bits) +
+                         (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
+
+       /* next the second superblock */
+       bh2 = sb_bread(s, offset);
+       if (!bh2) {
+               printk(KERN_ERR "qnx6: unable to read the second superblock\n");
+               goto out;
+       }
+       sb2 = (struct qnx6_super_block *)bh2->b_data;
+       if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
+               if (!silent)
+                       printk(KERN_ERR "qnx6: wrong signature (magic)"
+                                       " in superblock #2.\n");
+               goto out;
+       }
+
+       /* checksum check - start at byte 8 and end at byte 512 */
+       if (fs32_to_cpu(sbi, sb2->sb_checksum) !=
+                               crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
+               printk(KERN_ERR "qnx6: superblock #2 checksum error\n");
+               goto out;
+       }
+
+       if (fs64_to_cpu(sbi, sb1->sb_serial) >=
+                                       fs64_to_cpu(sbi, sb2->sb_serial)) {
+               /* superblock #1 active */
+               sbi->sb_buf = bh1;
+               sbi->sb = (struct qnx6_super_block *)bh1->b_data;
+               brelse(bh2);
+               printk(KERN_INFO "qnx6: superblock #1 active\n");
+       } else {
+               /* superblock #2 active */
+               sbi->sb_buf = bh2;
+               sbi->sb = (struct qnx6_super_block *)bh2->b_data;
+               brelse(bh1);
+               printk(KERN_INFO "qnx6: superblock #2 active\n");
+       }
+mmi_success:
+       /* sanity check - limit maximum indirect pointer levels */
+       if (sb1->Inode.levels > QNX6_PTR_MAX_LEVELS) {
+               printk(KERN_ERR "qnx6: too many inode levels (max %i, sb %i)\n",
+                       QNX6_PTR_MAX_LEVELS, sb1->Inode.levels);
+               goto out;
+       }
+       if (sb1->Longfile.levels > QNX6_PTR_MAX_LEVELS) {
+               printk(KERN_ERR "qnx6: too many longfilename levels"
+                               " (max %i, sb %i)\n",
+                       QNX6_PTR_MAX_LEVELS, sb1->Longfile.levels);
+               goto out;
+       }
+       s->s_op = &qnx6_sops;
+       s->s_magic = QNX6_SUPER_MAGIC;
+       s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
+
+       /* ease the later tree level calculations */
+       sbi = QNX6_SB(s);
+       sbi->s_ptrbits = ilog2(s->s_blocksize / 4);
+       sbi->inodes = qnx6_private_inode(s, &sb1->Inode);
+       if (!sbi->inodes)
+               goto out;
+       sbi->longfile = qnx6_private_inode(s, &sb1->Longfile);
+       if (!sbi->longfile)
+               goto out1;
+
+       /* prefetch root inode */
+       root = qnx6_iget(s, QNX6_ROOT_INO);
+       if (IS_ERR(root)) {
+               printk(KERN_ERR "qnx6: get inode failed\n");
+               ret = PTR_ERR(root);
+               goto out2;
+       }
+
+       ret = -ENOMEM;
+       s->s_root = d_make_root(root);
+       if (!s->s_root)
+               goto out2;
+
+       ret = -EINVAL;
+       errmsg = qnx6_checkroot(s);
+       if (errmsg != NULL) {
+               if (!silent)
+                       printk(KERN_ERR "qnx6: %s\n", errmsg);
+               goto out3;
+       }
+       return 0;
+
+out3:
+       dput(s->s_root);
+       s->s_root = NULL;
+out2:
+       iput(sbi->longfile);
+out1:
+       iput(sbi->inodes);
+out:
+       if (bh1)
+               brelse(bh1);
+       if (bh2)
+               brelse(bh2);
+outnobh:
+       kfree(qs);
+       s->s_fs_info = NULL;
+       return ret;
+}
+
+static void qnx6_put_super(struct super_block *sb)
+{
+       struct qnx6_sb_info *qs = QNX6_SB(sb);
+       brelse(qs->sb_buf);
+       iput(qs->longfile);
+       iput(qs->inodes);
+       kfree(qs);
+       sb->s_fs_info = NULL;
+       return;
+}
+
+static sector_t qnx6_bmap(struct address_space *mapping, sector_t block)
+{
+       return generic_block_bmap(mapping, block, qnx6_get_block);
+}
+static const struct address_space_operations qnx6_aops = {
+       .readpage       = qnx6_readpage,
+       .readpages      = qnx6_readpages,
+       .bmap           = qnx6_bmap
+};
+
+static struct inode *qnx6_private_inode(struct super_block *s,
+                                       struct qnx6_root_node *p)
+{
+       struct inode *inode = new_inode(s);
+       if (inode) {
+               struct qnx6_inode_info *ei = QNX6_I(inode);
+               struct qnx6_sb_info *sbi = QNX6_SB(s);
+               inode->i_size = fs64_to_cpu(sbi, p->size);
+               memcpy(ei->di_block_ptr, p->ptr, sizeof(p->ptr));
+               ei->di_filelevels = p->levels;
+               inode->i_mode = S_IFREG | S_IRUSR; /* probably wrong */
+               inode->i_mapping->a_ops = &qnx6_aops;
+       }
+       return inode;
+}
+
+struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
+{
+       struct qnx6_sb_info *sbi = QNX6_SB(sb);
+       struct qnx6_inode_entry *raw_inode;
+       struct inode *inode;
+       struct qnx6_inode_info  *ei;
+       struct address_space *mapping;
+       struct page *page;
+       u32 n, offs;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       ei = QNX6_I(inode);
+
+       inode->i_mode = 0;
+
+       if (ino == 0) {
+               printk(KERN_ERR "qnx6: bad inode number on dev %s: %u is "
+                               "out of range\n",
+                      sb->s_id, ino);
+               iget_failed(inode);
+               return ERR_PTR(-EIO);
+       }
+       n = (ino - 1) >> (PAGE_CACHE_SHIFT - QNX6_INODE_SIZE_BITS);
+       offs = (ino - 1) & (~PAGE_CACHE_MASK >> QNX6_INODE_SIZE_BITS);
+       mapping = sbi->inodes->i_mapping;
+       page = read_mapping_page(mapping, n, NULL);
+       if (IS_ERR(page)) {
+               printk(KERN_ERR "qnx6: major problem: unable to read inode from "
+                      "dev %s\n", sb->s_id);
+               iget_failed(inode);
+               return ERR_CAST(page);
+       }
+       kmap(page);
+       raw_inode = ((struct qnx6_inode_entry *)page_address(page)) + offs;
+
+       inode->i_mode    = fs16_to_cpu(sbi, raw_inode->di_mode);
+       inode->i_uid     = (uid_t)fs32_to_cpu(sbi, raw_inode->di_uid);
+       inode->i_gid     = (gid_t)fs32_to_cpu(sbi, raw_inode->di_gid);
+       inode->i_size    = fs64_to_cpu(sbi, raw_inode->di_size);
+       inode->i_mtime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_mtime);
+       inode->i_mtime.tv_nsec = 0;
+       inode->i_atime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_atime);
+       inode->i_atime.tv_nsec = 0;
+       inode->i_ctime.tv_sec   = fs32_to_cpu(sbi, raw_inode->di_ctime);
+       inode->i_ctime.tv_nsec = 0;
+
+       /* calc blocks based on 512 byte blocksize */
+       inode->i_blocks = (inode->i_size + 511) >> 9;
+
+       memcpy(&ei->di_block_ptr, &raw_inode->di_block_ptr,
+                               sizeof(raw_inode->di_block_ptr));
+       ei->di_filelevels = raw_inode->di_filelevels;
+
+       if (S_ISREG(inode->i_mode)) {
+               inode->i_fop = &generic_ro_fops;
+               inode->i_mapping->a_ops = &qnx6_aops;
+       } else if (S_ISDIR(inode->i_mode)) {
+               inode->i_op = &qnx6_dir_inode_operations;
+               inode->i_fop = &qnx6_dir_operations;
+               inode->i_mapping->a_ops = &qnx6_aops;
+       } else if (S_ISLNK(inode->i_mode)) {
+               inode->i_op = &page_symlink_inode_operations;
+               inode->i_mapping->a_ops = &qnx6_aops;
+       } else
+               init_special_inode(inode, inode->i_mode, 0);
+       qnx6_put_page(page);
+       unlock_new_inode(inode);
+       return inode;
+}
+
+static struct kmem_cache *qnx6_inode_cachep;
+
+static struct inode *qnx6_alloc_inode(struct super_block *sb)
+{
+       struct qnx6_inode_info *ei;
+       ei = kmem_cache_alloc(qnx6_inode_cachep, GFP_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void qnx6_i_callback(struct rcu_head *head)
+{
+       struct inode *inode = container_of(head, struct inode, i_rcu);
+       INIT_LIST_HEAD(&inode->i_dentry);
+       kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));
+}
+
+static void qnx6_destroy_inode(struct inode *inode)
+{
+       call_rcu(&inode->i_rcu, qnx6_i_callback);
+}
+
+static void init_once(void *foo)
+{
+       struct qnx6_inode_info *ei = (struct qnx6_inode_info *) foo;
+
+       inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+       qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",
+                                            sizeof(struct qnx6_inode_info),
+                                            0, (SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
+                                            init_once);
+       if (!qnx6_inode_cachep)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       kmem_cache_destroy(qnx6_inode_cachep);
+}
+
+static struct dentry *qnx6_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data)
+{
+       return mount_bdev(fs_type, flags, dev_name, data, qnx6_fill_super);
+}
+
+static struct file_system_type qnx6_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "qnx6",
+       .mount          = qnx6_mount,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+
+static int __init init_qnx6_fs(void)
+{
+       int err;
+
+       err = init_inodecache();
+       if (err)
+               return err;
+
+       err = register_filesystem(&qnx6_fs_type);
+       if (err) {
+               destroy_inodecache();
+               return err;
+       }
+
+       printk(KERN_INFO "QNX6 filesystem 1.0.0 registered.\n");
+       return 0;
+}
+
+static void __exit exit_qnx6_fs(void)
+{
+       unregister_filesystem(&qnx6_fs_type);
+       destroy_inodecache();
+}
+
+module_init(init_qnx6_fs)
+module_exit(exit_qnx6_fs)
+MODULE_LICENSE("GPL");
diff --git a/fs/qnx6/namei.c b/fs/qnx6/namei.c
new file mode 100644 (file)
index 0000000..8a97289
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 pagemap extension by Al Viro
+ *
+ */
+
+#include "qnx6.h"
+
+struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
+                               struct nameidata *nd)
+{
+       unsigned ino;
+       struct page *page;
+       struct inode *foundinode = NULL;
+       const char *name = dentry->d_name.name;
+       int len = dentry->d_name.len;
+
+       if (len > QNX6_LONG_NAME_MAX)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       ino = qnx6_find_entry(len, dir, name, &page);
+       if (ino) {
+               foundinode = qnx6_iget(dir->i_sb, ino);
+               qnx6_put_page(page);
+               if (IS_ERR(foundinode)) {
+                       QNX6DEBUG((KERN_ERR "qnx6: lookup->iget -> "
+                               " error %ld\n", PTR_ERR(foundinode)));
+                       return ERR_CAST(foundinode);
+               }
+       } else {
+               QNX6DEBUG((KERN_INFO "qnx6_lookup: not found %s\n", name));
+               return NULL;
+       }
+       d_add(dentry, foundinode);
+       return NULL;
+}
diff --git a/fs/qnx6/qnx6.h b/fs/qnx6/qnx6.h
new file mode 100644 (file)
index 0000000..6c5e02a
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ * 16-02-2012 page map extension by Al Viro
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+typedef __u16 __bitwise __fs16;
+typedef __u32 __bitwise __fs32;
+typedef __u64 __bitwise __fs64;
+
+#include <linux/qnx6_fs.h>
+
+#ifdef CONFIG_QNX6FS_DEBUG
+#define QNX6DEBUG(X) printk X
+#else
+#define QNX6DEBUG(X) (void) 0
+#endif
+
+struct qnx6_sb_info {
+       struct buffer_head      *sb_buf;        /* superblock buffer */
+       struct qnx6_super_block *sb;            /* our superblock */
+       int                     s_blks_off;     /* blkoffset fs-startpoint */
+       int                     s_ptrbits;      /* indirect pointer bitfield */
+       unsigned long           s_mount_opt;    /* all mount options */
+       int                     s_bytesex;      /* holds endianess info */
+       struct inode *          inodes;
+       struct inode *          longfile;
+};
+
+struct qnx6_inode_info {
+       __fs32                  di_block_ptr[QNX6_NO_DIRECT_POINTERS];
+       __u8                    di_filelevels;
+       __u32                   i_dir_start_lookup;
+       struct inode            vfs_inode;
+};
+
+extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino);
+extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
+                                       struct nameidata *nd);
+
+#ifdef CONFIG_QNX6FS_DEBUG
+extern void qnx6_superblock_debug(struct qnx6_super_block *,
+                                               struct super_block *);
+#endif
+
+extern const struct inode_operations qnx6_dir_inode_operations;
+extern const struct file_operations qnx6_dir_operations;
+
+static inline struct qnx6_sb_info *QNX6_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
+static inline struct qnx6_inode_info *QNX6_I(struct inode *inode)
+{
+       return container_of(inode, struct qnx6_inode_info, vfs_inode);
+}
+
+#define clear_opt(o, opt)              (o &= ~(QNX6_MOUNT_##opt))
+#define set_opt(o, opt)                        (o |= (QNX6_MOUNT_##opt))
+#define test_opt(sb, opt)              (QNX6_SB(sb)->s_mount_opt & \
+                                        QNX6_MOUNT_##opt)
+enum {
+       BYTESEX_LE,
+       BYTESEX_BE,
+};
+
+static inline __u64 fs64_to_cpu(struct qnx6_sb_info *sbi, __fs64 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return le64_to_cpu((__force __le64)n);
+       else
+               return be64_to_cpu((__force __be64)n);
+}
+
+static inline __fs64 cpu_to_fs64(struct qnx6_sb_info *sbi, __u64 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return (__force __fs64)cpu_to_le64(n);
+       else
+               return (__force __fs64)cpu_to_be64(n);
+}
+
+static inline __u32 fs32_to_cpu(struct qnx6_sb_info *sbi, __fs32 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return le32_to_cpu((__force __le32)n);
+       else
+               return be32_to_cpu((__force __be32)n);
+}
+
+static inline __fs32 cpu_to_fs32(struct qnx6_sb_info *sbi, __u32 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return (__force __fs32)cpu_to_le32(n);
+       else
+               return (__force __fs32)cpu_to_be32(n);
+}
+
+static inline __u16 fs16_to_cpu(struct qnx6_sb_info *sbi, __fs16 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return le16_to_cpu((__force __le16)n);
+       else
+               return be16_to_cpu((__force __be16)n);
+}
+
+static inline __fs16 cpu_to_fs16(struct qnx6_sb_info *sbi, __u16 n)
+{
+       if (sbi->s_bytesex == BYTESEX_LE)
+               return (__force __fs16)cpu_to_le16(n);
+       else
+               return (__force __fs16)cpu_to_be16(n);
+}
+
+extern struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s,
+                                                   int silent);
+
+static inline void qnx6_put_page(struct page *page)
+{
+       kunmap(page);
+       page_cache_release(page);
+}
+
+extern unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
+                               struct page **res_page);
diff --git a/fs/qnx6/super_mmi.c b/fs/qnx6/super_mmi.c
new file mode 100644 (file)
index 0000000..29c32cb
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * QNX6 file system, Linux implementation.
+ *
+ * Version : 1.0.0
+ *
+ * History :
+ *
+ * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
+ *
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include "qnx6.h"
+
+static void qnx6_mmi_copy_sb(struct qnx6_super_block *qsb,
+               struct qnx6_mmi_super_block *sb)
+{
+       qsb->sb_magic = sb->sb_magic;
+       qsb->sb_checksum = sb->sb_checksum;
+       qsb->sb_serial = sb->sb_serial;
+       qsb->sb_blocksize = sb->sb_blocksize;
+       qsb->sb_num_inodes = sb->sb_num_inodes;
+       qsb->sb_free_inodes = sb->sb_free_inodes;
+       qsb->sb_num_blocks = sb->sb_num_blocks;
+       qsb->sb_free_blocks = sb->sb_free_blocks;
+
+       /* the rest of the superblock is the same */
+       memcpy(&qsb->Inode, &sb->Inode, sizeof(sb->Inode));
+       memcpy(&qsb->Bitmap, &sb->Bitmap, sizeof(sb->Bitmap));
+       memcpy(&qsb->Longfile, &sb->Longfile, sizeof(sb->Longfile));
+}
+
+struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s, int silent)
+{
+       struct buffer_head *bh1, *bh2 = NULL;
+       struct qnx6_mmi_super_block *sb1, *sb2;
+       struct qnx6_super_block *qsb = NULL;
+       struct qnx6_sb_info *sbi;
+       __u64 offset;
+
+       /* Check the superblock signatures
+          start with the first superblock */
+       bh1 = sb_bread(s, 0);
+       if (!bh1) {
+               printk(KERN_ERR "qnx6: Unable to read first mmi superblock\n");
+               return NULL;
+       }
+       sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
+       sbi = QNX6_SB(s);
+       if (fs32_to_cpu(sbi, sb1->sb_magic) != QNX6_SUPER_MAGIC) {
+               if (!silent) {
+                       printk(KERN_ERR "qnx6: wrong signature (magic) in"
+                                       " superblock #1.\n");
+                       goto out;
+               }
+       }
+
+       /* checksum check - start at byte 8 and end at byte 512 */
+       if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
+                               crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
+               printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+               goto out;
+       }
+
+       /* calculate second superblock blocknumber */
+       offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + QNX6_SUPERBLOCK_AREA /
+                                       fs32_to_cpu(sbi, sb1->sb_blocksize);
+
+       /* set new blocksize */
+       if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
+               printk(KERN_ERR "qnx6: unable to set blocksize\n");
+               goto out;
+       }
+       /* blocksize invalidates bh - pull it back in */
+       brelse(bh1);
+       bh1 = sb_bread(s, 0);
+       if (!bh1)
+               goto out;
+       sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
+
+       /* read second superblock */
+       bh2 = sb_bread(s, offset);
+       if (!bh2) {
+               printk(KERN_ERR "qnx6: unable to read the second superblock\n");
+               goto out;
+       }
+       sb2 = (struct qnx6_mmi_super_block *)bh2->b_data;
+       if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
+               if (!silent)
+                       printk(KERN_ERR "qnx6: wrong signature (magic) in"
+                                       " superblock #2.\n");
+               goto out;
+       }
+
+       /* checksum check - start at byte 8 and end at byte 512 */
+       if (fs32_to_cpu(sbi, sb2->sb_checksum)
+                       != crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
+               printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
+               goto out;
+       }
+
+       qsb = kmalloc(sizeof(*qsb), GFP_KERNEL);
+       if (!qsb) {
+               printk(KERN_ERR "qnx6: unable to allocate memory.\n");
+               goto out;
+       }
+
+       if (fs64_to_cpu(sbi, sb1->sb_serial) >
+                                       fs64_to_cpu(sbi, sb2->sb_serial)) {
+               /* superblock #1 active */
+               qnx6_mmi_copy_sb(qsb, sb1);
+#ifdef CONFIG_QNX6FS_DEBUG
+               qnx6_superblock_debug(qsb, s);
+#endif
+               memcpy(bh1->b_data, qsb, sizeof(struct qnx6_super_block));
+
+               sbi->sb_buf = bh1;
+               sbi->sb = (struct qnx6_super_block *)bh1->b_data;
+               brelse(bh2);
+               printk(KERN_INFO "qnx6: superblock #1 active\n");
+       } else {
+               /* superblock #2 active */
+               qnx6_mmi_copy_sb(qsb, sb2);
+#ifdef CONFIG_QNX6FS_DEBUG
+               qnx6_superblock_debug(qsb, s);
+#endif
+               memcpy(bh2->b_data, qsb, sizeof(struct qnx6_super_block));
+
+               sbi->sb_buf = bh2;
+               sbi->sb = (struct qnx6_super_block *)bh2->b_data;
+               brelse(bh1);
+               printk(KERN_INFO "qnx6: superblock #2 active\n");
+       }
+       kfree(qsb);
+
+       /* offset for mmi_fs is just SUPERBLOCK_AREA bytes */
+       sbi->s_blks_off = QNX6_SUPERBLOCK_AREA / s->s_blocksize;
+
+       /* success */
+       return sbi->sb;
+
+out:
+       if (bh1 != NULL)
+               brelse(bh1);
+       if (bh2 != NULL)
+               brelse(bh2);
+       return NULL;
+}
index 4674197..8b4f12b 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
+#include <linux/sched.h>
 #include <linux/kmod.h>
 #include <linux/namei.h>
 #include <linux/capability.h>
index aec766a..a1fdabe 100644 (file)
@@ -209,22 +209,19 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
 int ramfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct ramfs_fs_info *fsi;
-       struct inode *inode = NULL;
-       struct dentry *root;
+       struct inode *inode;
        int err;
 
        save_mount_options(sb, data);
 
        fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
        sb->s_fs_info = fsi;
-       if (!fsi) {
-               err = -ENOMEM;
-               goto fail;
-       }
+       if (!fsi)
+               return -ENOMEM;
 
        err = ramfs_parse_options(data, &fsi->mount_opts);
        if (err)
-               goto fail;
+               return err;
 
        sb->s_maxbytes          = MAX_LFS_FILESIZE;
        sb->s_blocksize         = PAGE_CACHE_SIZE;
@@ -234,24 +231,11 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_time_gran         = 1;
 
        inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
-       if (!inode) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       root = d_alloc_root(inode);
-       sb->s_root = root;
-       if (!root) {
-               err = -ENOMEM;
-               goto fail;
-       }
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
+               return -ENOMEM;
 
        return 0;
-fail:
-       kfree(fsi);
-       sb->s_fs_info = NULL;
-       iput(inode);
-       return err;
 }
 
 struct dentry *ramfs_mount(struct file_system_type *fs_type,
diff --git a/fs/reiserfs/acl.h b/fs/reiserfs/acl.h
new file mode 100644 (file)
index 0000000..f096b80
--- /dev/null
@@ -0,0 +1,76 @@
+#include <linux/init.h>
+#include <linux/posix_acl.h>
+
+#define REISERFS_ACL_VERSION   0x0001
+
+typedef struct {
+       __le16 e_tag;
+       __le16 e_perm;
+       __le32 e_id;
+} reiserfs_acl_entry;
+
+typedef struct {
+       __le16 e_tag;
+       __le16 e_perm;
+} reiserfs_acl_entry_short;
+
+typedef struct {
+       __le32 a_version;
+} reiserfs_acl_header;
+
+static inline size_t reiserfs_acl_size(int count)
+{
+       if (count <= 4) {
+               return sizeof(reiserfs_acl_header) +
+                   count * sizeof(reiserfs_acl_entry_short);
+       } else {
+               return sizeof(reiserfs_acl_header) +
+                   4 * sizeof(reiserfs_acl_entry_short) +
+                   (count - 4) * sizeof(reiserfs_acl_entry);
+       }
+}
+
+static inline int reiserfs_acl_count(size_t size)
+{
+       ssize_t s;
+       size -= sizeof(reiserfs_acl_header);
+       s = size - 4 * sizeof(reiserfs_acl_entry_short);
+       if (s < 0) {
+               if (size % sizeof(reiserfs_acl_entry_short))
+                       return -1;
+               return size / sizeof(reiserfs_acl_entry_short);
+       } else {
+               if (s % sizeof(reiserfs_acl_entry))
+                       return -1;
+               return s / sizeof(reiserfs_acl_entry) + 4;
+       }
+}
+
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+struct posix_acl *reiserfs_get_acl(struct inode *inode, int type);
+int reiserfs_acl_chmod(struct inode *inode);
+int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                                struct inode *dir, struct dentry *dentry,
+                                struct inode *inode);
+int reiserfs_cache_default_acl(struct inode *dir);
+extern const struct xattr_handler reiserfs_posix_acl_default_handler;
+extern const struct xattr_handler reiserfs_posix_acl_access_handler;
+
+#else
+
+#define reiserfs_cache_default_acl(inode) 0
+#define reiserfs_get_acl NULL
+
+static inline int reiserfs_acl_chmod(struct inode *inode)
+{
+       return 0;
+}
+
+static inline int
+reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                            const struct inode *dir, struct dentry *dentry,
+                            struct inode *inode)
+{
+       return 0;
+}
+#endif
index 70de42f..4c0c7d1 100644 (file)
@@ -4,14 +4,12 @@
 /* Reiserfs block (de)allocator, bitmap-based. */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
-#include <linux/reiserfs_fs_sb.h>
-#include <linux/reiserfs_fs_i.h>
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 
index 133e935..66c53b6 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/stat.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
index 60c0804..2b7882b 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
 
index ace6350..8375c92 100644 (file)
@@ -3,9 +3,9 @@
  */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
index 1e4250b..430e065 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* To make any changes in the tree we find a node, that contains item
index 6471c67..91b0cc1 100644 (file)
@@ -19,7 +19,7 @@
 //
 
 #include <linux/kernel.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <asm/types.h>
 
 #define DELTA 0x9E3779B9
index 2074fd9..e1978fd 100644 (file)
@@ -5,7 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* this is one and only function that is used outside (do_balance.c) */
index 9e8cd5a..494c315 100644 (file)
@@ -4,9 +4,9 @@
 
 #include <linux/time.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/exportfs.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
index 950e3d1..0c21850 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/time.h>
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
index 72cb1cc..ee382ef 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 
 // this contains item handlers for old item types: sd, direct,
 // indirect, directory
index c3cf54f..cf9f4de 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/time.h>
 #include <linux/semaphore.h>
 #include <linux/vmalloc.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/fcntl.h>
index b43d015..79e5a8b 100644 (file)
@@ -5,7 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 /* these are used in do_balance.c */
index 7df1ce4..d735bc8 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/mutex.h>
 
 /*
index 1463788..84e8a69 100644 (file)
@@ -14,9 +14,9 @@
 #include <linux/time.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/quotaops.h>
 
 #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) set_nlink(i, 1); }
index 3a6de81..f732d6a 100644 (file)
@@ -5,8 +5,7 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/time.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 
 // find where objectid map starts
 #define objectid_map(s,rs) (old_format_only (s) ? \
index 45de98b..c0b1112 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <linux/time.h>
 #include <linux/fs.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/string.h>
 #include <linux/buffer_head.h>
 
@@ -329,7 +329,7 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
     Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it
     pointless complexity):
 
-    panics in reiserfs_fs.h have numbers from 1000 to 1999
+    panics in reiserfs.h have numbers from 1000 to 1999
     super.c                                    2000 to 2999
     preserve.c (unused)                            3000 to 3999
     bitmap.c                               4000 to 4999
index 7a99811..2c1ade6 100644 (file)
@@ -12,8 +12,7 @@
 #include <linux/time.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h
new file mode 100644 (file)
index 0000000..445d768
--- /dev/null
@@ -0,0 +1,2922 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+#include <linux/reiserfs_fs.h>
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
+#include <linux/buffer_head.h>
+
+/* the 32 bit compat definitions with int argument */
+#define REISERFS_IOC32_UNPACK          _IOW(0xCD, 1, int)
+#define REISERFS_IOC32_GETFLAGS                FS_IOC32_GETFLAGS
+#define REISERFS_IOC32_SETFLAGS                FS_IOC32_SETFLAGS
+#define REISERFS_IOC32_GETVERSION      FS_IOC32_GETVERSION
+#define REISERFS_IOC32_SETVERSION      FS_IOC32_SETVERSION
+
+struct reiserfs_journal_list;
+
+/** bitmasks for i_flags field in reiserfs-specific part of inode */
+typedef enum {
+    /** this says what format of key do all items (but stat data) of
+      an object have.  If this is set, that format is 3.6 otherwise
+      - 3.5 */
+       i_item_key_version_mask = 0x0001,
+    /** If this is unset, object has 3.5 stat data, otherwise, it has
+      3.6 stat data with 64bit size, 32bit nlink etc. */
+       i_stat_data_version_mask = 0x0002,
+    /** file might need tail packing on close */
+       i_pack_on_close_mask = 0x0004,
+    /** don't pack tail of file */
+       i_nopack_mask = 0x0008,
+    /** If those is set, "safe link" was created for this file during
+      truncate or unlink. Safe link is used to avoid leakage of disk
+      space on crash with some files open, but unlinked. */
+       i_link_saved_unlink_mask = 0x0010,
+       i_link_saved_truncate_mask = 0x0020,
+       i_has_xattr_dir = 0x0040,
+       i_data_log = 0x0080,
+} reiserfs_inode_flags;
+
+struct reiserfs_inode_info {
+       __u32 i_key[4];         /* key is still 4 32 bit integers */
+    /** transient inode flags that are never stored on disk. Bitmasks
+      for this field are defined above. */
+       __u32 i_flags;
+
+       __u32 i_first_direct_byte;      // offset of first byte stored in direct item.
+
+       /* copy of persistent inode flags read from sd_attrs. */
+       __u32 i_attrs;
+
+       int i_prealloc_block;   /* first unused block of a sequence of unused blocks */
+       int i_prealloc_count;   /* length of that sequence */
+       struct list_head i_prealloc_list;       /* per-transaction list of inodes which
+                                                * have preallocated blocks */
+
+       unsigned new_packing_locality:1;        /* new_packig_locality is created; new blocks
+                                                * for the contents of this directory should be
+                                                * displaced */
+
+       /* we use these for fsync or O_SYNC to decide which transaction
+        ** needs to be committed in order for this inode to be properly
+        ** flushed */
+       unsigned int i_trans_id;
+       struct reiserfs_journal_list *i_jl;
+       atomic_t openers;
+       struct mutex tailpack;
+#ifdef CONFIG_REISERFS_FS_XATTR
+       struct rw_semaphore i_xattr_sem;
+#endif
+       struct inode vfs_inode;
+};
+
+typedef enum {
+       reiserfs_attrs_cleared = 0x00000001,
+} reiserfs_super_block_flags;
+
+/* struct reiserfs_super_block accessors/mutators
+ * since this is a disk structure, it will always be in
+ * little endian format. */
+#define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
+#define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
+#define sb_free_blocks(sbp)         (le32_to_cpu((sbp)->s_v1.s_free_blocks))
+#define set_sb_free_blocks(sbp,v)   ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v))
+#define sb_root_block(sbp)          (le32_to_cpu((sbp)->s_v1.s_root_block))
+#define set_sb_root_block(sbp,v)    ((sbp)->s_v1.s_root_block = cpu_to_le32(v))
+
+#define sb_jp_journal_1st_block(sbp)  \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block))
+#define set_sb_jp_journal_1st_block(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v))
+#define sb_jp_journal_dev(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev))
+#define set_sb_jp_journal_dev(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v))
+#define sb_jp_journal_size(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size))
+#define set_sb_jp_journal_size(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v))
+#define sb_jp_journal_trans_max(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max))
+#define set_sb_jp_journal_trans_max(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v))
+#define sb_jp_journal_magic(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic))
+#define set_sb_jp_journal_magic(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v))
+#define sb_jp_journal_max_batch(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch))
+#define set_sb_jp_journal_max_batch(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v))
+#define sb_jp_jourmal_max_commit_age(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age))
+#define set_sb_jp_journal_max_commit_age(sbp,v) \
+              ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v))
+
+#define sb_blocksize(sbp)          (le16_to_cpu((sbp)->s_v1.s_blocksize))
+#define set_sb_blocksize(sbp,v)    ((sbp)->s_v1.s_blocksize = cpu_to_le16(v))
+#define sb_oid_maxsize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_maxsize))
+#define set_sb_oid_maxsize(sbp,v)  ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v))
+#define sb_oid_cursize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_cursize))
+#define set_sb_oid_cursize(sbp,v)  ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v))
+#define sb_umount_state(sbp)       (le16_to_cpu((sbp)->s_v1.s_umount_state))
+#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
+#define sb_fs_state(sbp)           (le16_to_cpu((sbp)->s_v1.s_fs_state))
+#define set_sb_fs_state(sbp,v)     ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
+#define sb_hash_function_code(sbp) \
+              (le32_to_cpu((sbp)->s_v1.s_hash_function_code))
+#define set_sb_hash_function_code(sbp,v) \
+              ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v))
+#define sb_tree_height(sbp)        (le16_to_cpu((sbp)->s_v1.s_tree_height))
+#define set_sb_tree_height(sbp,v)  ((sbp)->s_v1.s_tree_height = cpu_to_le16(v))
+#define sb_bmap_nr(sbp)            (le16_to_cpu((sbp)->s_v1.s_bmap_nr))
+#define set_sb_bmap_nr(sbp,v)      ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v))
+#define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
+#define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
+
+#define sb_mnt_count(sbp)         (le16_to_cpu((sbp)->s_mnt_count))
+#define set_sb_mnt_count(sbp, v)   ((sbp)->s_mnt_count = cpu_to_le16(v))
+
+#define sb_reserved_for_journal(sbp) \
+              (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
+#define set_sb_reserved_for_journal(sbp,v) \
+              ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v))
+
+/* LOGGING -- */
+
+/* These all interelate for performance.
+**
+** If the journal block count is smaller than n transactions, you lose speed.
+** I don't know what n is yet, I'm guessing 8-16.
+**
+** typical transaction size depends on the application, how often fsync is
+** called, and how many metadata blocks you dirty in a 30 second period.
+** The more small files (<16k) you use, the larger your transactions will
+** be.
+**
+** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal
+** to wrap, which slows things down.  If you need high speed meta data updates, the journal should be big enough
+** to prevent wrapping before dirty meta blocks get to disk.
+**
+** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal
+** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping.
+**
+** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash.
+**
+*/
+
+/* don't mess with these for a while */
+                               /* we have a node size define somewhere in reiserfs_fs.h. -Hans */
+#define JOURNAL_BLOCK_SIZE  4096       /* BUG gotta get rid of this */
+#define JOURNAL_MAX_CNODE   1500       /* max cnodes to allocate. */
+#define JOURNAL_HASH_SIZE 8192
+#define JOURNAL_NUM_BITMAPS 5  /* number of copies of the bitmaps to have floating.  Must be >= 2 */
+
+/* One of these for every block in every transaction
+** Each one is in two hash tables.  First, a hash of the current transaction, and after journal_end, a
+** hash of all the in memory transactions.
+** next and prev are used by the current transaction (journal_hash).
+** hnext and hprev are used by journal_list_hash.  If a block is in more than one transaction, the journal_list_hash
+** links it in multiple times.  This allows flush_journal_list to remove just the cnode belonging
+** to a given transaction.
+*/
+struct reiserfs_journal_cnode {
+       struct buffer_head *bh; /* real buffer head */
+       struct super_block *sb; /* dev of real buffer head */
+       __u32 blocknr;          /* block number of real buffer head, == 0 when buffer on disk */
+       unsigned long state;
+       struct reiserfs_journal_list *jlist;    /* journal list this cnode lives in */
+       struct reiserfs_journal_cnode *next;    /* next in transaction list */
+       struct reiserfs_journal_cnode *prev;    /* prev in transaction list */
+       struct reiserfs_journal_cnode *hprev;   /* prev in hash list */
+       struct reiserfs_journal_cnode *hnext;   /* next in hash list */
+};
+
+struct reiserfs_bitmap_node {
+       int id;
+       char *data;
+       struct list_head list;
+};
+
+struct reiserfs_list_bitmap {
+       struct reiserfs_journal_list *journal_list;
+       struct reiserfs_bitmap_node **bitmaps;
+};
+
+/*
+** one of these for each transaction.  The most important part here is the j_realblock.
+** this list of cnodes is used to hash all the blocks in all the commits, to mark all the
+** real buffer heads dirty once all the commits hit the disk,
+** and to make sure every real block in a transaction is on disk before allowing the log area
+** to be overwritten */
+struct reiserfs_journal_list {
+       unsigned long j_start;
+       unsigned long j_state;
+       unsigned long j_len;
+       atomic_t j_nonzerolen;
+       atomic_t j_commit_left;
+       atomic_t j_older_commits_done;  /* all commits older than this on disk */
+       struct mutex j_commit_mutex;
+       unsigned int j_trans_id;
+       time_t j_timestamp;
+       struct reiserfs_list_bitmap *j_list_bitmap;
+       struct buffer_head *j_commit_bh;        /* commit buffer head */
+       struct reiserfs_journal_cnode *j_realblock;
+       struct reiserfs_journal_cnode *j_freedlist;     /* list of buffers that were freed during this trans.  free each of these on flush */
+       /* time ordered list of all active transactions */
+       struct list_head j_list;
+
+       /* time ordered list of all transactions we haven't tried to flush yet */
+       struct list_head j_working_list;
+
+       /* list of tail conversion targets in need of flush before commit */
+       struct list_head j_tail_bh_list;
+       /* list of data=ordered buffers in need of flush before commit */
+       struct list_head j_bh_list;
+       int j_refcount;
+};
+
+struct reiserfs_journal {
+       struct buffer_head **j_ap_blocks;       /* journal blocks on disk */
+       struct reiserfs_journal_cnode *j_last;  /* newest journal block */
+       struct reiserfs_journal_cnode *j_first; /*  oldest journal block.  start here for traverse */
+
+       struct block_device *j_dev_bd;
+       fmode_t j_dev_mode;
+       int j_1st_reserved_block;       /* first block on s_dev of reserved area journal */
+
+       unsigned long j_state;
+       unsigned int j_trans_id;
+       unsigned long j_mount_id;
+       unsigned long j_start;  /* start of current waiting commit (index into j_ap_blocks) */
+       unsigned long j_len;    /* length of current waiting commit */
+       unsigned long j_len_alloc;      /* number of buffers requested by journal_begin() */
+       atomic_t j_wcount;      /* count of writers for current commit */
+       unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
+       unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */
+       unsigned j_last_flush_trans_id; /* last fully flushed journal timestamp */
+       struct buffer_head *j_header_bh;
+
+       time_t j_trans_start_time;      /* time this transaction started */
+       struct mutex j_mutex;
+       struct mutex j_flush_mutex;
+       wait_queue_head_t j_join_wait;  /* wait for current transaction to finish before starting new one */
+       atomic_t j_jlock;       /* lock for j_join_wait */
+       int j_list_bitmap_index;        /* number of next list bitmap to use */
+       int j_must_wait;        /* no more journal begins allowed. MUST sleep on j_join_wait */
+       int j_next_full_flush;  /* next journal_end will flush all journal list */
+       int j_next_async_flush; /* next journal_end will flush all async commits */
+
+       int j_cnode_used;       /* number of cnodes on the used list */
+       int j_cnode_free;       /* number of cnodes on the free list */
+
+       unsigned int j_trans_max;       /* max number of blocks in a transaction.  */
+       unsigned int j_max_batch;       /* max number of blocks to batch into a trans */
+       unsigned int j_max_commit_age;  /* in seconds, how old can an async commit be */
+       unsigned int j_max_trans_age;   /* in seconds, how old can a transaction be */
+       unsigned int j_default_max_commit_age;  /* the default for the max commit age */
+
+       struct reiserfs_journal_cnode *j_cnode_free_list;
+       struct reiserfs_journal_cnode *j_cnode_free_orig;       /* orig pointer returned from vmalloc */
+
+       struct reiserfs_journal_list *j_current_jl;
+       int j_free_bitmap_nodes;
+       int j_used_bitmap_nodes;
+
+       int j_num_lists;        /* total number of active transactions */
+       int j_num_work_lists;   /* number that need attention from kreiserfsd */
+
+       /* debugging to make sure things are flushed in order */
+       unsigned int j_last_flush_id;
+
+       /* debugging to make sure things are committed in order */
+       unsigned int j_last_commit_id;
+
+       struct list_head j_bitmap_nodes;
+       struct list_head j_dirty_buffers;
+       spinlock_t j_dirty_buffers_lock;        /* protects j_dirty_buffers */
+
+       /* list of all active transactions */
+       struct list_head j_journal_list;
+       /* lists that haven't been touched by writeback attempts */
+       struct list_head j_working_list;
+
+       struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */
+       struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */
+       struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];    /* hash table for all the real buffer heads in all
+                                                                                  the transactions */
+       struct list_head j_prealloc_list;       /* list of inodes which have preallocated blocks */
+       int j_persistent_trans;
+       unsigned long j_max_trans_size;
+       unsigned long j_max_batch_size;
+
+       int j_errno;
+
+       /* when flushing ordered buffers, throttle new ordered writers */
+       struct delayed_work j_work;
+       struct super_block *j_work_sb;
+       atomic_t j_async_throttle;
+};
+
+enum journal_state_bits {
+       J_WRITERS_BLOCKED = 1,  /* set when new writers not allowed */
+       J_WRITERS_QUEUED,       /* set when log is full due to too many writers */
+       J_ABORTED,              /* set when log is aborted */
+};
+
+#define JOURNAL_DESC_MAGIC "ReIsErLB"  /* ick.  magic string to find desc blocks in the journal */
+
+typedef __u32(*hashf_t) (const signed char *, int);
+
+struct reiserfs_bitmap_info {
+       __u32 free_count;
+};
+
+struct proc_dir_entry;
+
+#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
+typedef unsigned long int stat_cnt_t;
+typedef struct reiserfs_proc_info_data {
+       spinlock_t lock;
+       int exiting;
+       int max_hash_collisions;
+
+       stat_cnt_t breads;
+       stat_cnt_t bread_miss;
+       stat_cnt_t search_by_key;
+       stat_cnt_t search_by_key_fs_changed;
+       stat_cnt_t search_by_key_restarted;
+
+       stat_cnt_t insert_item_restarted;
+       stat_cnt_t paste_into_item_restarted;
+       stat_cnt_t cut_from_item_restarted;
+       stat_cnt_t delete_solid_item_restarted;
+       stat_cnt_t delete_item_restarted;
+
+       stat_cnt_t leaked_oid;
+       stat_cnt_t leaves_removable;
+
+       /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
+       stat_cnt_t balance_at[5];       /* XXX */
+       /* sbk == search_by_key */
+       stat_cnt_t sbk_read_at[5];      /* XXX */
+       stat_cnt_t sbk_fs_changed[5];
+       stat_cnt_t sbk_restarted[5];
+       stat_cnt_t items_at[5]; /* XXX */
+       stat_cnt_t free_at[5];  /* XXX */
+       stat_cnt_t can_node_be_removed[5];      /* XXX */
+       long int lnum[5];       /* XXX */
+       long int rnum[5];       /* XXX */
+       long int lbytes[5];     /* XXX */
+       long int rbytes[5];     /* XXX */
+       stat_cnt_t get_neighbors[5];
+       stat_cnt_t get_neighbors_restart[5];
+       stat_cnt_t need_l_neighbor[5];
+       stat_cnt_t need_r_neighbor[5];
+
+       stat_cnt_t free_block;
+       struct __scan_bitmap_stats {
+               stat_cnt_t call;
+               stat_cnt_t wait;
+               stat_cnt_t bmap;
+               stat_cnt_t retry;
+               stat_cnt_t in_journal_hint;
+               stat_cnt_t in_journal_nohint;
+               stat_cnt_t stolen;
+       } scan_bitmap;
+       struct __journal_stats {
+               stat_cnt_t in_journal;
+               stat_cnt_t in_journal_bitmap;
+               stat_cnt_t in_journal_reusable;
+               stat_cnt_t lock_journal;
+               stat_cnt_t lock_journal_wait;
+               stat_cnt_t journal_being;
+               stat_cnt_t journal_relock_writers;
+               stat_cnt_t journal_relock_wcount;
+               stat_cnt_t mark_dirty;
+               stat_cnt_t mark_dirty_already;
+               stat_cnt_t mark_dirty_notjournal;
+               stat_cnt_t restore_prepared;
+               stat_cnt_t prepare;
+               stat_cnt_t prepare_retry;
+       } journal;
+} reiserfs_proc_info_data_t;
+#else
+typedef struct reiserfs_proc_info_data {
+} reiserfs_proc_info_data_t;
+#endif
+
+/* reiserfs union of in-core super block data */
+struct reiserfs_sb_info {
+       struct buffer_head *s_sbh;      /* Buffer containing the super block */
+       /* both the comment and the choice of
+          name are unclear for s_rs -Hans */
+       struct reiserfs_super_block *s_rs;      /* Pointer to the super block in the buffer */
+       struct reiserfs_bitmap_info *s_ap_bitmap;
+       struct reiserfs_journal *s_journal;     /* pointer to journal information */
+       unsigned short s_mount_state;   /* reiserfs state (valid, invalid) */
+
+       /* Serialize writers access, replace the old bkl */
+       struct mutex lock;
+       /* Owner of the lock (can be recursive) */
+       struct task_struct *lock_owner;
+       /* Depth of the lock, start from -1 like the bkl */
+       int lock_depth;
+
+       /* Comment? -Hans */
+       void (*end_io_handler) (struct buffer_head *, int);
+       hashf_t s_hash_function;        /* pointer to function which is used
+                                          to sort names in directory. Set on
+                                          mount */
+       unsigned long s_mount_opt;      /* reiserfs's mount options are set
+                                          here (currently - NOTAIL, NOLOG,
+                                          REPLAYONLY) */
+
+       struct {                /* This is a structure that describes block allocator options */
+               unsigned long bits;     /* Bitfield for enable/disable kind of options */
+               unsigned long large_file_size;  /* size started from which we consider file to be a large one(in blocks) */
+               int border;     /* percentage of disk, border takes */
+               int preallocmin;        /* Minimal file size (in blocks) starting from which we do preallocations */
+               int preallocsize;       /* Number of blocks we try to prealloc when file
+                                          reaches preallocmin size (in blocks) or
+                                          prealloc_list is empty. */
+       } s_alloc_options;
+
+       /* Comment? -Hans */
+       wait_queue_head_t s_wait;
+       /* To be obsoleted soon by per buffer seals.. -Hans */
+       atomic_t s_generation_counter;  // increased by one every time the
+       // tree gets re-balanced
+       unsigned long s_properties;     /* File system properties. Currently holds
+                                          on-disk FS format */
+
+       /* session statistics */
+       int s_disk_reads;
+       int s_disk_writes;
+       int s_fix_nodes;
+       int s_do_balance;
+       int s_unneeded_left_neighbor;
+       int s_good_search_by_key_reada;
+       int s_bmaps;
+       int s_bmaps_without_search;
+       int s_direct2indirect;
+       int s_indirect2direct;
+       /* set up when it's ok for reiserfs_read_inode2() to read from
+          disk inode with nlink==0. Currently this is only used during
+          finish_unfinished() processing at mount time */
+       int s_is_unlinked_ok;
+       reiserfs_proc_info_data_t s_proc_info_data;
+       struct proc_dir_entry *procdir;
+       int reserved_blocks;    /* amount of blocks reserved for further allocations */
+       spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
+       struct dentry *priv_root;       /* root of /.reiserfs_priv */
+       struct dentry *xattr_root;      /* root of /.reiserfs_priv/xattrs */
+       int j_errno;
+#ifdef CONFIG_QUOTA
+       char *s_qf_names[MAXQUOTAS];
+       int s_jquota_fmt;
+#endif
+       char *s_jdev;           /* Stored jdev for mount option showing */
+#ifdef CONFIG_REISERFS_CHECK
+
+       struct tree_balance *cur_tb;    /*
+                                        * Detects whether more than one
+                                        * copy of tb exists per superblock
+                                        * as a means of checking whether
+                                        * do_balance is executing concurrently
+                                        * against another tree reader/writer
+                                        * on a same mount point.
+                                        */
+#endif
+};
+
+/* Definitions of reiserfs on-disk properties: */
+#define REISERFS_3_5 0
+#define REISERFS_3_6 1
+#define REISERFS_OLD_FORMAT 2
+
+enum reiserfs_mount_options {
+/* Mount options */
+       REISERFS_LARGETAIL,     /* large tails will be created in a session */
+       REISERFS_SMALLTAIL,     /* small (for files less than block size) tails will be created in a session */
+       REPLAYONLY,             /* replay journal and return 0. Use by fsck */
+       REISERFS_CONVERT,       /* -o conv: causes conversion of old
+                                  format super block to the new
+                                  format. If not specified - old
+                                  partition will be dealt with in a
+                                  manner of 3.5.x */
+
+/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
+** reiserfs disks from 3.5.19 or earlier.  99% of the time, this option
+** is not required.  If the normal autodection code can't determine which
+** hash to use (because both hashes had the same value for a file)
+** use this option to force a specific hash.  It won't allow you to override
+** the existing hash on the FS, so if you have a tea hash disk, and mount
+** with -o hash=rupasov, the mount will fail.
+*/
+       FORCE_TEA_HASH,         /* try to force tea hash on mount */
+       FORCE_RUPASOV_HASH,     /* try to force rupasov hash on mount */
+       FORCE_R5_HASH,          /* try to force rupasov hash on mount */
+       FORCE_HASH_DETECT,      /* try to detect hash function on mount */
+
+       REISERFS_DATA_LOG,
+       REISERFS_DATA_ORDERED,
+       REISERFS_DATA_WRITEBACK,
+
+/* used for testing experimental features, makes benchmarking new
+   features with and without more convenient, should never be used by
+   users in any code shipped to users (ideally) */
+
+       REISERFS_NO_BORDER,
+       REISERFS_NO_UNHASHED_RELOCATION,
+       REISERFS_HASHED_RELOCATION,
+       REISERFS_ATTRS,
+       REISERFS_XATTRS_USER,
+       REISERFS_POSIXACL,
+       REISERFS_EXPOSE_PRIVROOT,
+       REISERFS_BARRIER_NONE,
+       REISERFS_BARRIER_FLUSH,
+
+       /* Actions on error */
+       REISERFS_ERROR_PANIC,
+       REISERFS_ERROR_RO,
+       REISERFS_ERROR_CONTINUE,
+
+       REISERFS_USRQUOTA,      /* User quota option specified */
+       REISERFS_GRPQUOTA,      /* Group quota option specified */
+
+       REISERFS_TEST1,
+       REISERFS_TEST2,
+       REISERFS_TEST3,
+       REISERFS_TEST4,
+       REISERFS_UNSUPPORTED_OPT,
+};
+
+#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH))
+#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH))
+#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH))
+#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT))
+#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER))
+#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
+#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
+#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4))
+
+#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL))
+#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
+#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
+#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS))
+#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
+#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT))
+#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
+#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
+#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
+#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
+#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
+#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT))
+#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
+#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
+#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
+
+#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
+#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
+
+void reiserfs_file_buffer(struct buffer_head *bh, int list);
+extern struct file_system_type reiserfs_fs_type;
+int reiserfs_resize(struct super_block *, unsigned long);
+
+#define CARRY_ON                0
+#define SCHEDULE_OCCURRED       1
+
+#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh)
+#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal)
+#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
+#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
+#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap)
+
+#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
+
+/* A safe version of the "bdevname", which returns the "s_id" field of
+ * a superblock or else "Null superblock" if the super block is NULL.
+ */
+static inline char *reiserfs_bdevname(struct super_block *s)
+{
+       return (s == NULL) ? "Null superblock" : s->s_id;
+}
+
+#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
+static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
+                                               *journal)
+{
+       return test_bit(J_ABORTED, &journal->j_state);
+}
+
+/*
+ * Locking primitives. The write lock is a per superblock
+ * special mutex that has properties close to the Big Kernel Lock
+ * which was used in the previous locking scheme.
+ */
+void reiserfs_write_lock(struct super_block *s);
+void reiserfs_write_unlock(struct super_block *s);
+int reiserfs_write_lock_once(struct super_block *s);
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
+
+#ifdef CONFIG_REISERFS_CHECK
+void reiserfs_lock_check_recursive(struct super_block *s);
+#else
+static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
+#endif
+
+/*
+ * Several mutexes depend on the write lock.
+ * However sometimes we want to relax the write lock while we hold
+ * these mutexes, according to the release/reacquire on schedule()
+ * properties of the Bkl that were used.
+ * Reiserfs performances and locking were based on this scheme.
+ * Now that the write lock is a mutex and not the bkl anymore, doing so
+ * may result in a deadlock:
+ *
+ * A acquire write_lock
+ * A acquire j_commit_mutex
+ * A release write_lock and wait for something
+ * B acquire write_lock
+ * B can't acquire j_commit_mutex and sleep
+ * A can't acquire write lock anymore
+ * deadlock
+ *
+ * What we do here is avoiding such deadlock by playing the same game
+ * than the Bkl: if we can't acquire a mutex that depends on the write lock,
+ * we release the write lock, wait a bit and then retry.
+ *
+ * The mutexes concerned by this hack are:
+ * - The commit mutex of a journal list
+ * - The flush mutex
+ * - The journal lock
+ * - The inode mutex
+ */
+static inline void reiserfs_mutex_lock_safe(struct mutex *m,
+                              struct super_block *s)
+{
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       mutex_lock(m);
+       reiserfs_write_lock(s);
+}
+
+static inline void
+reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
+                              struct super_block *s)
+{
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       mutex_lock_nested(m, subclass);
+       reiserfs_write_lock(s);
+}
+
+static inline void
+reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
+{
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       down_read(sem);
+       reiserfs_write_lock(s);
+}
+
+/*
+ * When we schedule, we usually want to also release the write lock,
+ * according to the previous bkl based locking scheme of reiserfs.
+ */
+static inline void reiserfs_cond_resched(struct super_block *s)
+{
+       if (need_resched()) {
+               reiserfs_write_unlock(s);
+               schedule();
+               reiserfs_write_lock(s);
+       }
+}
+
+struct fid;
+
+/* in reading the #defines, it may help to understand that they employ
+   the following abbreviations:
+
+   B = Buffer
+   I = Item header
+   H = Height within the tree (should be changed to LEV)
+   N = Number of the item in the node
+   STAT = stat data
+   DEH = Directory Entry Header
+   EC = Entry Count
+   E = Entry number
+   UL = Unsigned Long
+   BLKH = BLocK Header
+   UNFM = UNForMatted node
+   DC = Disk Child
+   P = Path
+
+   These #defines are named by concatenating these abbreviations,
+   where first comes the arguments, and last comes the return value,
+   of the macro.
+
+*/
+
+#define USE_INODE_GENERATION_COUNTER
+
+#define REISERFS_PREALLOCATE
+#define DISPLACE_NEW_PACKING_LOCALITIES
+#define PREALLOCATION_SIZE 9
+
+/* n must be power of 2 */
+#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
+
+// to be ok for alpha and others we have to align structures to 8 byte
+// boundary.
+// FIXME: do not change 4 by anything else: there is code which relies on that
+#define ROUND_UP(x) _ROUND_UP(x,8LL)
+
+/* debug levels.  Right now, CONFIG_REISERFS_CHECK means print all debug
+** messages.
+*/
+#define REISERFS_DEBUG_CODE 5  /* extra messages to help find/debug errors */
+
+void __reiserfs_warning(struct super_block *s, const char *id,
+                        const char *func, const char *fmt, ...);
+#define reiserfs_warning(s, id, fmt, args...) \
+        __reiserfs_warning(s, id, __func__, fmt, ##args)
+/* assertions handling */
+
+/** always check a condition and panic if it's false. */
+#define __RASSERT(cond, scond, format, args...)                        \
+do {                                                                   \
+       if (!(cond))                                                    \
+               reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \
+                              __FILE__ ":%i:%s: " format "\n",         \
+                              in_interrupt() ? -1 : task_pid_nr(current), \
+                              __LINE__, __func__ , ##args);            \
+} while (0)
+
+#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
+
+#if defined( CONFIG_REISERFS_CHECK )
+#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args)
+#else
+#define RFALSE( cond, format, args... ) do {;} while( 0 )
+#endif
+
+#define CONSTF __attribute_const__
+/*
+ * Disk Data Structures
+ */
+
+/***************************************************************************/
+/*                             SUPER BLOCK                                 */
+/***************************************************************************/
+
+/*
+ * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
+ * the version in RAM is part of a larger structure containing fields never written to disk.
+ */
+#define UNSET_HASH 0           // read_super will guess about, what hash names
+                    // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+       __le32 jp_journal_1st_block;    /* where does journal start from on its
+                                        * device */
+       __le32 jp_journal_dev;  /* journal device st_rdev */
+       __le32 jp_journal_size; /* size of the journal */
+       __le32 jp_journal_trans_max;    /* max number of blocks in a transaction. */
+       __le32 jp_journal_magic;        /* random value made on fs creation (this
+                                        * was sb_journal_block_count) */
+       __le32 jp_journal_max_batch;    /* max number of blocks to batch into a
+                                        * trans */
+       __le32 jp_journal_max_commit_age;       /* in seconds, how old can an async
+                                                * commit be */
+       __le32 jp_journal_max_trans_age;        /* in seconds, how old can a transaction
+                                                * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+       __le32 s_block_count;   /* blocks count         */
+       __le32 s_free_blocks;   /* free blocks count    */
+       __le32 s_root_block;    /* root block number    */
+       struct journal_params s_journal;
+       __le16 s_blocksize;     /* block size */
+       __le16 s_oid_maxsize;   /* max size of object id array, see
+                                * get_objectid() commentary  */
+       __le16 s_oid_cursize;   /* current size of object id array */
+       __le16 s_umount_state;  /* this is set to 1 when filesystem was
+                                * umounted, to 2 - when not */
+       char s_magic[10];       /* reiserfs magic string indicates that
+                                * file system is reiserfs:
+                                * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+       __le16 s_fs_state;      /* it is set to used by fsck to mark which
+                                * phase of rebuilding is done */
+       __le32 s_hash_function_code;    /* indicate, what hash function is being use
+                                        * to sort names in a directory*/
+       __le16 s_tree_height;   /* height of disk tree */
+       __le16 s_bmap_nr;       /* amount of bitmap blocks needed to address
+                                * each block of file system */
+       __le16 s_version;       /* this field is only reliable on filesystem
+                                * with non-standard journal */
+       __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
+                                        * device, we need to keep after
+                                        * making fs with non-standard journal */
+} __attribute__ ((__packed__));
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+       struct reiserfs_super_block_v1 s_v1;
+       __le32 s_inode_generation;
+       __le32 s_flags;         /* Right now used only by inode-attributes, if enabled */
+       unsigned char s_uuid[16];       /* filesystem unique identifier */
+       unsigned char s_label[16];      /* filesystem volume label */
+       __le16 s_mnt_count;             /* Count of mounts since last fsck */
+       __le16 s_max_mnt_count;         /* Maximum mounts before check */
+       __le32 s_lastcheck;             /* Timestamp of last fsck */
+       __le32 s_check_interval;        /* Interval between checks */
+       char s_unused[76];      /* zero filled by mkreiserfs and
+                                * reiserfs_convert_objectid_map_v1()
+                                * so any additions must be updated
+                                * there as well. */
+} __attribute__ ((__packed__));
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define PUT_SB_BLOCK_COUNT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
+#define PUT_SB_FREE_BLOCKS(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
+#define PUT_SB_ROOT_BLOCK(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
+#define PUT_SB_TREE_HEIGHT(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
+#define PUT_SB_REISERFS_STATE(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
+#define PUT_SB_VERSION(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
+#define PUT_SB_BMAP_NR(s, val) \
+   do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
+         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
+
+int is_reiserfs_3_5(struct reiserfs_super_block *rs);
+int is_reiserfs_3_6(struct reiserfs_super_block *rs);
+int is_reiserfs_jr(struct reiserfs_super_block *rs);
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+   enough space.  If someone wants to write a fancy bootloader that
+   needs more than 64k, let us know, and this will be increased in size.
+   This number must be larger than than the largest block size on any
+   platform, or code will break.  -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+#define REISERFS_FIRST_BLOCK unused_define
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
+
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
+#define CARRY_ON      0
+#define REPEAT_SEARCH -1
+#define IO_ERROR      -2
+#define NO_DISK_SPACE -3
+#define NO_BALANCING_NEEDED  (-4)
+#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
+
+typedef __u32 b_blocknr_t;
+typedef __le32 unp_t;
+
+struct unfm_nodeinfo {
+       unp_t unfm_nodenum;
+       unsigned short unfm_freespace;
+};
+
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
+{
+       return container_of(inode, struct reiserfs_inode_info, vfs_inode);
+}
+
+static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
+/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16
+ * which overflows on large file systems. */
+static inline __u32 reiserfs_bmap_count(struct super_block *sb)
+{
+       return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1;
+}
+
+static inline int bmap_would_wrap(unsigned bmap_nr)
+{
+       return bmap_nr > ((1LL << 16) - 1);
+}
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+   improves our benchmarks. The principle behind it is that percentage
+   space saving is what matters, not absolute space saving.  This is
+   non-intuitive, but it helps to understand it if you consider that the
+   cost to access 4 blocks is not much more than the cost to access 1
+   block, if you have to do a seek and rotate.  A tail risks a
+   non-linear disk access that is significant as a percentage of total
+   time cost for a 4 block file and saves an amount of space that is
+   less significant as a percentage of space, or so goes the hypothesis.
+   -Hans */
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+   ( (n_file_size) >= (n_block_size) * 4 ) || \
+   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+   ( ( (n_file_size) >= (n_block_size) ) && \
+     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
+)
+
+/* Another strategy for tails, this one means only create a tail if all the
+   file would fit into one DIRECT item.
+   Primary intention for this one is to increase performance by decreasing
+   seeking.
+*/
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+/*
+ * values for s_umount_state field
+ */
+#define REISERFS_VALID_FS    1
+#define REISERFS_ERROR_FS    2
+
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15            // FIXME: comment is required
+
+/***************************************************************************/
+/*                       KEY & ITEM HEAD                                   */
+/***************************************************************************/
+
+//
+// directories use this key as well as old files
+//
+struct offset_v1 {
+       __le32 k_offset;
+       __le32 k_uniqueness;
+} __attribute__ ((__packed__));
+
+struct offset_v2 {
+       __le64 v;
+} __attribute__ ((__packed__));
+
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
+{
+       __u8 type = le64_to_cpu(v2->v) >> 60;
+       return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
+}
+
+static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type)
+{
+       v2->v =
+           (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60);
+}
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
+{
+       return le64_to_cpu(v2->v) & (~0ULL >> 4);
+}
+
+static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset)
+{
+       offset &= (~0ULL >> 4);
+       v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset);
+}
+
+/* Key of an item determines its location in the S+tree, and
+   is composed of 4 components */
+struct reiserfs_key {
+       __le32 k_dir_id;        /* packing locality: by default parent
+                                  directory object id */
+       __le32 k_objectid;      /* object identifier */
+       union {
+               struct offset_v1 k_offset_v1;
+               struct offset_v2 k_offset_v2;
+       } __attribute__ ((__packed__)) u;
+} __attribute__ ((__packed__));
+
+struct in_core_key {
+       __u32 k_dir_id;         /* packing locality: by default parent
+                                  directory object id */
+       __u32 k_objectid;       /* object identifier */
+       __u64 k_offset;
+       __u8 k_type;
+};
+
+struct cpu_key {
+       struct in_core_key on_disk_key;
+       int version;
+       int key_length;         /* 3 in all cases but direct2indirect and
+                                  indirect2direct conversion */
+};
+
+/* Our function for comparing keys can compare keys of different
+   lengths.  It takes as a parameter the length of the keys it is to
+   compare.  These defines are used in determining what is to be passed
+   to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN     4
+#define REISERFS_SHORT_KEY_LEN    2
+
+/* The result of the key compare */
+#define FIRST_GREATER 1
+#define SECOND_GREATER -1
+#define KEYS_IDENTICAL 0
+#define KEY_FOUND 1
+#define KEY_NOT_FOUND 0
+
+#define KEY_SIZE (sizeof(struct reiserfs_key))
+#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
+
+/* return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+// return values for reiserfs_find_entry and search_by_entry_key
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/*  Everything in the filesystem is stored as a set of items.  The
+    item head contains the key of the item, its free space (for
+    indirect items) and specifies the location of the item itself
+    within the block.  */
+
+struct item_head {
+       /* Everything in the tree is found by searching for it based on
+        * its key.*/
+       struct reiserfs_key ih_key;
+       union {
+               /* The free space in the last unformatted node of an
+                  indirect item if this is an indirect item.  This
+                  equals 0xFFFF iff this is a direct item or stat data
+                  item. Note that the key, not this field, is used to
+                  determine the item type, and thus which field this
+                  union contains. */
+               __le16 ih_free_space_reserved;
+               /* Iff this is a directory item, this field equals the
+                  number of directory entries in the directory item. */
+               __le16 ih_entry_count;
+       } __attribute__ ((__packed__)) u;
+       __le16 ih_item_len;     /* total size of the item body */
+       __le16 ih_item_location;        /* an offset to the item body
+                                        * within the block */
+       __le16 ih_version;      /* 0 for all old items, 2 for new
+                                  ones. Highest bit is set by fsck
+                                  temporary, cleaned after all
+                                  done */
+} __attribute__ ((__packed__));
+/* size of item header     */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
+#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
+#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
+#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
+#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
+
+#define put_ih_free_space(ih, val)   do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0)
+#define put_ih_version(ih, val)      do { (ih)->ih_version = cpu_to_le16(val); } while (0)
+#define put_ih_entry_count(ih, val)  do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0)
+#define put_ih_location(ih, val)     do { (ih)->ih_item_location = cpu_to_le16(val); } while (0)
+#define put_ih_item_len(ih, val)     do { (ih)->ih_item_len = cpu_to_le16(val); } while (0)
+
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
+
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))
+
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location.  These are a noop on ia32
+** 
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) get_unaligned_le32((p) + (i))
+#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i))
+
+//
+// in old version uniqueness field shows key type
+//
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555  // FIXME: comment is required
+
+//
+// here are conversion routines
+//
+static inline int uniqueness2type(__u32 uniqueness) CONSTF;
+static inline int uniqueness2type(__u32 uniqueness)
+{
+       switch ((int)uniqueness) {
+       case V1_SD_UNIQUENESS:
+               return TYPE_STAT_DATA;
+       case V1_INDIRECT_UNIQUENESS:
+               return TYPE_INDIRECT;
+       case V1_DIRECT_UNIQUENESS:
+               return TYPE_DIRECT;
+       case V1_DIRENTRY_UNIQUENESS:
+               return TYPE_DIRENTRY;
+       case V1_ANY_UNIQUENESS:
+       default:
+               return TYPE_ANY;
+       }
+}
+
+static inline __u32 type2uniqueness(int type) CONSTF;
+static inline __u32 type2uniqueness(int type)
+{
+       switch (type) {
+       case TYPE_STAT_DATA:
+               return V1_SD_UNIQUENESS;
+       case TYPE_INDIRECT:
+               return V1_INDIRECT_UNIQUENESS;
+       case TYPE_DIRECT:
+               return V1_DIRECT_UNIQUENESS;
+       case TYPE_DIRENTRY:
+               return V1_DIRENTRY_UNIQUENESS;
+       case TYPE_ANY:
+       default:
+               return V1_ANY_UNIQUENESS;
+       }
+}
+
+//
+// key is pointer to on disk key which is stored in le, result is cpu,
+// there is no way to get version of object from key, so, provide
+// version to these defines
+//
+static inline loff_t le_key_k_offset(int version,
+                                    const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           le32_to_cpu(key->u.k_offset_v1.k_offset) :
+           offset_v2_k_offset(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
+{
+       return le_key_k_offset(ih_version(ih), &(ih->ih_key));
+}
+
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
+{
+       return (version == KEY_FORMAT_3_5) ?
+           uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+           offset_v2_k_type(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_type(const struct item_head *ih)
+{
+       return le_key_k_type(ih_version(ih), &(ih->ih_key));
+}
+
+static inline void set_le_key_k_offset(int version, struct reiserfs_key *key,
+                                      loff_t offset)
+{
+       (version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) :       /* jdm check */
+           (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
+}
+
+static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset)
+{
+       set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
+}
+
+static inline void set_le_key_k_type(int version, struct reiserfs_key *key,
+                                    int type)
+{
+       (version == KEY_FORMAT_3_5) ?
+           (void)(key->u.k_offset_v1.k_uniqueness =
+                  cpu_to_le32(type2uniqueness(type)))
+           : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type));
+}
+
+static inline void set_le_ih_k_type(struct item_head *ih, int type)
+{
+       set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
+}
+
+static inline int is_direntry_le_key(int version, struct reiserfs_key *key)
+{
+       return le_key_k_type(version, key) == TYPE_DIRENTRY;
+}
+
+static inline int is_direct_le_key(int version, struct reiserfs_key *key)
+{
+       return le_key_k_type(version, key) == TYPE_DIRECT;
+}
+
+static inline int is_indirect_le_key(int version, struct reiserfs_key *key)
+{
+       return le_key_k_type(version, key) == TYPE_INDIRECT;
+}
+
+static inline int is_statdata_le_key(int version, struct reiserfs_key *key)
+{
+       return le_key_k_type(version, key) == TYPE_STAT_DATA;
+}
+
+//
+// item header has version.
+//
+static inline int is_direntry_le_ih(struct item_head *ih)
+{
+       return is_direntry_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_direct_le_ih(struct item_head *ih)
+{
+       return is_direct_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_indirect_le_ih(struct item_head *ih)
+{
+       return is_indirect_le_key(ih_version(ih), &ih->ih_key);
+}
+
+static inline int is_statdata_le_ih(struct item_head *ih)
+{
+       return is_statdata_le_key(ih_version(ih), &ih->ih_key);
+}
+
+//
+// key is pointer to cpu key, result is cpu
+//
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_offset;
+}
+
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
+{
+       return key->on_disk_key.k_type;
+}
+
+static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset)
+{
+       key->on_disk_key.k_offset = offset;
+}
+
+static inline void set_cpu_key_k_type(struct cpu_key *key, int type)
+{
+       key->on_disk_key.k_type = type;
+}
+
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
+{
+       key->on_disk_key.k_offset--;
+}
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* are these used ? */
+#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
+#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
+#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
+#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
+
+#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \
+    (!COMP_SHORT_KEYS(ih, key) && \
+         I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize))
+
+/* maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+extern struct reiserfs_key root_key;
+
+/* 
+ * Picture represents a leaf of the S+tree
+ *  ______________________________________________________
+ * |      |  Array of     |                   |           |
+ * |Block |  Object-Item  |      F r e e      |  Objects- |
+ * | head |  Headers      |     S p a c e     |   Items   |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head {
+       __le16 blk_level;       /* Level of a block in the tree. */
+       __le16 blk_nr_item;     /* Number of keys/items in a block. */
+       __le16 blk_free_space;  /* Block free space in bytes. */
+       __le16 blk_reserved;
+       /* dump this in v4/planA */
+       struct reiserfs_key blk_right_delim_key;        /* kept only for compatibility */
+};
+
+#define BLKH_SIZE                     (sizeof(struct block_head))
+#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
+#define set_blkh_level(p_blkh,val)    ((p_blkh)->blk_level = cpu_to_le16(val))
+#define set_blkh_nr_item(p_blkh,val)  ((p_blkh)->blk_nr_item = cpu_to_le16(val))
+#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val))
+#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val))
+#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
+#define set_blkh_right_delim_key(p_blkh,val)  ((p_blkh)->blk_right_delim_key = val)
+
+/*
+ * values for blk_level field of the struct block_head
+ */
+
+#define FREE_LEVEL 0           /* when node gets removed from the tree its
+                                  blk_level is set to FREE_LEVEL. It is then
+                                  used to see whether the node is still in the
+                                  tree */
+
+#define DISK_LEAF_NODE_LEVEL  1        /* Leaf node level. */
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(bh)                 ((struct block_head *)((bh)->b_data))
+/* Number of items that are in buffer. */
+#define B_NR_ITEMS(bh)                 (blkh_nr_item(B_BLK_HEAD(bh)))
+#define B_LEVEL(bh)                    (blkh_level(B_BLK_HEAD(bh)))
+#define B_FREE_SPACE(bh)               (blkh_free_space(B_BLK_HEAD(bh)))
+
+#define PUT_B_NR_ITEMS(bh, val)                do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_LEVEL(bh, val)           do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0)
+#define PUT_B_FREE_SPACE(bh, val)      do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0)
+
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(bh)         (&(blk_right_delim_key(B_BLK_HEAD(bh))))
+
+/* Does the buffer contain a disk leaf. */
+#define B_IS_ITEMS_LEVEL(bh)           (B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL)
+
+/* Does the buffer contain a disk internal node */
+#define B_IS_KEYS_LEVEL(bh)      (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \
+                                           && B_LEVEL(bh) <= MAX_HEIGHT)
+
+/***************************************************************************/
+/*                             STAT DATA                                   */
+/***************************************************************************/
+
+//
+// old stat data is 32 bytes long. We are going to distinguish new one by
+// different size
+//
+struct stat_data_v1 {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_nlink;        /* number of hard links */
+       __le16 sd_uid;          /* owner */
+       __le16 sd_gid;          /* group */
+       __le32 sd_size;         /* file size */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       union {
+               __le32 sd_rdev;
+               __le32 sd_blocks;       /* number of blocks file uses */
+       } __attribute__ ((__packed__)) u;
+       __le32 sd_first_direct_byte;    /* first byte of file which is stored
+                                          in a direct item: except that if it
+                                          equals 1 it is a symlink and if it
+                                          equals ~(__u32)0 there is no
+                                          direct item.  The existence of this
+                                          field really grates on me. Let's
+                                          replace it with a macro based on
+                                          sd_size and our tail suppression
+                                          policy.  Someday.  -Hans */
+} __attribute__ ((__packed__));
+
+#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+                                (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+   so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
+#define REISERFS_APPEND_FL    FS_APPEND_FL
+#define REISERFS_SYNC_FL      FS_SYNC_FL
+#define REISERFS_NOATIME_FL   FS_NOATIME_FL
+#define REISERFS_NODUMP_FL    FS_NODUMP_FL
+#define REISERFS_SECRM_FL     FS_SECRM_FL
+#define REISERFS_UNRM_FL      FS_UNRM_FL
+#define REISERFS_COMPR_FL     FS_COMPR_FL
+#define REISERFS_NOTAIL_FL    FS_NOTAIL_FL
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |        \
+                               REISERFS_SYNC_FL |      \
+                               REISERFS_NOATIME_FL |   \
+                               REISERFS_NODUMP_FL |    \
+                               REISERFS_SECRM_FL |     \
+                               REISERFS_COMPR_FL |     \
+                               REISERFS_NOTAIL_FL )
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+   address blocks) */
+struct stat_data {
+       __le16 sd_mode;         /* file type, permissions */
+       __le16 sd_attrs;        /* persistent inode flags */
+       __le32 sd_nlink;        /* number of hard links */
+       __le64 sd_size;         /* file size */
+       __le32 sd_uid;          /* owner */
+       __le32 sd_gid;          /* group */
+       __le32 sd_atime;        /* time of last access */
+       __le32 sd_mtime;        /* time file was last modified  */
+       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+       __le32 sd_blocks;
+       union {
+               __le32 sd_rdev;
+               __le32 sd_generation;
+               //__le32 sd_first_direct_byte;
+               /* first byte of file which is stored in a
+                  direct item: except that if it equals 1
+                  it is a symlink and if it equals
+                  ~(__u32)0 there is no direct item.  The
+                  existence of this field really grates
+                  on me. Let's replace it with a macro
+                  based on sd_size and our tail
+                  suppression policy? */
+       } __attribute__ ((__packed__)) u;
+} __attribute__ ((__packed__));
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE              SD_SIZE
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
+
+/***************************************************************************/
+/*                      DIRECTORY STRUCTURE                                */
+/***************************************************************************/
+/* 
+   Picture represents the structure of directory items
+   ________________________________________________
+   |  Array of     |   |     |        |       |   |
+   | directory     |N-1| N-2 | ....   |   1st |0th|
+   | entry headers |   |     |        |       |   |
+   |_______________|___|_____|________|_______|___|
+                    <----   directory entries         ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items.  This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+   Q: How to get key of object pointed to by entry from entry?  
+
+   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
+      of object, entry points to */
+
+/* NOT IMPLEMENTED:   
+   Directory will someday contain stat data of object */
+
+struct reiserfs_de_head {
+       __le32 deh_offset;      /* third component of the directory entry key */
+       __le32 deh_dir_id;      /* objectid of the parent directory of the object, that is referenced
+                                  by directory entry */
+       __le32 deh_objectid;    /* objectid of the object, that is referenced by directory entry */
+       __le16 deh_location;    /* offset of name in the whole item */
+       __le16 deh_state;       /* whether 1) entry contains stat data (for future), and 2) whether
+                                  entry is hidden (unlinked) */
+} __attribute__ ((__packed__));
+#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0         /* not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+#   define ADDR_UNALIGNED_BITS  (3)
+#endif
+
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
+#ifdef ADDR_UNALIGNED_BITS
+
+#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+#   define set_bit_unaligned(nr, addr) \
+       __test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)       \
+       __test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)        \
+       test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+
+#else
+
+#   define set_bit_unaligned(nr, addr) __test_and_set_bit_le(nr, addr)
+#   define clear_bit_unaligned(nr, addr)       __test_and_clear_bit_le(nr, addr)
+#   define test_bit_unaligned(nr, addr)        test_bit_le(nr, addr)
+
+#endif
+
+#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh)       set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh)        clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh)                    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh)                    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh)             !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+                                  __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+                               __le32 par_dirid, __le32 par_objid);
+
+/* array of the entry headers */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+/* length of the directory entry in directory item. This define
+   calculates length of i-th directory entry using directory entry
+   locations from dir entry head. When it calculates length of 0-th
+   directory entry, it uses length of whole item in place of entry
+   location of the non-existent following entry in the calculation.
+   See picture above.*/
+/*
+#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
+*/
+static inline int entry_length(const struct buffer_head *bh,
+                              const struct item_head *ih, int pos_in_item)
+{
+       struct reiserfs_de_head *deh;
+
+       deh = B_I_DEH(bh, ih) + pos_in_item;
+       if (pos_in_item)
+               return deh_location(deh - 1) - deh_location(deh);
+
+       return ih_item_len(ih) - deh_location(deh);
+}
+
+/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* name by bh, ih and entry_num */
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
+
+// two entries per block (at least)
+#define REISERFS_MAX_NAME(block_size) 255
+
+/* this structure is used for operations on directory entries. It is
+   not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+   entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry {
+       struct buffer_head *de_bh;
+       int de_item_num;
+       struct item_head *de_ih;
+       int de_entry_num;
+       struct reiserfs_de_head *de_deh;
+       int de_entrylen;
+       int de_namelen;
+       char *de_name;
+       unsigned long *de_gen_number_bit_string;
+
+       __u32 de_dir_id;
+       __u32 de_objectid;
+
+       struct cpu_key de_entry_key;
+};
+
+/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
+
+/* pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
+
+/* length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
+(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
+
+/* hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER  127
+
+#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ *  ______________________________________________________
+ * |      |  Array of     |  Array of         |  Free     |
+ * |block |    keys       |  pointers         | space     |
+ * | head |      N        |      N+1          |           |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/*                      DISK CHILD                                         */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+   to a node that is on disk. */
+struct disk_child {
+       __le32 dc_block_number; /* Disk child's block number. */
+       __le16 dc_size;         /* Disk child's used space.   */
+       __le16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p)  (le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p)          (le16_to_cpu((dc_p)->dc_size))
+#define put_dc_block_number(dc_p, val)   do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0)
+#define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(bh, n_pos)  ((struct disk_child *)\
+((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos)))
+#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \
+                               (put_dc_block_number(B_N_CHILD(bh, n_pos), val))
+
+ /* maximal value of field child_size in structure disk_child */
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
+
+/***************************************************************************/
+/*                      PATH STRUCTURES AND DEFINES                        */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
+   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
+   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking through an internal node.  If it
+   is looking through a leaf node bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given key. */
+
+struct path_element {
+       struct buffer_head *pe_buffer;  /* Pointer to the buffer at the path in the tree. */
+       int pe_position;        /* Position in the tree node which is placed in the */
+       /* buffer above.                                  */
+};
+
+#define MAX_HEIGHT 5           /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT         7  /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET   2  /* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1  /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6         /* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+/* We need to keep track of who the ancestors of nodes are.  When we
+   perform a search we record which nodes were visited while
+   descending the tree looking for the node we searched for. This list
+   of nodes is called the path.  This information is used while
+   performing balancing.  Note that this path information may become
+   invalid, and this means we must check it when using it to see if it
+   is still valid. You'll need to read search_by_key and the comments
+   in it, especially about decrement_counters_in_path(), to understand
+   this structure.  
+
+Paths make the code so much harder to work with and debug.... An
+enormous number of bugs are due to them, and trying to write or modify
+code that uses them just makes my head hurt.  They are based on an
+excessive effort to avoid disturbing the precious VFS code.:-( The
+gods only know how we are going to SMP the code that uses them.
+znodes are the way! */
+
+#define PATH_READA     0x1     /* do read ahead */
+#define PATH_READA_BACK 0x2    /* read backwards */
+
+struct treepath {
+       int path_length;        /* Length of the array above.   */
+       int reada;
+       struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements.  */
+       int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(path, n_offset)  ((path)->path_elements + (n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(path, n_offset)   (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length))
+                               /* you know, to the person who didn't
+                                  write this the macro name does not
+                                  at first suggest what it does.
+                                  Maybe POSITION_FROM_PATH_END? Or
+                                  maybe we should just focus on
+                                  dumping paths... -Hans */
+#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length))
+
+#define PATH_PITEM_HEAD(path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+   where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h))    /* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)      /* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h))
+
+#define get_last_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+/***************************************************************************/
+/*                       MISC                                              */
+/***************************************************************************/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+// in in-core inode key is stored on le form
+#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT    0x7ffffff
+#define MAX_US_INT 0xffff
+
+// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
+#define U32_MAX (~(__u32)0)
+
+static inline loff_t max_reiserfs_offset(struct inode *inode)
+{
+       if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+               return (loff_t) U32_MAX;
+
+       return (loff_t) ((~(__u64) 0) >> 4);
+}
+
+/*#define MAX_KEY_UNIQUENESS   MAX_UL_INT*/
+#define MAX_KEY_OBJECTID       MAX_UL_INT
+
+#define MAX_B_NUM  MAX_UL_INT
+#define MAX_FC_NUM MAX_US_INT
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
+#define REISERFS_KERNEL_MEM            0       /* reiserfs kernel memory mode  */
+#define REISERFS_USER_MEM              1       /* reiserfs user memory mode            */
+
+#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
+#define get_generation(s) atomic_read (&fs_generation(s))
+#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s)              \
+({                                     \
+       reiserfs_cond_resched(s);       \
+       __fs_changed(gen, s);           \
+})
+
+/***************************************************************************/
+/*                  FIXATE NODES                                           */
+/***************************************************************************/
+
+#define VI_TYPE_LEFT_MERGEABLE 1
+#define VI_TYPE_RIGHT_MERGEABLE 2
+
+/* To make any changes in the tree we always first find node, that
+   contains item to be changed/deleted or place to insert a new
+   item. We call this node S. To do balancing we need to decide what
+   we will shift to left/right neighbor, or to a new node, where new
+   item will be etc. To make this analysis simpler we build virtual
+   node. Virtual node is an array of items, that will replace items of
+   node S. (For instance if we are going to delete an item, virtual
+   node does not contain it). Virtual node keeps information about
+   item sizes and types, mergeability of first and last items, sizes
+   of all entries in directory item. We use this array of items when
+   calculating what we can shift to neighbors and how many nodes we
+   have to have if we do not any shiftings, if we shift to left/right
+   neighbor or to both. */
+struct virtual_item {
+       int vi_index;           // index in the array of item operations
+       unsigned short vi_type; // left/right mergeability
+       unsigned short vi_item_len;     /* length of item that it will have after balancing */
+       struct item_head *vi_ih;
+       const char *vi_item;    // body of item (old or new)
+       const void *vi_new_data;        // 0 always but paste mode
+       void *vi_uarea;         // item specific area
+};
+
+struct virtual_node {
+       char *vn_free_ptr;      /* this is a pointer to the free space in the buffer */
+       unsigned short vn_nr_item;      /* number of items in virtual node */
+       short vn_size;          /* size of node , that node would have if it has unlimited size and no balancing is performed */
+       short vn_mode;          /* mode of balancing (paste, insert, delete, cut) */
+       short vn_affected_item_num;
+       short vn_pos_in_item;
+       struct item_head *vn_ins_ih;    /* item header of inserted item, 0 for other modes */
+       const void *vn_data;
+       struct virtual_item *vn_vi;     /* array of items (including a new one, excluding item to be deleted) */
+};
+
+/* used by directory items when creating virtual nodes */
+struct direntry_uarea {
+       int flags;
+       __u16 entry_count;
+       __u16 entry_sizes[1];
+} __attribute__ ((__packed__));
+
+/***************************************************************************/
+/*                  TREE BALANCE                                           */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+   constructed as we go to the extent that its various parts are
+   needed.  It contains arrays of nodes that can potentially be
+   involved in the balancing of node S, and parameters that define how
+   each of the nodes must be balanced.  Note that in these algorithms
+   for balancing the worst case is to need to balance the current node
+   S and the left and right neighbors and all of their parents plus
+   create a new node.  We implement S1 balancing for the leaf nodes
+   and S0 balancing for the internal nodes (S1 and S0 are defined in
+   our papers.)*/
+
+#define MAX_FREE_BLOCK 7       /* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance {
+       int tb_mode;
+       int need_balance_dirty;
+       struct super_block *tb_sb;
+       struct reiserfs_transaction_handle *transaction_handle;
+       struct treepath *tb_path;
+       struct buffer_head *L[MAX_HEIGHT];      /* array of left neighbors of nodes in the path */
+       struct buffer_head *R[MAX_HEIGHT];      /* array of right neighbors of nodes in the path */
+       struct buffer_head *FL[MAX_HEIGHT];     /* array of fathers of the left  neighbors      */
+       struct buffer_head *FR[MAX_HEIGHT];     /* array of fathers of the right neighbors      */
+       struct buffer_head *CFL[MAX_HEIGHT];    /* array of common parents of center node and its left neighbor  */
+       struct buffer_head *CFR[MAX_HEIGHT];    /* array of common parents of center node and its right neighbor */
+
+       struct buffer_head *FEB[MAX_FEB_SIZE];  /* array of empty buffers. Number of buffers in array equals
+                                                  cur_blknum. */
+       struct buffer_head *used[MAX_FEB_SIZE];
+       struct buffer_head *thrown[MAX_FEB_SIZE];
+       int lnum[MAX_HEIGHT];   /* array of number of items which must be
+                                  shifted to the left in order to balance the
+                                  current node; for leaves includes item that
+                                  will be partially shifted; for internal
+                                  nodes, it is the number of child pointers
+                                  rather than items. It includes the new item
+                                  being created. The code sometimes subtracts
+                                  one to get the number of wholly shifted
+                                  items for other purposes. */
+       int rnum[MAX_HEIGHT];   /* substitute right for left in comment above */
+       int lkey[MAX_HEIGHT];   /* array indexed by height h mapping the key delimiting L[h] and
+                                  S[h] to its item number within the node CFL[h] */
+       int rkey[MAX_HEIGHT];   /* substitute r for l in comment above */
+       int insert_size[MAX_HEIGHT];    /* the number of bytes by we are trying to add or remove from
+                                          S[h]. A negative value means removing.  */
+       int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
+                                  balancing on the level h of the tree.  If 0 then S is
+                                  being deleted, if 1 then S is remaining and no new nodes
+                                  are being created, if 2 or 3 then 1 or 2 new nodes is
+                                  being created */
+
+       /* fields that are used only for balancing leaves of the tree */
+       int cur_blknum;         /* number of empty blocks having been already allocated                 */
+       int s0num;              /* number of items that fall into left most  node when S[0] splits     */
+       int s1num;              /* number of items that fall into first  new node when S[0] splits     */
+       int s2num;              /* number of items that fall into second new node when S[0] splits     */
+       int lbytes;             /* number of bytes which can flow to the left neighbor from the        left    */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted */
+       int rbytes;             /* number of bytes which will flow to the right neighbor from the right        */
+       /* most liquid item that cannot be shifted from S[0] entirely         */
+       /* if -1 then nothing will be partially shifted                           */
+       int s1bytes;            /* number of bytes which flow to the first  new node when S[0] splits   */
+       /* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
+       int s2bytes;
+       struct buffer_head *buf_to_free[MAX_FREE_BLOCK];        /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+       char *vn_buf;           /* kmalloced memory. Used to create
+                                  virtual node and keep map of
+                                  dirtied bitmap blocks */
+       int vn_buf_size;        /* size of the vn_buf */
+       struct virtual_node *tb_vn;     /* VN starts after bitmap of bitmap blocks */
+
+       int fs_gen;             /* saved value of `reiserfs_generation' counter
+                                  see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+       struct in_core_key key; /* key pointer, to pass to block allocator or
+                                  another low-level subsystem */
+#endif
+};
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT       'i'
+/* When inserting into (directories only) or appending onto an already
+   existent item. */
+#define M_PASTE                'p'
+/* When deleting an item. */
+#define M_DELETE       'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT          'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL     'n'
+
+/* When further balancing is not needed, then do_balance does not need
+   to be called. */
+#define M_SKIP_BALANCING               's'
+#define M_CONVERT      'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has
+   been gotten from tb struct */
+struct buffer_info {
+       struct tree_balance *tb;
+       struct buffer_head *bi_bh;
+       struct buffer_head *bi_parent;
+       int bi_position;
+};
+
+static inline struct super_block *sb_from_tb(struct tree_balance *tb)
+{
+       return tb ? tb->tb_sb : NULL;
+}
+
+static inline struct super_block *sb_from_bi(struct buffer_info *bi)
+{
+       return bi ? sb_from_tb(bi->tb) : NULL;
+}
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
++-------------------+------------+--------------+------------+
+|                  |  k_offset  | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+|     stat data     |  0        |      0       |   no       |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
+| non 1st directory | hash value |              |   yes      |
+|     item          |            |              |            |
++-------------------+------------+--------------+------------+
+| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+struct item_operations {
+       int (*bytes_number) (struct item_head * ih, int block_size);
+       void (*decrement_key) (struct cpu_key *);
+       int (*is_left_mergeable) (struct reiserfs_key * ih,
+                                 unsigned long bsize);
+       void (*print_item) (struct item_head *, char *item);
+       void (*check_item) (struct item_head *, char *item);
+
+       int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+                         int is_affected, int insert_size);
+       int (*check_left) (struct virtual_item * vi, int free,
+                          int start_skip, int end_skip);
+       int (*check_right) (struct virtual_item * vi, int free);
+       int (*part_size) (struct virtual_item * vi, int from, int to);
+       int (*unit_num) (struct virtual_item * vi);
+       void (*print_vi) (struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
+#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
+#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
+#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
+#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
+#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
+#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
+#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
+#define op_unit_num(vi)                                     item_ops[(vi)->vi_index]->unit_num (vi)
+#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
+
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(ih) (ih_item_len(ih) / UNFM_P_SIZE)
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
+
+/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
+
+/* get the item header */
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
+
+    /* following defines use reiserfs buffer header and item header */
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
+
+// this is 3976 for size==4096
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+   blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
+
+struct reiserfs_iget_args {
+       __u32 objectid;
+       __u32 dirid;
+};
+
+/***************************************************************************/
+/*                    FUNCTION DECLARATIONS                                */
+/***************************************************************************/
+
+#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
+
+#define journal_trans_half(blocksize) \
+       ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+
+/* journal.c see journal.c for all the comments here */
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+       __le32 j_trans_id;      /* id of commit */
+       __le32 j_len;           /* length of commit. len +1 is the commit block */
+       __le32 j_mount_id;      /* mount id of this trans */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
+#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
+#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
+
+#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
+#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+       __le32 j_trans_id;      /* must match j_trans_id from the desc block */
+       __le32 j_len;           /* ditto */
+       __le32 j_realblock[1];  /* real locations for each block */
+};
+
+#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
+#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
+#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
+
+#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+       __le32 j_last_flush_trans_id;   /* id of last fully flushed transaction */
+       __le32 j_first_unflushed_offset;        /* offset in the log of where to start replay after a crash */
+       __le32 j_mount_id;
+       /* 12 */ struct journal_params jh_journal;
+};
+
+/* biggest tunable defines are right here */
+#define JOURNAL_BLOCK_COUNT 8192       /* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT   900        /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#define JOURNAL_BLOCKS_PER_OBJECT(sb)  (JOURNAL_PER_BALANCE_CNT * 3 + \
+                                        2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \
+                                             REISERFS_QUOTA_TRANS_BLOCKS(sb)))
+
+#ifdef CONFIG_QUOTA
+#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA))
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
+#else
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
+#endif
+
+/* both of these can be as low as 1, or as high as you want.  The min is the
+** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
+** as needed, and released when transactions are committed.  On release, if 
+** the current number of nodes is > max, the node is freed, otherwise, 
+** it is put on a free list for faster use later.
+*/
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
+
+#define JBH_HASH_SHIFT 13      /* these are based on journal hash size of 8192 */
+#define JBH_HASH_MASK 8191
+
+#define _jhashfn(sb,block)     \
+       (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
+        (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
+#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
+
+// We need these to make journal.c code more readable
+#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+
+enum reiserfs_bh_state_bits {
+       BH_JDirty = BH_PrivateStart,    /* buffer is in current transaction */
+       BH_JDirty_wait,
+       BH_JNew,                /* disk block was taken off free list before
+                                * being in a finished transaction, or
+                                * written to disk. Can be reused immed. */
+       BH_JPrepared,
+       BH_JRestore_dirty,
+       BH_JTest,               // debugging only will go away
+};
+
+BUFFER_FNS(JDirty, journaled);
+TAS_BUFFER_FNS(JDirty, journaled);
+BUFFER_FNS(JDirty_wait, journal_dirty);
+TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
+BUFFER_FNS(JNew, journal_new);
+TAS_BUFFER_FNS(JNew, journal_new);
+BUFFER_FNS(JPrepared, journal_prepared);
+TAS_BUFFER_FNS(JPrepared, journal_prepared);
+BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+BUFFER_FNS(JTest, journal_test);
+TAS_BUFFER_FNS(JTest, journal_test);
+
+/*
+** transaction handle which is passed around for all journal calls
+*/
+struct reiserfs_transaction_handle {
+       struct super_block *t_super;    /* super for this FS when journal_begin was
+                                          called. saves calls to reiserfs_get_super
+                                          also used by nested transactions to make
+                                          sure they are nesting on the right FS
+                                          _must_ be first in the handle
+                                        */
+       int t_refcount;
+       int t_blocks_logged;    /* number of blocks this writer has logged */
+       int t_blocks_allocated; /* number of blocks this writer allocated */
+       unsigned int t_trans_id;        /* sanity check, equals the current trans id */
+       void *t_handle_save;    /* save existing current->journal_info */
+       unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
+                                          should be displaced from others */
+       struct list_head t_list;
+};
+
+/* used to keep track of ordered and tail writes, attached to the buffer
+ * head through b_journal_head.
+ */
+struct reiserfs_jh {
+       struct reiserfs_journal_list *jl;
+       struct buffer_head *bh;
+       struct list_head list;
+};
+
+void reiserfs_free_jh(struct buffer_head *bh);
+int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
+int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
+int journal_mark_dirty(struct reiserfs_transaction_handle *,
+                      struct super_block *, struct buffer_head *bh);
+
+static inline int reiserfs_file_data_log(struct inode *inode)
+{
+       if (reiserfs_data_log(inode->i_sb) ||
+           (REISERFS_I(inode)->i_flags & i_data_log))
+               return 1;
+       return 0;
+}
+
+static inline int reiserfs_transaction_running(struct super_block *s)
+{
+       struct reiserfs_transaction_handle *th = current->journal_info;
+       if (th && th->t_super == s)
+               return 1;
+       if (th && th->t_super == NULL)
+               BUG();
+       return 0;
+}
+
+static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th)
+{
+       return th->t_blocks_allocated - th->t_blocks_logged;
+}
+
+struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
+                                                                   super_block
+                                                                   *,
+                                                                   int count);
+int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
+int reiserfs_commit_page(struct inode *inode, struct page *page,
+                        unsigned from, unsigned to);
+int reiserfs_flush_old_commits(struct super_block *);
+int reiserfs_commit_for_inode(struct inode *);
+int reiserfs_inode_needs_commit(struct inode *);
+void reiserfs_update_inode_transaction(struct inode *);
+void reiserfs_wait_on_write_block(struct super_block *s);
+void reiserfs_block_writes(struct reiserfs_transaction_handle *th);
+void reiserfs_allow_writes(struct super_block *s);
+void reiserfs_check_lock_depth(struct super_block *s, char *caller);
+int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh,
+                                int wait);
+void reiserfs_restore_prepared_buffer(struct super_block *,
+                                     struct buffer_head *bh);
+int journal_init(struct super_block *, const char *j_dev_name, int old_format,
+                unsigned int);
+int journal_release(struct reiserfs_transaction_handle *, struct super_block *);
+int journal_release_error(struct reiserfs_transaction_handle *,
+                         struct super_block *);
+int journal_end(struct reiserfs_transaction_handle *, struct super_block *,
+               unsigned long);
+int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
+                    unsigned long);
+int journal_mark_freed(struct reiserfs_transaction_handle *,
+                      struct super_block *, b_blocknr_t blocknr);
+int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
+int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr,
+                        int bit_nr, int searchall, b_blocknr_t *next);
+int journal_begin(struct reiserfs_transaction_handle *,
+                 struct super_block *sb, unsigned long);
+int journal_join_abort(struct reiserfs_transaction_handle *,
+                      struct super_block *sb, unsigned long);
+void reiserfs_abort_journal(struct super_block *sb, int errno);
+void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
+int reiserfs_allocate_list_bitmaps(struct super_block *s,
+                                  struct reiserfs_list_bitmap *, unsigned int);
+
+void add_save_link(struct reiserfs_transaction_handle *th,
+                  struct inode *inode, int truncate);
+int remove_save_link(struct inode *inode, int truncate);
+
+/* objectid.c */
+__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th);
+void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
+                              __u32 objectid_to_release);
+int reiserfs_convert_objectid_map_v1(struct super_block *);
+
+/* stree.c */
+int B_IS_IN_TREE(const struct buffer_head *);
+extern void copy_item_head(struct item_head *to,
+                          const struct item_head *from);
+
+// first key is in cpu form, second - le
+extern int comp_short_keys(const struct reiserfs_key *le_key,
+                          const struct cpu_key *cpu_key);
+extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from);
+
+// both are in le form
+extern int comp_le_keys(const struct reiserfs_key *,
+                       const struct reiserfs_key *);
+extern int comp_short_le_keys(const struct reiserfs_key *,
+                             const struct reiserfs_key *);
+
+//
+// get key version from on disk key - kludge
+//
+static inline int le_key_version(const struct reiserfs_key *key)
+{
+       int type;
+
+       type = offset_v2_k_type(&(key->u.k_offset_v2));
+       if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+           && type != TYPE_DIRENTRY)
+               return KEY_FORMAT_3_5;
+
+       return KEY_FORMAT_3_6;
+
+}
+
+static inline void copy_key(struct reiserfs_key *to,
+                           const struct reiserfs_key *from)
+{
+       memcpy(to, from, KEY_SIZE);
+}
+
+int comp_items(const struct item_head *stored_ih, const struct treepath *path);
+const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
+                                   const struct super_block *sb);
+int search_by_key(struct super_block *, const struct cpu_key *,
+                 struct treepath *, int);
+#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
+int search_for_position_by_key(struct super_block *sb,
+                              const struct cpu_key *cpu_key,
+                              struct treepath *search_path);
+extern void decrement_bcount(struct buffer_head *bh);
+void decrement_counters_in_path(struct treepath *search_path);
+void pathrelse(struct treepath *search_path);
+int reiserfs_check_path(struct treepath *p);
+void pathrelse_and_restore(struct super_block *s, struct treepath *search_path);
+
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
+                        struct treepath *path,
+                        const struct cpu_key *key,
+                        struct item_head *ih,
+                        struct inode *inode, const char *body);
+
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
+                            struct treepath *path,
+                            const struct cpu_key *key,
+                            struct inode *inode,
+                            const char *body, int paste_size);
+
+int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
+                          struct treepath *path,
+                          struct cpu_key *key,
+                          struct inode *inode,
+                          struct page *page, loff_t new_file_size);
+
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
+                        struct treepath *path,
+                        const struct cpu_key *key,
+                        struct inode *inode, struct buffer_head *un_bh);
+
+void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
+                               struct inode *inode, struct reiserfs_key *key);
+int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
+                          struct inode *inode);
+int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
+                        struct inode *inode, struct page *,
+                        int update_timestamps);
+
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
+
+void padd_item(char *item, int total_length, int length);
+
+/* inode.c */
+/* args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0  /* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1     /* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2    /* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4        /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_IMUX     8        /* i_mutex is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE   16       /* don't leave any transactions running */
+
+void reiserfs_read_locked_inode(struct inode *inode,
+                               struct reiserfs_iget_args *args);
+int reiserfs_find_actor(struct inode *inode, void *p);
+int reiserfs_init_locked_inode(struct inode *inode, void *p);
+void reiserfs_evict_inode(struct inode *inode);
+int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc);
+int reiserfs_get_block(struct inode *inode, sector_t block,
+                      struct buffer_head *bh_result, int create);
+struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+                                    int fh_len, int fh_type);
+struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
+                                    int fh_len, int fh_type);
+int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
+                      int connectable);
+
+int reiserfs_truncate_file(struct inode *, int update_timestamps);
+void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
+                 int type, int key_length);
+void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
+                      int version,
+                      loff_t offset, int type, int length, int entry_count);
+struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
+
+struct reiserfs_security_handle;
+int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
+                      struct inode *dir, umode_t mode,
+                      const char *symname, loff_t i_size,
+                      struct dentry *dentry, struct inode *inode,
+                      struct reiserfs_security_handle *security);
+
+void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
+                            struct inode *inode, loff_t size);
+
+static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
+                                     struct inode *inode)
+{
+       reiserfs_update_sd_size(th, inode, inode->i_size);
+}
+
+void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
+void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
+int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
+
+int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
+
+/* namei.c */
+void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
+int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
+                       struct treepath *path, struct reiserfs_dir_entry *de);
+struct dentry *reiserfs_get_parent(struct dentry *);
+
+#ifdef CONFIG_REISERFS_PROC_INFO
+int reiserfs_proc_info_init(struct super_block *sb);
+int reiserfs_proc_info_done(struct super_block *sb);
+int reiserfs_proc_info_global_init(void);
+int reiserfs_proc_info_global_done(void);
+
+#define PROC_EXP( e )   e
+
+#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data
+#define PROC_INFO_MAX( sb, field, value )                                                              \
+    __PINFO( sb ).field =                                                                                              \
+        max( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
+#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
+#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
+#define PROC_INFO_BH_STAT( sb, bh, level )                                                     \
+    PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] );                                             \
+    PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );     \
+    PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
+#else
+static inline int reiserfs_proc_info_init(struct super_block *sb)
+{
+       return 0;
+}
+
+static inline int reiserfs_proc_info_done(struct super_block *sb)
+{
+       return 0;
+}
+
+static inline int reiserfs_proc_info_global_init(void)
+{
+       return 0;
+}
+
+static inline int reiserfs_proc_info_global_done(void)
+{
+       return 0;
+}
+
+#define PROC_EXP( e )
+#define VOID_V ( ( void ) 0 )
+#define PROC_INFO_MAX( sb, field, value ) VOID_V
+#define PROC_INFO_INC( sb, field ) VOID_V
+#define PROC_INFO_ADD( sb, field, val ) VOID_V
+#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V
+#endif
+
+/* dir.c */
+extern const struct inode_operations reiserfs_dir_inode_operations;
+extern const struct inode_operations reiserfs_symlink_inode_operations;
+extern const struct inode_operations reiserfs_special_inode_operations;
+extern const struct file_operations reiserfs_dir_operations;
+int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
+
+/* tail_conversion.c */
+int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
+                   struct treepath *, struct buffer_head *, loff_t);
+int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
+                   struct page *, struct treepath *, const struct cpu_key *,
+                   loff_t, char *);
+void reiserfs_unmap_buffer(struct buffer_head *);
+
+/* file.c */
+extern const struct inode_operations reiserfs_file_inode_operations;
+extern const struct file_operations reiserfs_file_operations;
+extern const struct address_space_operations reiserfs_address_space_operations;
+
+/* fix_nodes.c */
+
+int fix_nodes(int n_op_mode, struct tree_balance *tb,
+             struct item_head *ins_ih, const void *);
+void unfix_nodes(struct tree_balance *);
+
+/* prints.c */
+void __reiserfs_panic(struct super_block *s, const char *id,
+                     const char *function, const char *fmt, ...)
+    __attribute__ ((noreturn));
+#define reiserfs_panic(s, id, fmt, args...) \
+       __reiserfs_panic(s, id, __func__, fmt, ##args)
+void __reiserfs_error(struct super_block *s, const char *id,
+                     const char *function, const char *fmt, ...);
+#define reiserfs_error(s, id, fmt, args...) \
+        __reiserfs_error(s, id, __func__, fmt, ##args)
+void reiserfs_info(struct super_block *s, const char *fmt, ...);
+void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
+void print_indirect_item(struct buffer_head *bh, int item_num);
+void store_print_tb(struct tree_balance *tb);
+void print_cur_tb(char *mes);
+void print_de(struct reiserfs_dir_entry *de);
+void print_bi(struct buffer_info *bi, char *mes);
+#define PRINT_LEAF_ITEMS 1     /* print all items */
+#define PRINT_DIRECTORY_ITEMS 2        /* print directory items */
+#define PRINT_DIRECT_ITEMS 4   /* print contents of direct items */
+void print_block(struct buffer_head *bh, ...);
+void print_bmap(struct super_block *s, int silent);
+void print_bmap_block(int i, char *data, int size, int silent);
+/*void print_super_block (struct super_block * s, char * mes);*/
+void print_objectid_map(struct super_block *s);
+void print_block_head(struct buffer_head *bh, char *mes);
+void check_leaf(struct buffer_head *bh);
+void check_internal(struct buffer_head *bh);
+void print_statistics(struct super_block *s);
+char *reiserfs_hashname(int code);
+
+/* lbalance.c */
+int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
+                   int mov_bytes, struct buffer_head *Snew);
+int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes);
+int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
+void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
+                      int del_num, int del_bytes);
+void leaf_insert_into_buf(struct buffer_info *bi, int before,
+                         struct item_head *inserted_item_ih,
+                         const char *inserted_item_body, int zeros_number);
+void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
+                         int pos_in_item, int paste_size, const char *body,
+                         int zeros_number);
+void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
+                         int pos_in_item, int cut_size);
+void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
+                       int new_entry_count, struct reiserfs_de_head *new_dehs,
+                       const char *records, int paste_size);
+/* ibalance.c */
+int balance_internal(struct tree_balance *, int, int, struct item_head *,
+                    struct buffer_head **);
+
+/* do_balance.c */
+void do_balance_mark_leaf_dirty(struct tree_balance *tb,
+                               struct buffer_head *bh, int flag);
+#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
+#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
+
+void do_balance(struct tree_balance *tb, struct item_head *ih,
+               const char *body, int flag);
+void reiserfs_invalidate_buffer(struct tree_balance *tb,
+                               struct buffer_head *bh);
+
+int get_left_neighbor_position(struct tree_balance *tb, int h);
+int get_right_neighbor_position(struct tree_balance *tb, int h);
+void replace_key(struct tree_balance *tb, struct buffer_head *, int,
+                struct buffer_head *, int);
+void make_empty_node(struct buffer_info *);
+struct buffer_head *get_FEB(struct tree_balance *);
+
+/* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+struct __reiserfs_blocknr_hint {
+       struct inode *inode;    /* inode passed to allocator, if we allocate unf. nodes */
+       sector_t block;         /* file offset, in blocks */
+       struct in_core_key key;
+       struct treepath *path;  /* search path, used by allocator to deternine search_start by
+                                * various ways */
+       struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
+                                                * bitmap blocks changes  */
+       b_blocknr_t beg, end;
+       b_blocknr_t search_start;       /* a field used to transfer search start value (block number)
+                                        * between different block allocator procedures
+                                        * (determine_search_start() and others) */
+       int prealloc_size;      /* is set in determine_prealloc_size() function, used by underlayed
+                                * function that do actual allocation */
+
+       unsigned formatted_node:1;      /* the allocator uses different polices for getting disk space for
+                                        * formatted/unformatted blocks with/without preallocation */
+       unsigned preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+int reiserfs_parse_alloc_options(struct super_block *, char *);
+void reiserfs_init_alloc_options(struct super_block *s);
+
+/*
+ * given a directory, this will tell you what packing locality
+ * to use for a new object underneat it.  The locality is returned
+ * in disk byte order (le).
+ */
+__le32 reiserfs_choose_packing(struct inode *dir);
+
+int reiserfs_init_bitmap_cache(struct super_block *sb);
+void reiserfs_free_bitmap_cache(struct super_block *sb);
+void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
+int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
+void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
+                        b_blocknr_t, int for_unformatted);
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int,
+                              int);
+static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
+                                            b_blocknr_t * new_blocknrs,
+                                            int amount_needed)
+{
+       reiserfs_blocknr_hint_t hint = {
+               .th = tb->transaction_handle,
+               .path = tb->tb_path,
+               .inode = NULL,
+               .key = tb->key,
+               .block = 0,
+               .formatted_node = 1
+       };
+       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed,
+                                         0);
+}
+
+static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
+                                           *th, struct inode *inode,
+                                           b_blocknr_t * new_blocknrs,
+                                           struct treepath *path,
+                                           sector_t block)
+{
+       reiserfs_blocknr_hint_t hint = {
+               .th = th,
+               .path = path,
+               .inode = inode,
+               .block = block,
+               .formatted_node = 0,
+               .preallocate = 0
+       };
+       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
+#ifdef REISERFS_PREALLOCATE
+static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
+                                            *th, struct inode *inode,
+                                            b_blocknr_t * new_blocknrs,
+                                            struct treepath *path,
+                                            sector_t block)
+{
+       reiserfs_blocknr_hint_t hint = {
+               .th = th,
+               .path = path,
+               .inode = inode,
+               .block = block,
+               .formatted_node = 0,
+               .preallocate = 1
+       };
+       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+}
+
+void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
+                              struct inode *inode);
+void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th);
+#endif
+
+/* hashes.c */
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
+
+#define reiserfs_set_le_bit            __set_bit_le
+#define reiserfs_test_and_set_le_bit   __test_and_set_bit_le
+#define reiserfs_clear_le_bit          __clear_bit_le
+#define reiserfs_test_and_clear_le_bit __test_and_clear_bit_le
+#define reiserfs_test_le_bit           test_bit_le
+#define reiserfs_find_next_zero_le_bit find_next_zero_bit_le
+
+/* sometimes reiserfs_truncate may require to allocate few new blocks
+   to perform indirect2direct conversion. People probably used to
+   think, that truncate should work without problems on a filesystem
+   without free disk space. They may complain that they can not
+   truncate due to lack of free disk space. This spare space allows us
+   to not worry about it. 500 is probably too much, but it should be
+   absolutely safe */
+#define SPARE_SPACE 500
+
+/* prototypes from ioctl.c */
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+long reiserfs_compat_ioctl(struct file *filp,
+                  unsigned int cmd, unsigned long arg);
+int reiserfs_unpack(struct inode *inode, struct file *filp);
index 7483279..9a17f63 100644 (file)
@@ -13,8 +13,7 @@
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_fs_sb.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 
 int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
index 77df82f..f8afa4b 100644 (file)
@@ -51,7 +51,7 @@
 #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/buffer_head.h>
 #include <linux/quotaops.h>
 
index e12d8b9..8b7616e 100644 (file)
@@ -16,9 +16,9 @@
 #include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <asm/uaccess.h>
-#include <linux/reiserfs_fs.h>
-#include <linux/reiserfs_acl.h>
-#include <linux/reiserfs_xattr.h>
+#include "reiserfs.h"
+#include "acl.h"
+#include "xattr.h"
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
@@ -1874,11 +1874,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                unlock_new_inode(root_inode);
        }
 
-       s->s_root = d_alloc_root(root_inode);
-       if (!s->s_root) {
-               iput(root_inode);
+       s->s_root = d_make_root(root_inode);
+       if (!s->s_root)
                goto error;
-       }
        // define and initialize hash function
        sbi->s_hash_function = hash_function(s);
        if (sbi->s_hash_function == NULL) {
index 8f546bd..5e2624d 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/time.h>
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 
 /* access to tail : when one is going to read tail it must make sure, that is not running.
  direct2indirect and indirect2direct can not run concurrently */
index c24deda..46fc1c2 100644 (file)
@@ -33,7 +33,7 @@
  * The xattrs themselves are protected by the xattr_sem.
  */
 
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/capability.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
@@ -43,8 +43,8 @@
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
-#include <linux/reiserfs_acl.h>
+#include "xattr.h"
+#include "acl.h"
 #include <asm/uaccess.h>
 #include <net/checksum.h>
 #include <linux/stat.h>
diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h
new file mode 100644 (file)
index 0000000..f59626c
--- /dev/null
@@ -0,0 +1,122 @@
+#include <linux/reiserfs_xattr.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/rwsem.h>
+
+struct inode;
+struct dentry;
+struct iattr;
+struct super_block;
+struct nameidata;
+
+int reiserfs_xattr_register_handlers(void) __init;
+void reiserfs_xattr_unregister_handlers(void);
+int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
+int reiserfs_lookup_privroot(struct super_block *sb);
+int reiserfs_delete_xattrs(struct inode *inode);
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
+int reiserfs_permission(struct inode *inode, int mask);
+
+#ifdef CONFIG_REISERFS_FS_XATTR
+#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
+ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
+                         void *buffer, size_t size);
+int reiserfs_setxattr(struct dentry *dentry, const char *name,
+                     const void *value, size_t size, int flags);
+ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int reiserfs_removexattr(struct dentry *dentry, const char *name);
+
+int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
+int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
+int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
+                             struct inode *, const char *, const void *,
+                             size_t, int);
+
+extern const struct xattr_handler reiserfs_xattr_user_handler;
+extern const struct xattr_handler reiserfs_xattr_trusted_handler;
+extern const struct xattr_handler reiserfs_xattr_security_handler;
+#ifdef CONFIG_REISERFS_FS_SECURITY
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+                          const struct qstr *qstr,
+                          struct reiserfs_security_handle *sec);
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                           struct inode *inode,
+                           struct reiserfs_security_handle *sec);
+void reiserfs_security_free(struct reiserfs_security_handle *sec);
+#endif
+
+static inline int reiserfs_xattrs_initialized(struct super_block *sb)
+{
+       return REISERFS_SB(sb)->priv_root != NULL;
+}
+
+#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
+static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
+{
+       loff_t ret = 0;
+       if (reiserfs_file_data_log(inode)) {
+               ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize);
+               ret >>= inode->i_sb->s_blocksize_bits;
+       }
+       return ret;
+}
+
+/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file.
+ * Let's try to be smart about it.
+ * xattr root: We cache it. If it's not cached, we may need to create it.
+ * xattr dir: If anything has been loaded for this inode, we can set a flag
+ *            saying so.
+ * xattr file: Since we don't cache xattrs, we can't tell. We always include
+ *             blocks for it.
+ *
+ * However, since root and dir can be created between calls - YOU MUST SAVE
+ * THIS VALUE.
+ */
+static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode)
+{
+       size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+
+       if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) {
+               nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+               if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode)
+                       nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+       }
+
+       return nblocks;
+}
+
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+       init_rwsem(&REISERFS_I(inode)->i_xattr_sem);
+}
+
+#else
+
+#define reiserfs_getxattr NULL
+#define reiserfs_setxattr NULL
+#define reiserfs_listxattr NULL
+#define reiserfs_removexattr NULL
+
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+}
+#endif  /*  CONFIG_REISERFS_FS_XATTR  */
+
+#ifndef CONFIG_REISERFS_FS_SECURITY
+static inline int reiserfs_security_init(struct inode *dir,
+                                        struct inode *inode,
+                                        const struct qstr *qstr,
+                                        struct reiserfs_security_handle *sec)
+{
+       return 0;
+}
+static inline int
+reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                       struct inode *inode,
+                       struct reiserfs_security_handle *sec)
+{
+       return 0;
+}
+static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{}
+#endif
index 6da0396..44474f9 100644 (file)
@@ -1,14 +1,14 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/posix_acl.h>
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/slab.h>
 #include <linux/posix_acl_xattr.h>
-#include <linux/reiserfs_xattr.h>
-#include <linux/reiserfs_acl.h>
+#include "xattr.h"
+#include "acl.h"
 #include <asm/uaccess.h>
 
 static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
index 534668f..800a3ce 100644 (file)
@@ -1,10 +1,10 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/slab.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <linux/security.h>
 #include <asm/uaccess.h>
 
index 9883736..a003571 100644 (file)
@@ -1,10 +1,10 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <asm/uaccess.h>
 
 static int
index 45ae1a0..8667491 100644 (file)
@@ -1,9 +1,9 @@
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
+#include "xattr.h"
 #include <asm/uaccess.h>
 
 static int
index bb36ab7..e64f6b5 100644 (file)
@@ -538,14 +538,12 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent)
        if (IS_ERR(root))
                goto error;
 
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root)
-               goto error_i;
+               goto error;
 
        return 0;
 
-error_i:
-       iput(root);
 error:
        return -EINVAL;
 error_rsb_inval:
index ecaa2f7..970b116 100644 (file)
@@ -316,11 +316,10 @@ check_directory_table:
        }
        insert_inode_hash(root);
 
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (sb->s_root == NULL) {
                ERROR("Root inode create failed\n");
                err = -ENOMEM;
-               iput(root);
                goto failed_mount;
        }
 
index 8806b89..86f1356 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -307,7 +307,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
                if (inode->i_op->readlink) {
                        error = security_inode_readlink(path.dentry);
                        if (!error) {
-                               touch_atime(path.mnt, path.dentry);
+                               touch_atime(&path);
                                error = inode->i_op->readlink(path.dentry,
                                                              buf, bufsiz);
                        }
index 6277ec6..d90e900 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/backing-dev.h>
 #include <linux/rculist_bl.h>
 #include <linux/cleancache.h>
+#include <linux/fsnotify.h>
 #include "internal.h"
 
 
index 140f26a..52c3bdb 100644 (file)
@@ -61,10 +61,9 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* instantiate and link root dentry */
-       root = d_alloc_root(inode);
+       root = d_make_root(inode);
        if (!root) {
                pr_debug("%s: could not get root dentry!\n",__func__);
-               iput(inode);
                return -ENOMEM;
        }
        root->d_fsdata = &sysfs_root;
index b217797..d7466e2 100644 (file)
@@ -121,9 +121,6 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
 {
        struct inode *inode = old_dentry->d_inode;
 
-       if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max)
-               return -EMLINK;
-
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
        ihold(inode);
@@ -134,10 +131,8 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir,
 static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 {
        struct inode * inode;
-       int err = -EMLINK;
+       int err;
 
-       if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max) 
-               goto out;
        inode_inc_link_count(dir);
 
        inode = sysv_new_inode(dir, S_IFDIR|mode);
@@ -251,11 +246,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
                        drop_nlink(new_inode);
                inode_dec_link_count(new_inode);
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
-                               goto out_dir;
-               }
                err = sysv_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index f60c196..7491c33 100644 (file)
@@ -44,7 +44,7 @@ enum {
        JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60
 };
 
-static void detected_xenix(struct sysv_sb_info *sbi)
+static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links)
 {
        struct buffer_head *bh1 = sbi->s_bh1;
        struct buffer_head *bh2 = sbi->s_bh2;
@@ -59,7 +59,7 @@ static void detected_xenix(struct sysv_sb_info *sbi)
                sbd2 = (struct xenix_super_block *) (bh2->b_data - 512);
        }
 
-       sbi->s_link_max = XENIX_LINK_MAX;
+       *max_links = XENIX_LINK_MAX;
        sbi->s_fic_size = XENIX_NICINOD;
        sbi->s_flc_size = XENIX_NICFREE;
        sbi->s_sbd1 = (char *)sbd1;
@@ -75,7 +75,7 @@ static void detected_xenix(struct sysv_sb_info *sbi)
        sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize);
 }
 
-static void detected_sysv4(struct sysv_sb_info *sbi)
+static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links)
 {
        struct sysv4_super_block * sbd;
        struct buffer_head *bh1 = sbi->s_bh1;
@@ -86,7 +86,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi)
        else
                sbd = (struct sysv4_super_block *) bh2->b_data;
 
-       sbi->s_link_max = SYSV_LINK_MAX;
+       *max_links = SYSV_LINK_MAX;
        sbi->s_fic_size = SYSV_NICINOD;
        sbi->s_flc_size = SYSV_NICFREE;
        sbi->s_sbd1 = (char *)sbd;
@@ -103,7 +103,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi)
        sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_sysv2(struct sysv_sb_info *sbi)
+static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links)
 {
        struct sysv2_super_block *sbd;
        struct buffer_head *bh1 = sbi->s_bh1;
@@ -114,7 +114,7 @@ static void detected_sysv2(struct sysv_sb_info *sbi)
        else
                sbd = (struct sysv2_super_block *) bh2->b_data;
 
-       sbi->s_link_max = SYSV_LINK_MAX;
+       *max_links = SYSV_LINK_MAX;
        sbi->s_fic_size = SYSV_NICINOD;
        sbi->s_flc_size = SYSV_NICFREE;
        sbi->s_sbd1 = (char *)sbd;
@@ -131,14 +131,14 @@ static void detected_sysv2(struct sysv_sb_info *sbi)
        sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_coherent(struct sysv_sb_info *sbi)
+static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links)
 {
        struct coh_super_block * sbd;
        struct buffer_head *bh1 = sbi->s_bh1;
 
        sbd = (struct coh_super_block *) bh1->b_data;
 
-       sbi->s_link_max = COH_LINK_MAX;
+       *max_links = COH_LINK_MAX;
        sbi->s_fic_size = COH_NICINOD;
        sbi->s_flc_size = COH_NICFREE;
        sbi->s_sbd1 = (char *)sbd;
@@ -154,12 +154,12 @@ static void detected_coherent(struct sysv_sb_info *sbi)
        sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_v7(struct sysv_sb_info *sbi)
+static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links)
 {
        struct buffer_head *bh2 = sbi->s_bh2;
        struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data;
 
-       sbi->s_link_max = V7_LINK_MAX;
+       *max_links = V7_LINK_MAX;
        sbi->s_fic_size = V7_NICINOD;
        sbi->s_flc_size = V7_NICFREE;
        sbi->s_sbd1 = (char *)sbd;
@@ -290,7 +290,7 @@ static char *flavour_names[] = {
        [FSTYPE_AFS]    = "AFS",
 };
 
-static void (*flavour_setup[])(struct sysv_sb_info *) = {
+static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = {
        [FSTYPE_XENIX]  = detected_xenix,
        [FSTYPE_SYSV4]  = detected_sysv4,
        [FSTYPE_SYSV2]  = detected_sysv2,
@@ -310,7 +310,7 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
 
        sbi->s_firstinodezone = 2;
 
-       flavour_setup[sbi->s_type](sbi);
+       flavour_setup[sbi->s_type](sbi, &sb->s_max_links);
        
        sbi->s_truncate = 1;
        sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;
@@ -341,9 +341,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
                printk("SysV FS: get root inode failed\n");
                return 0;
        }
-       sb->s_root = d_alloc_root(root_inode);
+       sb->s_root = d_make_root(root_inode);
        if (!sb->s_root) {
-               iput(root_inode);
                printk("SysV FS: get root dentry failed\n");
                return 0;
        }
index 0e4b821..11b0767 100644 (file)
@@ -24,7 +24,6 @@ struct sysv_sb_info {
        char           s_bytesex;       /* bytesex (le/be/pdp) */
        char           s_truncate;      /* if 1: names > SYSV_NAMELEN chars are truncated */
                                        /* if 0: they are disallowed (ENAMETOOLONG) */
-       nlink_t        s_link_max;      /* max number of hard links to a file */
        unsigned int   s_inodes_per_block;      /* number of inodes per block */
        unsigned int   s_inodes_per_block_1;    /* inodes_per_block - 1 */
        unsigned int   s_inodes_per_block_bits; /* log2(inodes_per_block) */
index 63765d5..76e4e05 100644 (file)
@@ -2076,15 +2076,13 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
                goto out_umount;
        }
 
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root)
-               goto out_iput;
+               goto out_umount;
 
        mutex_unlock(&c->umount_mutex);
        return 0;
 
-out_iput:
-       iput(root);
 out_umount:
        ubifs_umount(c);
 out_unlock:
index 08bf46e..38de8f2 100644 (file)
@@ -32,8 +32,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/exportfs.h>
 
-enum { UDF_MAX_LINKS = 0xffff };
-
 static inline int udf_match(int len1, const unsigned char *name1, int len2,
                            const unsigned char *name2)
 {
@@ -649,10 +647,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct udf_inode_info *dinfo = UDF_I(dir);
        struct udf_inode_info *iinfo;
 
-       err = -EMLINK;
-       if (dir->i_nlink >= UDF_MAX_LINKS)
-               goto out;
-
        err = -EIO;
        inode = udf_new_inode(dir, S_IFDIR | mode, &err);
        if (!inode)
@@ -1032,9 +1026,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        struct fileIdentDesc cfi, *fi;
        int err;
 
-       if (inode->i_nlink >= UDF_MAX_LINKS)
-               return -EMLINK;
-
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi) {
                return err;
@@ -1126,10 +1117,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
                                old_dir->i_ino)
                        goto end_rename;
-
-               retval = -EMLINK;
-               if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS)
-                       goto end_rename;
        }
        if (!nfi) {
                nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
index c09a84d..85067b4 100644 (file)
@@ -75,6 +75,8 @@
 
 #define UDF_DEFAULT_BLOCKSIZE 2048
 
+enum { UDF_MAX_LINKS = 0xffff };
+
 /* These are the "meat" - everything else is stuffing */
 static int udf_fill_super(struct super_block *, void *, int);
 static void udf_put_super(struct super_block *);
@@ -2035,13 +2037,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        }
 
        /* Allocate a dentry for the root inode */
-       sb->s_root = d_alloc_root(inode);
+       sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                udf_err(sb, "Couldn't allocate root dentry\n");
-               iput(inode);
                goto error_out;
        }
        sb->s_maxbytes = MAX_LFS_FILESIZE;
+       sb->s_max_links = UDF_MAX_LINKS;
        return 0;
 
 error_out:
index 38cac19..a2281ca 100644 (file)
@@ -166,10 +166,6 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
        int error;
 
        lock_ufs(dir->i_sb);
-       if (inode->i_nlink >= UFS_LINK_MAX) {
-               unlock_ufs(dir->i_sb);
-               return -EMLINK;
-       }
 
        inode->i_ctime = CURRENT_TIME_SEC;
        inode_inc_link_count(inode);
@@ -183,10 +179,7 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir,
 static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
        struct inode * inode;
-       int err = -EMLINK;
-
-       if (dir->i_nlink >= UFS_LINK_MAX)
-               goto out;
+       int err;
 
        lock_ufs(dir->i_sb);
        inode_inc_link_count(dir);
@@ -305,11 +298,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        drop_nlink(new_inode);
                inode_dec_link_count(new_inode);
        } else {
-               if (dir_de) {
-                       err = -EMLINK;
-                       if (new_dir->i_nlink >= UFS_LINK_MAX)
-                               goto out_dir;
-               }
                err = ufs_add_link(new_dentry, old_inode);
                if (err)
                        goto out_dir;
index 5246ee3..f636f6b 100644 (file)
@@ -1157,16 +1157,17 @@ magic_found:
                            "fast symlink size (%u)\n", uspi->s_maxsymlinklen);
                uspi->s_maxsymlinklen = maxsymlen;
        }
+       sb->s_max_links = UFS_LINK_MAX;
 
        inode = ufs_iget(sb, UFS_ROOTINO);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
                goto failed;
        }
-       sb->s_root = d_alloc_root(inode);
+       sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                ret = -ENOMEM;
-               goto dalloc_failed;
+               goto failed;
        }
 
        ufs_setup_cstotal(sb);
@@ -1180,8 +1181,6 @@ magic_found:
        UFSD("EXIT\n");
        return 0;
 
-dalloc_failed:
-       iput(inode);
 failed:
        if (ubh)
                ubh_brelse_uspi (uspi);
index 866de27..e44ef7e 100644 (file)
@@ -118,17 +118,6 @@ xfs_rename(
        new_parent = (src_dp != target_dp);
        src_is_directory = S_ISDIR(src_ip->i_d.di_mode);
 
-       if (src_is_directory) {
-               /*
-                * Check for link count overflow on target_dp
-                */
-               if (target_ip == NULL && new_parent &&
-                   target_dp->i_d.di_nlink >= XFS_MAXLINK) {
-                       error = XFS_ERROR(EMLINK);
-                       goto std_return;
-               }
-       }
-
        xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
                                inodes, &num_inodes);
 
index ee5b695..baf40e3 100644 (file)
@@ -1341,6 +1341,7 @@ xfs_fs_fill_super(
        sb->s_blocksize = mp->m_sb.sb_blocksize;
        sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
        sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
+       sb->s_max_links = XFS_MAXLINK;
        sb->s_time_gran = 1;
        set_posix_acl_flag(sb);
 
@@ -1361,10 +1362,10 @@ xfs_fs_fill_super(
                error = EINVAL;
                goto out_syncd_stop;
        }
-       sb->s_root = d_alloc_root(root);
+       sb->s_root = d_make_root(root);
        if (!sb->s_root) {
                error = ENOMEM;
-               goto out_iput;
+               goto out_syncd_stop;
        }
 
        return 0;
@@ -1383,8 +1384,6 @@ xfs_fs_fill_super(
  out:
        return -error;
 
- out_iput:
-       iput(root);
  out_syncd_stop:
        xfs_syncd_stop(mp);
  out_unmount:
index 89dbb4a..79c05ac 100644 (file)
@@ -296,8 +296,6 @@ xfs_bumplink(
        xfs_trans_t *tp,
        xfs_inode_t *ip)
 {
-       if (ip->i_d.di_nlink >= XFS_MAXLINK)
-               return XFS_ERROR(EMLINK);
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
 
        ASSERT(ip->i_d.di_nlink > 0);
index ebdb888..64981d7 100644 (file)
@@ -917,14 +917,6 @@ xfs_create(
        xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
        unlock_dp_on_error = B_TRUE;
 
-       /*
-        * Check for directory link count overflow.
-        */
-       if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) {
-               error = XFS_ERROR(EMLINK);
-               goto out_trans_cancel;
-       }
-
        xfs_bmap_init(&free_list, &first_block);
 
        /*
@@ -1428,14 +1420,6 @@ xfs_link(
        xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
 
-       /*
-        * If the source has too many links, we can't make any more to it.
-        */
-       if (sip->i_d.di_nlink >= XFS_MAXLINK) {
-               error = XFS_ERROR(EMLINK);
-               goto error_return;
-       }
-
        /*
         * If we are using project inheritance, we only allow hard link
         * creation in our tree when the project IDs are the same; else
index 42b77b5..70cfcb2 100644 (file)
@@ -24,7 +24,9 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
+#ifndef atomic_inc_not_zero
 #define atomic_inc_not_zero(v)         atomic_add_unless((v), 1, 0)
+#endif
 
 /**
  * atomic_inc_not_zero_hint - increment if not null
index 9ff7a2c..ed3ef19 100644 (file)
@@ -684,7 +684,7 @@ extern void             audit_log_untrustedstring(struct audit_buffer *ab,
                                                      const char *string);
 extern void                audit_log_d_path(struct audit_buffer *ab,
                                             const char *prefix,
-                                            struct path *path);
+                                            const struct path *path);
 extern void                audit_log_key(struct audit_buffer *ab,
                                          char *key);
 extern void                audit_log_lost(const char *message);
index 0092102..366422b 100644 (file)
@@ -92,17 +92,17 @@ struct linux_binfmt {
        unsigned long min_coredump;     /* minimal dump size */
 };
 
-extern int __register_binfmt(struct linux_binfmt *fmt, int insert);
+extern void __register_binfmt(struct linux_binfmt *fmt, int insert);
 
 /* Registration of default binfmt handlers */
-static inline int register_binfmt(struct linux_binfmt *fmt)
+static inline void register_binfmt(struct linux_binfmt *fmt)
 {
-       return __register_binfmt(fmt, 0);
+       __register_binfmt(fmt, 0);
 }
 /* Same as above, but adds a new binfmt at the top of the list */
-static inline int insert_binfmt(struct linux_binfmt *fmt)
+static inline void insert_binfmt(struct linux_binfmt *fmt)
 {
-       return __register_binfmt(fmt, 1);
+       __register_binfmt(fmt, 1);
 }
 
 extern void unregister_binfmt(struct linux_binfmt *);
index 8a94217..48ce547 100644 (file)
  */
 #define CRYPTO_ALG_INSTANCE            0x00000800
 
+/* Set this bit if the algorithm provided is hardware accelerated but
+ * not available to userspace via instruction set or so.
+ */
+#define CRYPTO_ALG_KERN_DRIVER_ONLY    0x00001000
+
 /*
  * Transform masks and values (for crt_flags).
  */
@@ -309,6 +314,8 @@ struct crypto_alg {
  */
 int crypto_register_alg(struct crypto_alg *alg);
 int crypto_unregister_alg(struct crypto_alg *alg);
+int crypto_register_algs(struct crypto_alg *algs, int count);
+int crypto_unregister_algs(struct crypto_alg *algs, int count);
 
 /*
  * Algorithm query interface.
index ff5f525..7e11f14 100644 (file)
@@ -222,7 +222,6 @@ extern void shrink_dcache_for_umount(struct super_block *);
 extern int d_invalidate(struct dentry *);
 
 /* only used at mount-time */
-extern struct dentry * d_alloc_root(struct inode *);
 extern struct dentry * d_make_root(struct inode *);
 
 /* <clickety>-<click> the ramfs-type tree */
index 6169c26..ae36b72 100644 (file)
@@ -86,7 +86,7 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
                                  struct dentry *parent,
                                  struct debugfs_blob_wrapper *blob);
 
-struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
+struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
                                     struct dentry *parent,
                                     struct debugfs_regset32 *regset);
 
@@ -208,7 +208,7 @@ static inline struct dentry *debugfs_create_blob(const char *name, umode_t mode,
 }
 
 static inline struct dentry *debugfs_create_regset32(const char *name,
-                                  mode_t mode, struct dentry *parent,
+                                  umode_t mode, struct dentry *parent,
                                   struct debugfs_regset32 *regset)
 {
        return ERR_PTR(-ENODEV);
index 7c46bc3..5ad17cc 100644 (file)
@@ -262,10 +262,6 @@ extern int __must_check driver_create_file(struct device_driver *driver,
 extern void driver_remove_file(struct device_driver *driver,
                               const struct driver_attribute *attr);
 
-extern int __must_check driver_add_kobj(struct device_driver *drv,
-                                       struct kobject *kobj,
-                                       const char *fmt, ...);
-
 extern int __must_check driver_for_each_device(struct device_driver *drv,
                                               struct device *start,
                                               void *data,
index 21a7995..58bf158 100644 (file)
@@ -12,7 +12,6 @@
 struct file;
 
 extern void fput(struct file *);
-extern void drop_file_write_access(struct file *file);
 
 struct file_operations;
 struct vfsmount;
index 69cd5bb..9bbe1a9 100644 (file)
@@ -1459,6 +1459,7 @@ struct super_block {
        u8 s_uuid[16];                          /* UUID */
 
        void                    *s_fs_info;     /* Filesystem private info */
+       unsigned int            s_max_links;
        fmode_t                 s_mode;
 
        /* Granularity of c/m/atime in ns.
@@ -1811,11 +1812,11 @@ static inline void inode_inc_iversion(struct inode *inode)
        spin_unlock(&inode->i_lock);
 }
 
-extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);
+extern void touch_atime(struct path *);
 static inline void file_accessed(struct file *file)
 {
        if (!(file->f_flags & O_NOATIME))
-               touch_atime(file->f_path.mnt, file->f_path.dentry);
+               touch_atime(&file->f_path);
 }
 
 int sync_inode(struct inode *inode, struct writeback_control *wbc);
@@ -2304,7 +2305,10 @@ extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
 extern int inode_needs_sync(struct inode *inode);
 extern int generic_delete_inode(struct inode *inode);
-extern int generic_drop_inode(struct inode *inode);
+static inline int generic_drop_inode(struct inode *inode)
+{
+       return !inode->i_nlink || inode_unhashed(inode);
+}
 
 extern struct inode *ilookup5_nowait(struct super_block *sb,
                unsigned long hashval, int (*test)(struct inode *, void *),
index b148087..fa98bdb 100644 (file)
@@ -168,6 +168,7 @@ struct gfs2_rindex {
 #define GFS2_RGF_METAONLY      0x00000002
 #define GFS2_RGF_DATAONLY      0x00000004
 #define GFS2_RGF_NOALLOC       0x00000008
+#define GFS2_RGF_TRIMMED       0x00000010
 
 struct gfs2_rgrp {
        struct gfs2_meta_header rg_header;
index 5253471..1600ebf 100644 (file)
@@ -155,6 +155,7 @@ struct key {
 #define KEY_FLAG_IN_QUOTA      3       /* set if key consumes quota */
 #define KEY_FLAG_USER_CONSTRUCT        4       /* set if key is being constructed in userspace */
 #define KEY_FLAG_NEGATIVE      5       /* set if key is negative */
+#define KEY_FLAG_ROOT_CAN_CLEAR        6       /* set if key can be cleared by root without permission */
 
        /* the description string
         * - this is used to match a key against search criteria
index 2d4beab..b7ed475 100644 (file)
@@ -42,6 +42,7 @@
 #define OPENPROM_SUPER_MAGIC   0x9fa1
 #define PROC_SUPER_MAGIC       0x9fa0
 #define QNX4_SUPER_MAGIC       0x002f          /* qnx4 fs detection */
+#define QNX6_SUPER_MAGIC       0x68191122      /* qnx6 fs detection */
 
 #define REISERFS_SUPER_MAGIC   0x52654973      /* used by gcc */
                                        /* used by file system utilities that
index b1c8318..ee67e32 100644 (file)
@@ -893,9 +893,9 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
 
 int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
                unsigned long size);
-unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
+void zap_page_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *);
-unsigned long unmap_vmas(struct mmu_gather *tlb,
+void unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *start_vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *);
index f02d8b2..d46a18f 100644 (file)
@@ -58,6 +58,9 @@ struct device_node {
        struct  kref kref;
        unsigned long _flags;
        void    *data;
+#if defined(CONFIG_EEH)
+       struct eeh_dev *edev;
+#endif
 #if defined(CONFIG_SPARC)
        char    *path_component_name;
        unsigned int unique_id;
@@ -72,6 +75,13 @@ struct of_phandle_args {
        uint32_t args[MAX_PHANDLE_ARGS];
 };
 
+#if defined(CONFIG_EEH)
+static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
+{
+       return dn->edev;
+}
+#endif
+
 #ifdef CONFIG_OF_DYNAMIC
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
index 4633b2f..86292be 100644 (file)
@@ -46,7 +46,6 @@ struct padata_priv {
        struct list_head        list;
        struct parallel_data    *pd;
        int                     cb_cpu;
-       int                     seq_nr;
        int                     info;
        void                    (*parallel)(struct padata_priv *padata);
        void                    (*serial)(struct padata_priv *padata);
@@ -116,7 +115,6 @@ struct padata_cpumask {
  * @pinst: padata instance.
  * @pqueue: percpu padata queues used for parallelization.
  * @squeue: percpu padata queues used for serialuzation.
- * @seq_nr: The sequence number that will be attached to the next object.
  * @reorder_objects: Number of objects waiting in the reorder queues.
  * @refcnt: Number of objects holding a reference on this parallel_data.
  * @max_seq_nr:  Maximal used sequence number.
@@ -129,12 +127,12 @@ struct parallel_data {
        struct padata_instance          *pinst;
        struct padata_parallel_queue    __percpu *pqueue;
        struct padata_serial_queue      __percpu *squeue;
-       atomic_t                        seq_nr;
        atomic_t                        reorder_objects;
        atomic_t                        refcnt;
-       unsigned int                    max_seq_nr;
        struct padata_cpumask           cpumask;
        spinlock_t                      lock ____cacheline_aligned;
+       spinlock_t                      seq_lock;
+       unsigned int                    seq_nr;
        unsigned int                    processed;
        struct timer_list               timer;
 };
index b843fe7..27bf521 100644 (file)
@@ -1660,6 +1660,13 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
 static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
 #endif  /* CONFIG_OF */
 
+#ifdef CONFIG_EEH
+static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
+{
+       return pdev->dev.archdata.edev;
+}
+#endif
+
 /**
  * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
  * @pdev: the PCI device
index 7ddc7f1..a0413ac 100644 (file)
 # define PR_SET_MM_START_BRK           6
 # define PR_SET_MM_BRK                 7
 
+/*
+ * Set specific pid that is allowed to ptrace the current task.
+ * A value of 0 mean "no process".
+ */
+#define PR_SET_PTRACER 0x59616d61
+# define PR_SET_PTRACER_ANY ((unsigned long)-1)
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/qnx6_fs.h b/include/linux/qnx6_fs.h
new file mode 100644 (file)
index 0000000..26049ea
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  Name                 : qnx6_fs.h
+ *  Author               : Kai Bankett
+ *  Function             : qnx6 global filesystem definitions
+ *  History              : 17-01-2012 created
+ */
+#ifndef _LINUX_QNX6_FS_H
+#define _LINUX_QNX6_FS_H
+
+#include <linux/types.h>
+#include <linux/magic.h>
+
+#define QNX6_ROOT_INO 1
+
+/* for di_status */
+#define QNX6_FILE_DIRECTORY    0x01
+#define QNX6_FILE_DELETED      0x02
+#define QNX6_FILE_NORMAL       0x03
+
+#define QNX6_SUPERBLOCK_SIZE   0x200   /* superblock always is 512 bytes */
+#define QNX6_SUPERBLOCK_AREA   0x1000  /* area reserved for superblock */
+#define        QNX6_BOOTBLOCK_SIZE     0x2000  /* heading bootblock area */
+#define QNX6_DIR_ENTRY_SIZE    0x20    /* dir entry size of 32 bytes */
+#define QNX6_INODE_SIZE                0x80    /* each inode is 128 bytes */
+#define QNX6_INODE_SIZE_BITS   7       /* inode entry size shift */
+
+#define QNX6_NO_DIRECT_POINTERS        16      /* 16 blockptrs in sbl/inode */
+#define QNX6_PTR_MAX_LEVELS    5       /* maximum indirect levels */
+
+/* for filenames */
+#define QNX6_SHORT_NAME_MAX    27
+#define QNX6_LONG_NAME_MAX     510
+
+/* list of mount options */
+#define QNX6_MOUNT_MMI_FS      0x010000 /* mount as Audi MMI 3G fs */
+
+/*
+ * This is the original qnx6 inode layout on disk.
+ * Each inode is 128 byte long.
+ */
+struct qnx6_inode_entry {
+       __fs64          di_size;
+       __fs32          di_uid;
+       __fs32          di_gid;
+       __fs32          di_ftime;
+       __fs32          di_mtime;
+       __fs32          di_atime;
+       __fs32          di_ctime;
+       __fs16          di_mode;
+       __fs16          di_ext_mode;
+       __fs32          di_block_ptr[QNX6_NO_DIRECT_POINTERS];
+       __u8            di_filelevels;
+       __u8            di_status;
+       __u8            di_unknown2[2];
+       __fs32          di_zero2[6];
+};
+
+/*
+ * Each directory entry is maximum 32 bytes long.
+ * If more characters or special characters required it is stored
+ * in the longfilenames structure.
+ */
+struct qnx6_dir_entry {
+       __fs32          de_inode;
+       __u8            de_size;
+       char            de_fname[QNX6_SHORT_NAME_MAX];
+};
+
+/*
+ * Longfilename direntries have a different structure
+ */
+struct qnx6_long_dir_entry {
+       __fs32          de_inode;
+       __u8            de_size;
+       __u8            de_unknown[3];
+       __fs32          de_long_inode;
+       __fs32          de_checksum;
+};
+
+struct qnx6_long_filename {
+       __fs16          lf_size;
+       __u8            lf_fname[QNX6_LONG_NAME_MAX];
+};
+
+struct qnx6_root_node {
+       __fs64          size;
+       __fs32          ptr[QNX6_NO_DIRECT_POINTERS];
+       __u8            levels;
+       __u8            mode;
+       __u8            spare[6];
+};
+
+struct qnx6_super_block {
+       __fs32          sb_magic;
+       __fs32          sb_checksum;
+       __fs64          sb_serial;
+       __fs32          sb_ctime;       /* time the fs was created */
+       __fs32          sb_atime;       /* last access time */
+       __fs32          sb_flags;
+       __fs16          sb_version1;    /* filesystem version information */
+       __fs16          sb_version2;    /* filesystem version information */
+       __u8            sb_volumeid[16];
+       __fs32          sb_blocksize;
+       __fs32          sb_num_inodes;
+       __fs32          sb_free_inodes;
+       __fs32          sb_num_blocks;
+       __fs32          sb_free_blocks;
+       __fs32          sb_allocgroup;
+       struct qnx6_root_node Inode;
+       struct qnx6_root_node Bitmap;
+       struct qnx6_root_node Longfile;
+       struct qnx6_root_node Unknown;
+};
+
+/* Audi MMI 3G superblock layout is different to plain qnx6 */
+struct qnx6_mmi_super_block {
+       __fs32          sb_magic;
+       __fs32          sb_checksum;
+       __fs64          sb_serial;
+       __u8            sb_spare0[12];
+       __u8            sb_id[12];
+       __fs32          sb_blocksize;
+       __fs32          sb_num_inodes;
+       __fs32          sb_free_inodes;
+       __fs32          sb_num_blocks;
+       __fs32          sb_free_blocks;
+       __u8            sb_spare1[4];
+       struct qnx6_root_node Inode;
+       struct qnx6_root_node Bitmap;
+       struct qnx6_root_node Longfile;
+       struct qnx6_root_node Unknown;
+};
+
+#endif
diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
deleted file mode 100644 (file)
index f096b80..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <linux/init.h>
-#include <linux/posix_acl.h>
-
-#define REISERFS_ACL_VERSION   0x0001
-
-typedef struct {
-       __le16 e_tag;
-       __le16 e_perm;
-       __le32 e_id;
-} reiserfs_acl_entry;
-
-typedef struct {
-       __le16 e_tag;
-       __le16 e_perm;
-} reiserfs_acl_entry_short;
-
-typedef struct {
-       __le32 a_version;
-} reiserfs_acl_header;
-
-static inline size_t reiserfs_acl_size(int count)
-{
-       if (count <= 4) {
-               return sizeof(reiserfs_acl_header) +
-                   count * sizeof(reiserfs_acl_entry_short);
-       } else {
-               return sizeof(reiserfs_acl_header) +
-                   4 * sizeof(reiserfs_acl_entry_short) +
-                   (count - 4) * sizeof(reiserfs_acl_entry);
-       }
-}
-
-static inline int reiserfs_acl_count(size_t size)
-{
-       ssize_t s;
-       size -= sizeof(reiserfs_acl_header);
-       s = size - 4 * sizeof(reiserfs_acl_entry_short);
-       if (s < 0) {
-               if (size % sizeof(reiserfs_acl_entry_short))
-                       return -1;
-               return size / sizeof(reiserfs_acl_entry_short);
-       } else {
-               if (s % sizeof(reiserfs_acl_entry))
-                       return -1;
-               return s / sizeof(reiserfs_acl_entry) + 4;
-       }
-}
-
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-struct posix_acl *reiserfs_get_acl(struct inode *inode, int type);
-int reiserfs_acl_chmod(struct inode *inode);
-int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
-                                struct inode *dir, struct dentry *dentry,
-                                struct inode *inode);
-int reiserfs_cache_default_acl(struct inode *dir);
-extern const struct xattr_handler reiserfs_posix_acl_default_handler;
-extern const struct xattr_handler reiserfs_posix_acl_access_handler;
-
-#else
-
-#define reiserfs_cache_default_acl(inode) 0
-#define reiserfs_get_acl NULL
-
-static inline int reiserfs_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
-
-static inline int
-reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
-                            const struct inode *dir, struct dentry *dentry,
-                            struct inode *inode)
-{
-       return 0;
-}
-#endif
index 2213ddc..ea3700c 100644 (file)
@@ -1,32 +1,12 @@
 /*
  * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
  */
-
-                               /* this file has an amazingly stupid
-                                  name, yura please fix it to be
-                                  reiserfs.h, and merge all the rest
-                                  of our .h files that are in this
-                                  directory into it.  */
-
 #ifndef _LINUX_REISER_FS_H
 #define _LINUX_REISER_FS_H
 
 #include <linux/types.h>
 #include <linux/magic.h>
 
-#ifdef __KERNEL__
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <asm/unaligned.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/buffer_head.h>
-#include <linux/reiserfs_fs_i.h>
-#include <linux/reiserfs_fs_sb.h>
-#endif
-
 /*
  *  include/linux/reiser_fs.h
  *
 #define REISERFS_IOC_GETVERSION                FS_IOC_GETVERSION
 #define REISERFS_IOC_SETVERSION                FS_IOC_SETVERSION
 
-#ifdef __KERNEL__
-/* the 32 bit compat definitions with int argument */
-#define REISERFS_IOC32_UNPACK          _IOW(0xCD, 1, int)
-#define REISERFS_IOC32_GETFLAGS                FS_IOC32_GETFLAGS
-#define REISERFS_IOC32_SETFLAGS                FS_IOC32_SETFLAGS
-#define REISERFS_IOC32_GETVERSION      FS_IOC32_GETVERSION
-#define REISERFS_IOC32_SETVERSION      FS_IOC32_SETVERSION
-
-/*
- * Locking primitives. The write lock is a per superblock
- * special mutex that has properties close to the Big Kernel Lock
- * which was used in the previous locking scheme.
- */
-void reiserfs_write_lock(struct super_block *s);
-void reiserfs_write_unlock(struct super_block *s);
-int reiserfs_write_lock_once(struct super_block *s);
-void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
-
-#ifdef CONFIG_REISERFS_CHECK
-void reiserfs_lock_check_recursive(struct super_block *s);
-#else
-static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
-#endif
-
-/*
- * Several mutexes depend on the write lock.
- * However sometimes we want to relax the write lock while we hold
- * these mutexes, according to the release/reacquire on schedule()
- * properties of the Bkl that were used.
- * Reiserfs performances and locking were based on this scheme.
- * Now that the write lock is a mutex and not the bkl anymore, doing so
- * may result in a deadlock:
- *
- * A acquire write_lock
- * A acquire j_commit_mutex
- * A release write_lock and wait for something
- * B acquire write_lock
- * B can't acquire j_commit_mutex and sleep
- * A can't acquire write lock anymore
- * deadlock
- *
- * What we do here is avoiding such deadlock by playing the same game
- * than the Bkl: if we can't acquire a mutex that depends on the write lock,
- * we release the write lock, wait a bit and then retry.
- *
- * The mutexes concerned by this hack are:
- * - The commit mutex of a journal list
- * - The flush mutex
- * - The journal lock
- * - The inode mutex
- */
-static inline void reiserfs_mutex_lock_safe(struct mutex *m,
-                              struct super_block *s)
-{
-       reiserfs_lock_check_recursive(s);
-       reiserfs_write_unlock(s);
-       mutex_lock(m);
-       reiserfs_write_lock(s);
-}
-
-static inline void
-reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
-                              struct super_block *s)
-{
-       reiserfs_lock_check_recursive(s);
-       reiserfs_write_unlock(s);
-       mutex_lock_nested(m, subclass);
-       reiserfs_write_lock(s);
-}
-
-static inline void
-reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
-{
-       reiserfs_lock_check_recursive(s);
-       reiserfs_write_unlock(s);
-       down_read(sem);
-       reiserfs_write_lock(s);
-}
-
-/*
- * When we schedule, we usually want to also release the write lock,
- * according to the previous bkl based locking scheme of reiserfs.
- */
-static inline void reiserfs_cond_resched(struct super_block *s)
-{
-       if (need_resched()) {
-               reiserfs_write_unlock(s);
-               schedule();
-               reiserfs_write_lock(s);
-       }
-}
-
-struct fid;
-
-/* in reading the #defines, it may help to understand that they employ
-   the following abbreviations:
-
-   B = Buffer
-   I = Item header
-   H = Height within the tree (should be changed to LEV)
-   N = Number of the item in the node
-   STAT = stat data
-   DEH = Directory Entry Header
-   EC = Entry Count
-   E = Entry number
-   UL = Unsigned Long
-   BLKH = BLocK Header
-   UNFM = UNForMatted node
-   DC = Disk Child
-   P = Path
-
-   These #defines are named by concatenating these abbreviations,
-   where first comes the arguments, and last comes the return value,
-   of the macro.
-
-*/
-
-#define USE_INODE_GENERATION_COUNTER
-
-#define REISERFS_PREALLOCATE
-#define DISPLACE_NEW_PACKING_LOCALITIES
-#define PREALLOCATION_SIZE 9
-
-/* n must be power of 2 */
-#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
-
-// to be ok for alpha and others we have to align structures to 8 byte
-// boundary.
-// FIXME: do not change 4 by anything else: there is code which relies on that
-#define ROUND_UP(x) _ROUND_UP(x,8LL)
-
-/* debug levels.  Right now, CONFIG_REISERFS_CHECK means print all debug
-** messages.
-*/
-#define REISERFS_DEBUG_CODE 5  /* extra messages to help find/debug errors */
-
-void __reiserfs_warning(struct super_block *s, const char *id,
-                        const char *func, const char *fmt, ...);
-#define reiserfs_warning(s, id, fmt, args...) \
-        __reiserfs_warning(s, id, __func__, fmt, ##args)
-/* assertions handling */
-
-/** always check a condition and panic if it's false. */
-#define __RASSERT(cond, scond, format, args...)                        \
-do {                                                                   \
-       if (!(cond))                                                    \
-               reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \
-                              __FILE__ ":%i:%s: " format "\n",         \
-                              in_interrupt() ? -1 : task_pid_nr(current), \
-                              __LINE__, __func__ , ##args);            \
-} while (0)
-
-#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
-
-#if defined( CONFIG_REISERFS_CHECK )
-#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args)
-#else
-#define RFALSE( cond, format, args... ) do {;} while( 0 )
-#endif
-
-#define CONSTF __attribute_const__
-/*
- * Disk Data Structures
- */
-
-/***************************************************************************/
-/*                             SUPER BLOCK                                 */
-/***************************************************************************/
-
-/*
- * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
- * the version in RAM is part of a larger structure containing fields never written to disk.
- */
-#define UNSET_HASH 0           // read_super will guess about, what hash names
-                    // in directories were sorted with
-#define TEA_HASH  1
-#define YURA_HASH 2
-#define R5_HASH   3
-#define DEFAULT_HASH R5_HASH
-
-struct journal_params {
-       __le32 jp_journal_1st_block;    /* where does journal start from on its
-                                        * device */
-       __le32 jp_journal_dev;  /* journal device st_rdev */
-       __le32 jp_journal_size; /* size of the journal */
-       __le32 jp_journal_trans_max;    /* max number of blocks in a transaction. */
-       __le32 jp_journal_magic;        /* random value made on fs creation (this
-                                        * was sb_journal_block_count) */
-       __le32 jp_journal_max_batch;    /* max number of blocks to batch into a
-                                        * trans */
-       __le32 jp_journal_max_commit_age;       /* in seconds, how old can an async
-                                                * commit be */
-       __le32 jp_journal_max_trans_age;        /* in seconds, how old can a transaction
-                                                * be */
-};
-
-/* this is the super from 3.5.X, where X >= 10 */
-struct reiserfs_super_block_v1 {
-       __le32 s_block_count;   /* blocks count         */
-       __le32 s_free_blocks;   /* free blocks count    */
-       __le32 s_root_block;    /* root block number    */
-       struct journal_params s_journal;
-       __le16 s_blocksize;     /* block size */
-       __le16 s_oid_maxsize;   /* max size of object id array, see
-                                * get_objectid() commentary  */
-       __le16 s_oid_cursize;   /* current size of object id array */
-       __le16 s_umount_state;  /* this is set to 1 when filesystem was
-                                * umounted, to 2 - when not */
-       char s_magic[10];       /* reiserfs magic string indicates that
-                                * file system is reiserfs:
-                                * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
-       __le16 s_fs_state;      /* it is set to used by fsck to mark which
-                                * phase of rebuilding is done */
-       __le32 s_hash_function_code;    /* indicate, what hash function is being use
-                                        * to sort names in a directory*/
-       __le16 s_tree_height;   /* height of disk tree */
-       __le16 s_bmap_nr;       /* amount of bitmap blocks needed to address
-                                * each block of file system */
-       __le16 s_version;       /* this field is only reliable on filesystem
-                                * with non-standard journal */
-       __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
-                                        * device, we need to keep after
-                                        * making fs with non-standard journal */
-} __attribute__ ((__packed__));
-
-#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
-
-/* this is the on disk super block */
-struct reiserfs_super_block {
-       struct reiserfs_super_block_v1 s_v1;
-       __le32 s_inode_generation;
-       __le32 s_flags;         /* Right now used only by inode-attributes, if enabled */
-       unsigned char s_uuid[16];       /* filesystem unique identifier */
-       unsigned char s_label[16];      /* filesystem volume label */
-       __le16 s_mnt_count;             /* Count of mounts since last fsck */
-       __le16 s_max_mnt_count;         /* Maximum mounts before check */
-       __le32 s_lastcheck;             /* Timestamp of last fsck */
-       __le32 s_check_interval;        /* Interval between checks */
-       char s_unused[76];      /* zero filled by mkreiserfs and
-                                * reiserfs_convert_objectid_map_v1()
-                                * so any additions must be updated
-                                * there as well. */
-} __attribute__ ((__packed__));
-
-#define SB_SIZE (sizeof(struct reiserfs_super_block))
-
-#define REISERFS_VERSION_1 0
-#define REISERFS_VERSION_2 2
-
-// on-disk super block fields converted to cpu form
-#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
-#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
-#define SB_BLOCKSIZE(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
-#define SB_BLOCK_COUNT(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
-#define SB_FREE_BLOCKS(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
-#define SB_REISERFS_MAGIC(s) \
-        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
-#define SB_ROOT_BLOCK(s) \
-        le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
-#define SB_TREE_HEIGHT(s) \
-        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
-#define SB_REISERFS_STATE(s) \
-        le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
-#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
-#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
-
-#define PUT_SB_BLOCK_COUNT(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0)
-#define PUT_SB_FREE_BLOCKS(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0)
-#define PUT_SB_ROOT_BLOCK(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0)
-#define PUT_SB_TREE_HEIGHT(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
-#define PUT_SB_REISERFS_STATE(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
-#define PUT_SB_VERSION(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
-#define PUT_SB_BMAP_NR(s, val) \
-   do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
-
-#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
-#define SB_ONDISK_JOURNAL_SIZE(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
-#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
-#define SB_ONDISK_JOURNAL_DEVICE(s) \
-         le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
-#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
-         le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
-
-#define is_block_in_log_or_reserved_area(s, block) \
-         block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
-         && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) +  \
-         ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
-         SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
-
-int is_reiserfs_3_5(struct reiserfs_super_block *rs);
-int is_reiserfs_3_6(struct reiserfs_super_block *rs);
-int is_reiserfs_jr(struct reiserfs_super_block *rs);
-
-/* ReiserFS leaves the first 64k unused, so that partition labels have
-   enough space.  If someone wants to write a fancy bootloader that
-   needs more than 64k, let us know, and this will be increased in size.
-   This number must be larger than than the largest block size on any
-   platform, or code will break.  -Hans */
-#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
-#define REISERFS_FIRST_BLOCK unused_define
-#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
-
-/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
-#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
-
-/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
-#define CARRY_ON      0
-#define REPEAT_SEARCH -1
-#define IO_ERROR      -2
-#define NO_DISK_SPACE -3
-#define NO_BALANCING_NEEDED  (-4)
-#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
-#define QUOTA_EXCEEDED -6
-
-typedef __u32 b_blocknr_t;
-typedef __le32 unp_t;
-
-struct unfm_nodeinfo {
-       unp_t unfm_nodenum;
-       unsigned short unfm_freespace;
-};
-
-/* there are two formats of keys: 3.5 and 3.6
- */
-#define KEY_FORMAT_3_5 0
-#define KEY_FORMAT_3_6 1
-
-/* there are two stat datas */
-#define STAT_DATA_V1 0
-#define STAT_DATA_V2 1
-
-static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
-{
-       return container_of(inode, struct reiserfs_inode_info, vfs_inode);
-}
-
-static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16
- * which overflows on large file systems. */
-static inline __u32 reiserfs_bmap_count(struct super_block *sb)
-{
-       return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1;
-}
-
-static inline int bmap_would_wrap(unsigned bmap_nr)
-{
-       return bmap_nr > ((1LL << 16) - 1);
-}
-
-/** this says about version of key of all items (but stat data) the
-    object consists of */
-#define get_inode_item_key_version( inode )                                    \
-    ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
-
-#define set_inode_item_key_version( inode, version )                           \
-         ({ if((version)==KEY_FORMAT_3_6)                                      \
-                REISERFS_I(inode)->i_flags |= i_item_key_version_mask;      \
-            else                                                               \
-                REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
-
-#define get_inode_sd_version(inode)                                            \
-    ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
-
-#define set_inode_sd_version(inode, version)                                   \
-         ({ if((version)==STAT_DATA_V2)                                        \
-                REISERFS_I(inode)->i_flags |= i_stat_data_version_mask;     \
-            else                                                               \
-                REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
-
-/* This is an aggressive tail suppression policy, I am hoping it
-   improves our benchmarks. The principle behind it is that percentage
-   space saving is what matters, not absolute space saving.  This is
-   non-intuitive, but it helps to understand it if you consider that the
-   cost to access 4 blocks is not much more than the cost to access 1
-   block, if you have to do a seek and rotate.  A tail risks a
-   non-linear disk access that is significant as a percentage of total
-   time cost for a 4 block file and saves an amount of space that is
-   less significant as a percentage of space, or so goes the hypothesis.
-   -Hans */
-#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
-(\
-  (!(n_tail_size)) || \
-  (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
-   ( (n_file_size) >= (n_block_size) * 4 ) || \
-   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
-   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
-   ( ( (n_file_size) >= (n_block_size) ) && \
-     ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
-)
-
-/* Another strategy for tails, this one means only create a tail if all the
-   file would fit into one DIRECT item.
-   Primary intention for this one is to increase performance by decreasing
-   seeking.
-*/
-#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
-(\
-  (!(n_tail_size)) || \
-  (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
-)
-
-/*
- * values for s_umount_state field
- */
-#define REISERFS_VALID_FS    1
-#define REISERFS_ERROR_FS    2
-
-//
-// there are 5 item types currently
-//
-#define TYPE_STAT_DATA 0
-#define TYPE_INDIRECT 1
-#define TYPE_DIRECT 2
-#define TYPE_DIRENTRY 3
-#define TYPE_MAXTYPE 3
-#define TYPE_ANY 15            // FIXME: comment is required
-
-/***************************************************************************/
-/*                       KEY & ITEM HEAD                                   */
-/***************************************************************************/
-
-//
-// directories use this key as well as old files
-//
-struct offset_v1 {
-       __le32 k_offset;
-       __le32 k_uniqueness;
-} __attribute__ ((__packed__));
-
-struct offset_v2 {
-       __le64 v;
-} __attribute__ ((__packed__));
-
-static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
-{
-       __u8 type = le64_to_cpu(v2->v) >> 60;
-       return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
-}
-
-static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type)
-{
-       v2->v =
-           (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60);
-}
-
-static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
-{
-       return le64_to_cpu(v2->v) & (~0ULL >> 4);
-}
-
-static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset)
-{
-       offset &= (~0ULL >> 4);
-       v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset);
-}
-
-/* Key of an item determines its location in the S+tree, and
-   is composed of 4 components */
-struct reiserfs_key {
-       __le32 k_dir_id;        /* packing locality: by default parent
-                                  directory object id */
-       __le32 k_objectid;      /* object identifier */
-       union {
-               struct offset_v1 k_offset_v1;
-               struct offset_v2 k_offset_v2;
-       } __attribute__ ((__packed__)) u;
-} __attribute__ ((__packed__));
-
-struct in_core_key {
-       __u32 k_dir_id;         /* packing locality: by default parent
-                                  directory object id */
-       __u32 k_objectid;       /* object identifier */
-       __u64 k_offset;
-       __u8 k_type;
-};
-
-struct cpu_key {
-       struct in_core_key on_disk_key;
-       int version;
-       int key_length;         /* 3 in all cases but direct2indirect and
-                                  indirect2direct conversion */
-};
-
-/* Our function for comparing keys can compare keys of different
-   lengths.  It takes as a parameter the length of the keys it is to
-   compare.  These defines are used in determining what is to be passed
-   to it as that parameter. */
-#define REISERFS_FULL_KEY_LEN     4
-#define REISERFS_SHORT_KEY_LEN    2
-
-/* The result of the key compare */
-#define FIRST_GREATER 1
-#define SECOND_GREATER -1
-#define KEYS_IDENTICAL 0
-#define KEY_FOUND 1
-#define KEY_NOT_FOUND 0
-
-#define KEY_SIZE (sizeof(struct reiserfs_key))
-#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
-
-/* return values for search_by_key and clones */
-#define ITEM_FOUND 1
-#define ITEM_NOT_FOUND 0
-#define ENTRY_FOUND 1
-#define ENTRY_NOT_FOUND 0
-#define DIRECTORY_NOT_FOUND -1
-#define REGULAR_FILE_FOUND -2
-#define DIRECTORY_FOUND -3
-#define BYTE_FOUND 1
-#define BYTE_NOT_FOUND 0
-#define FILE_NOT_FOUND -1
-
-#define POSITION_FOUND 1
-#define POSITION_NOT_FOUND 0
-
-// return values for reiserfs_find_entry and search_by_entry_key
-#define NAME_FOUND 1
-#define NAME_NOT_FOUND 0
-#define GOTO_PREVIOUS_ITEM 2
-#define NAME_FOUND_INVISIBLE 3
-
-/*  Everything in the filesystem is stored as a set of items.  The
-    item head contains the key of the item, its free space (for
-    indirect items) and specifies the location of the item itself
-    within the block.  */
-
-struct item_head {
-       /* Everything in the tree is found by searching for it based on
-        * its key.*/
-       struct reiserfs_key ih_key;
-       union {
-               /* The free space in the last unformatted node of an
-                  indirect item if this is an indirect item.  This
-                  equals 0xFFFF iff this is a direct item or stat data
-                  item. Note that the key, not this field, is used to
-                  determine the item type, and thus which field this
-                  union contains. */
-               __le16 ih_free_space_reserved;
-               /* Iff this is a directory item, this field equals the
-                  number of directory entries in the directory item. */
-               __le16 ih_entry_count;
-       } __attribute__ ((__packed__)) u;
-       __le16 ih_item_len;     /* total size of the item body */
-       __le16 ih_item_location;        /* an offset to the item body
-                                        * within the block */
-       __le16 ih_version;      /* 0 for all old items, 2 for new
-                                  ones. Highest bit is set by fsck
-                                  temporary, cleaned after all
-                                  done */
-} __attribute__ ((__packed__));
-/* size of item header     */
-#define IH_SIZE (sizeof(struct item_head))
-
-#define ih_free_space(ih)            le16_to_cpu((ih)->u.ih_free_space_reserved)
-#define ih_version(ih)               le16_to_cpu((ih)->ih_version)
-#define ih_entry_count(ih)           le16_to_cpu((ih)->u.ih_entry_count)
-#define ih_location(ih)              le16_to_cpu((ih)->ih_item_location)
-#define ih_item_len(ih)              le16_to_cpu((ih)->ih_item_len)
-
-#define put_ih_free_space(ih, val)   do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0)
-#define put_ih_version(ih, val)      do { (ih)->ih_version = cpu_to_le16(val); } while (0)
-#define put_ih_entry_count(ih, val)  do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0)
-#define put_ih_location(ih, val)     do { (ih)->ih_item_location = cpu_to_le16(val); } while (0)
-#define put_ih_item_len(ih, val)     do { (ih)->ih_item_len = cpu_to_le16(val); } while (0)
-
-#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
-
-#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
-#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))
-
-/* these operate on indirect items, where you've got an array of ints
-** at a possibly unaligned location.  These are a noop on ia32
-** 
-** p is the array of __u32, i is the index into the array, v is the value
-** to store there.
-*/
-#define get_block_num(p, i) get_unaligned_le32((p) + (i))
-#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i))
-
-//
-// in old version uniqueness field shows key type
-//
-#define V1_SD_UNIQUENESS 0
-#define V1_INDIRECT_UNIQUENESS 0xfffffffe
-#define V1_DIRECT_UNIQUENESS 0xffffffff
-#define V1_DIRENTRY_UNIQUENESS 500
-#define V1_ANY_UNIQUENESS 555  // FIXME: comment is required
-
-//
-// here are conversion routines
-//
-static inline int uniqueness2type(__u32 uniqueness) CONSTF;
-static inline int uniqueness2type(__u32 uniqueness)
-{
-       switch ((int)uniqueness) {
-       case V1_SD_UNIQUENESS:
-               return TYPE_STAT_DATA;
-       case V1_INDIRECT_UNIQUENESS:
-               return TYPE_INDIRECT;
-       case V1_DIRECT_UNIQUENESS:
-               return TYPE_DIRECT;
-       case V1_DIRENTRY_UNIQUENESS:
-               return TYPE_DIRENTRY;
-       case V1_ANY_UNIQUENESS:
-       default:
-               return TYPE_ANY;
-       }
-}
-
-static inline __u32 type2uniqueness(int type) CONSTF;
-static inline __u32 type2uniqueness(int type)
-{
-       switch (type) {
-       case TYPE_STAT_DATA:
-               return V1_SD_UNIQUENESS;
-       case TYPE_INDIRECT:
-               return V1_INDIRECT_UNIQUENESS;
-       case TYPE_DIRECT:
-               return V1_DIRECT_UNIQUENESS;
-       case TYPE_DIRENTRY:
-               return V1_DIRENTRY_UNIQUENESS;
-       case TYPE_ANY:
-       default:
-               return V1_ANY_UNIQUENESS;
-       }
-}
-
-//
-// key is pointer to on disk key which is stored in le, result is cpu,
-// there is no way to get version of object from key, so, provide
-// version to these defines
-//
-static inline loff_t le_key_k_offset(int version,
-                                    const struct reiserfs_key *key)
-{
-       return (version == KEY_FORMAT_3_5) ?
-           le32_to_cpu(key->u.k_offset_v1.k_offset) :
-           offset_v2_k_offset(&(key->u.k_offset_v2));
-}
-
-static inline loff_t le_ih_k_offset(const struct item_head *ih)
-{
-       return le_key_k_offset(ih_version(ih), &(ih->ih_key));
-}
-
-static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
-{
-       return (version == KEY_FORMAT_3_5) ?
-           uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
-           offset_v2_k_type(&(key->u.k_offset_v2));
-}
-
-static inline loff_t le_ih_k_type(const struct item_head *ih)
-{
-       return le_key_k_type(ih_version(ih), &(ih->ih_key));
-}
-
-static inline void set_le_key_k_offset(int version, struct reiserfs_key *key,
-                                      loff_t offset)
-{
-       (version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) :       /* jdm check */
-           (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
-}
-
-static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset)
-{
-       set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
-}
-
-static inline void set_le_key_k_type(int version, struct reiserfs_key *key,
-                                    int type)
-{
-       (version == KEY_FORMAT_3_5) ?
-           (void)(key->u.k_offset_v1.k_uniqueness =
-                  cpu_to_le32(type2uniqueness(type)))
-           : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type));
-}
-
-static inline void set_le_ih_k_type(struct item_head *ih, int type)
-{
-       set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
-}
-
-static inline int is_direntry_le_key(int version, struct reiserfs_key *key)
-{
-       return le_key_k_type(version, key) == TYPE_DIRENTRY;
-}
-
-static inline int is_direct_le_key(int version, struct reiserfs_key *key)
-{
-       return le_key_k_type(version, key) == TYPE_DIRECT;
-}
-
-static inline int is_indirect_le_key(int version, struct reiserfs_key *key)
-{
-       return le_key_k_type(version, key) == TYPE_INDIRECT;
-}
-
-static inline int is_statdata_le_key(int version, struct reiserfs_key *key)
-{
-       return le_key_k_type(version, key) == TYPE_STAT_DATA;
-}
-
-//
-// item header has version.
-//
-static inline int is_direntry_le_ih(struct item_head *ih)
-{
-       return is_direntry_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_direct_le_ih(struct item_head *ih)
-{
-       return is_direct_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_indirect_le_ih(struct item_head *ih)
-{
-       return is_indirect_le_key(ih_version(ih), &ih->ih_key);
-}
-
-static inline int is_statdata_le_ih(struct item_head *ih)
-{
-       return is_statdata_le_key(ih_version(ih), &ih->ih_key);
-}
-
-//
-// key is pointer to cpu key, result is cpu
-//
-static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
-{
-       return key->on_disk_key.k_offset;
-}
-
-static inline loff_t cpu_key_k_type(const struct cpu_key *key)
-{
-       return key->on_disk_key.k_type;
-}
-
-static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset)
-{
-       key->on_disk_key.k_offset = offset;
-}
-
-static inline void set_cpu_key_k_type(struct cpu_key *key, int type)
-{
-       key->on_disk_key.k_type = type;
-}
-
-static inline void cpu_key_k_offset_dec(struct cpu_key *key)
-{
-       key->on_disk_key.k_offset--;
-}
-
-#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
-#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
-#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
-#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
-
-/* are these used ? */
-#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
-#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
-#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
-#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
-
-#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \
-    (!COMP_SHORT_KEYS(ih, key) && \
-         I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize))
-
-/* maximal length of item */
-#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
-#define MIN_ITEM_LEN 1
-
-/* object identifier for root dir */
-#define REISERFS_ROOT_OBJECTID 2
-#define REISERFS_ROOT_PARENT_OBJECTID 1
-
-extern struct reiserfs_key root_key;
-
-/* 
- * Picture represents a leaf of the S+tree
- *  ______________________________________________________
- * |      |  Array of     |                   |           |
- * |Block |  Object-Item  |      F r e e      |  Objects- |
- * | head |  Headers      |     S p a c e     |   Items   |
- * |______|_______________|___________________|___________|
- */
-
-/* Header of a disk block.  More precisely, header of a formatted leaf
-   or internal node, and not the header of an unformatted node. */
-struct block_head {
-       __le16 blk_level;       /* Level of a block in the tree. */
-       __le16 blk_nr_item;     /* Number of keys/items in a block. */
-       __le16 blk_free_space;  /* Block free space in bytes. */
-       __le16 blk_reserved;
-       /* dump this in v4/planA */
-       struct reiserfs_key blk_right_delim_key;        /* kept only for compatibility */
-};
-
-#define BLKH_SIZE                     (sizeof(struct block_head))
-#define blkh_level(p_blkh)            (le16_to_cpu((p_blkh)->blk_level))
-#define blkh_nr_item(p_blkh)          (le16_to_cpu((p_blkh)->blk_nr_item))
-#define blkh_free_space(p_blkh)       (le16_to_cpu((p_blkh)->blk_free_space))
-#define blkh_reserved(p_blkh)         (le16_to_cpu((p_blkh)->blk_reserved))
-#define set_blkh_level(p_blkh,val)    ((p_blkh)->blk_level = cpu_to_le16(val))
-#define set_blkh_nr_item(p_blkh,val)  ((p_blkh)->blk_nr_item = cpu_to_le16(val))
-#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val))
-#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val))
-#define blkh_right_delim_key(p_blkh)  ((p_blkh)->blk_right_delim_key)
-#define set_blkh_right_delim_key(p_blkh,val)  ((p_blkh)->blk_right_delim_key = val)
-
-/*
- * values for blk_level field of the struct block_head
- */
-
-#define FREE_LEVEL 0           /* when node gets removed from the tree its
-                                  blk_level is set to FREE_LEVEL. It is then
-                                  used to see whether the node is still in the
-                                  tree */
-
-#define DISK_LEAF_NODE_LEVEL  1        /* Leaf node level. */
-
-/* Given the buffer head of a formatted node, resolve to the block head of that node. */
-#define B_BLK_HEAD(bh)                 ((struct block_head *)((bh)->b_data))
-/* Number of items that are in buffer. */
-#define B_NR_ITEMS(bh)                 (blkh_nr_item(B_BLK_HEAD(bh)))
-#define B_LEVEL(bh)                    (blkh_level(B_BLK_HEAD(bh)))
-#define B_FREE_SPACE(bh)               (blkh_free_space(B_BLK_HEAD(bh)))
-
-#define PUT_B_NR_ITEMS(bh, val)                do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0)
-#define PUT_B_LEVEL(bh, val)           do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0)
-#define PUT_B_FREE_SPACE(bh, val)      do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0)
-
-/* Get right delimiting key. -- little endian */
-#define B_PRIGHT_DELIM_KEY(bh)         (&(blk_right_delim_key(B_BLK_HEAD(bh))))
-
-/* Does the buffer contain a disk leaf. */
-#define B_IS_ITEMS_LEVEL(bh)           (B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL)
-
-/* Does the buffer contain a disk internal node */
-#define B_IS_KEYS_LEVEL(bh)      (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \
-                                           && B_LEVEL(bh) <= MAX_HEIGHT)
-
-/***************************************************************************/
-/*                             STAT DATA                                   */
-/***************************************************************************/
-
-//
-// old stat data is 32 bytes long. We are going to distinguish new one by
-// different size
-//
-struct stat_data_v1 {
-       __le16 sd_mode;         /* file type, permissions */
-       __le16 sd_nlink;        /* number of hard links */
-       __le16 sd_uid;          /* owner */
-       __le16 sd_gid;          /* group */
-       __le32 sd_size;         /* file size */
-       __le32 sd_atime;        /* time of last access */
-       __le32 sd_mtime;        /* time file was last modified  */
-       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
-       union {
-               __le32 sd_rdev;
-               __le32 sd_blocks;       /* number of blocks file uses */
-       } __attribute__ ((__packed__)) u;
-       __le32 sd_first_direct_byte;    /* first byte of file which is stored
-                                          in a direct item: except that if it
-                                          equals 1 it is a symlink and if it
-                                          equals ~(__u32)0 there is no
-                                          direct item.  The existence of this
-                                          field really grates on me. Let's
-                                          replace it with a macro based on
-                                          sd_size and our tail suppression
-                                          policy.  Someday.  -Hans */
-} __attribute__ ((__packed__));
-
-#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
-#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
-#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
-#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
-#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
-#define set_sd_v1_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le16(v))
-#define sd_v1_uid(sdp)          (le16_to_cpu((sdp)->sd_uid))
-#define set_sd_v1_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le16(v))
-#define sd_v1_gid(sdp)          (le16_to_cpu((sdp)->sd_gid))
-#define set_sd_v1_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le16(v))
-#define sd_v1_size(sdp)         (le32_to_cpu((sdp)->sd_size))
-#define set_sd_v1_size(sdp,v)   ((sdp)->sd_size = cpu_to_le32(v))
-#define sd_v1_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
-#define set_sd_v1_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
-#define sd_v1_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
-#define set_sd_v1_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
-#define sd_v1_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
-#define set_sd_v1_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
-#define sd_v1_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
-#define set_sd_v1_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
-#define sd_v1_blocks(sdp)       (le32_to_cpu((sdp)->u.sd_blocks))
-#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
-#define sd_v1_first_direct_byte(sdp) \
-                                (le32_to_cpu((sdp)->sd_first_direct_byte))
-#define set_sd_v1_first_direct_byte(sdp,v) \
-                                ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
-
-/* inode flags stored in sd_attrs (nee sd_reserved) */
-
-/* we want common flags to have the same values as in ext2,
-   so chattr(1) will work without problems */
-#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
-#define REISERFS_APPEND_FL    FS_APPEND_FL
-#define REISERFS_SYNC_FL      FS_SYNC_FL
-#define REISERFS_NOATIME_FL   FS_NOATIME_FL
-#define REISERFS_NODUMP_FL    FS_NODUMP_FL
-#define REISERFS_SECRM_FL     FS_SECRM_FL
-#define REISERFS_UNRM_FL      FS_UNRM_FL
-#define REISERFS_COMPR_FL     FS_COMPR_FL
-#define REISERFS_NOTAIL_FL    FS_NOTAIL_FL
-
-/* persistent flags that file inherits from the parent directory */
-#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |        \
-                               REISERFS_SYNC_FL |      \
-                               REISERFS_NOATIME_FL |   \
-                               REISERFS_NODUMP_FL |    \
-                               REISERFS_SECRM_FL |     \
-                               REISERFS_COMPR_FL |     \
-                               REISERFS_NOTAIL_FL )
-
-/* Stat Data on disk (reiserfs version of UFS disk inode minus the
-   address blocks) */
-struct stat_data {
-       __le16 sd_mode;         /* file type, permissions */
-       __le16 sd_attrs;        /* persistent inode flags */
-       __le32 sd_nlink;        /* number of hard links */
-       __le64 sd_size;         /* file size */
-       __le32 sd_uid;          /* owner */
-       __le32 sd_gid;          /* group */
-       __le32 sd_atime;        /* time of last access */
-       __le32 sd_mtime;        /* time file was last modified  */
-       __le32 sd_ctime;        /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
-       __le32 sd_blocks;
-       union {
-               __le32 sd_rdev;
-               __le32 sd_generation;
-               //__le32 sd_first_direct_byte;
-               /* first byte of file which is stored in a
-                  direct item: except that if it equals 1
-                  it is a symlink and if it equals
-                  ~(__u32)0 there is no direct item.  The
-                  existence of this field really grates
-                  on me. Let's replace it with a macro
-                  based on sd_size and our tail
-                  suppression policy? */
-       } __attribute__ ((__packed__)) u;
-} __attribute__ ((__packed__));
-//
-// this is 44 bytes long
-//
-#define SD_SIZE (sizeof(struct stat_data))
-#define SD_V2_SIZE              SD_SIZE
-#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
-#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
-#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
-/* sd_reserved */
-/* set_sd_reserved */
-#define sd_v2_nlink(sdp)        (le32_to_cpu((sdp)->sd_nlink))
-#define set_sd_v2_nlink(sdp,v)  ((sdp)->sd_nlink = cpu_to_le32(v))
-#define sd_v2_size(sdp)         (le64_to_cpu((sdp)->sd_size))
-#define set_sd_v2_size(sdp,v)   ((sdp)->sd_size = cpu_to_le64(v))
-#define sd_v2_uid(sdp)          (le32_to_cpu((sdp)->sd_uid))
-#define set_sd_v2_uid(sdp,v)    ((sdp)->sd_uid = cpu_to_le32(v))
-#define sd_v2_gid(sdp)          (le32_to_cpu((sdp)->sd_gid))
-#define set_sd_v2_gid(sdp,v)    ((sdp)->sd_gid = cpu_to_le32(v))
-#define sd_v2_atime(sdp)        (le32_to_cpu((sdp)->sd_atime))
-#define set_sd_v2_atime(sdp,v)  ((sdp)->sd_atime = cpu_to_le32(v))
-#define sd_v2_mtime(sdp)        (le32_to_cpu((sdp)->sd_mtime))
-#define set_sd_v2_mtime(sdp,v)  ((sdp)->sd_mtime = cpu_to_le32(v))
-#define sd_v2_ctime(sdp)        (le32_to_cpu((sdp)->sd_ctime))
-#define set_sd_v2_ctime(sdp,v)  ((sdp)->sd_ctime = cpu_to_le32(v))
-#define sd_v2_blocks(sdp)       (le32_to_cpu((sdp)->sd_blocks))
-#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
-#define sd_v2_rdev(sdp)         (le32_to_cpu((sdp)->u.sd_rdev))
-#define set_sd_v2_rdev(sdp,v)   ((sdp)->u.sd_rdev = cpu_to_le32(v))
-#define sd_v2_generation(sdp)   (le32_to_cpu((sdp)->u.sd_generation))
-#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
-#define sd_v2_attrs(sdp)         (le16_to_cpu((sdp)->sd_attrs))
-#define set_sd_v2_attrs(sdp,v)   ((sdp)->sd_attrs = cpu_to_le16(v))
-
-/***************************************************************************/
-/*                      DIRECTORY STRUCTURE                                */
-/***************************************************************************/
-/* 
-   Picture represents the structure of directory items
-   ________________________________________________
-   |  Array of     |   |     |        |       |   |
-   | directory     |N-1| N-2 | ....   |   1st |0th|
-   | entry headers |   |     |        |       |   |
-   |_______________|___|_____|________|_______|___|
-                    <----   directory entries         ------>
-
- First directory item has k_offset component 1. We store "." and ".."
- in one item, always, we never split "." and ".." into differing
- items.  This makes, among other things, the code for removing
- directories simpler. */
-#define SD_OFFSET  0
-#define SD_UNIQUENESS 0
-#define DOT_OFFSET 1
-#define DOT_DOT_OFFSET 2
-#define DIRENTRY_UNIQUENESS 500
-
-/* */
-#define FIRST_ITEM_OFFSET 1
-
-/*
-   Q: How to get key of object pointed to by entry from entry?  
-
-   A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
-      of object, entry points to */
-
-/* NOT IMPLEMENTED:   
-   Directory will someday contain stat data of object */
-
-struct reiserfs_de_head {
-       __le32 deh_offset;      /* third component of the directory entry key */
-       __le32 deh_dir_id;      /* objectid of the parent directory of the object, that is referenced
-                                  by directory entry */
-       __le32 deh_objectid;    /* objectid of the object, that is referenced by directory entry */
-       __le16 deh_location;    /* offset of name in the whole item */
-       __le16 deh_state;       /* whether 1) entry contains stat data (for future), and 2) whether
-                                  entry is hidden (unlinked) */
-} __attribute__ ((__packed__));
-#define DEH_SIZE                  sizeof(struct reiserfs_de_head)
-#define deh_offset(p_deh)         (le32_to_cpu((p_deh)->deh_offset))
-#define deh_dir_id(p_deh)         (le32_to_cpu((p_deh)->deh_dir_id))
-#define deh_objectid(p_deh)       (le32_to_cpu((p_deh)->deh_objectid))
-#define deh_location(p_deh)       (le16_to_cpu((p_deh)->deh_location))
-#define deh_state(p_deh)          (le16_to_cpu((p_deh)->deh_state))
-
-#define put_deh_offset(p_deh,v)   ((p_deh)->deh_offset = cpu_to_le32((v)))
-#define put_deh_dir_id(p_deh,v)   ((p_deh)->deh_dir_id = cpu_to_le32((v)))
-#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
-#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
-#define put_deh_state(p_deh,v)    ((p_deh)->deh_state = cpu_to_le16((v)))
-
-/* empty directory contains two entries "." and ".." and their headers */
-#define EMPTY_DIR_SIZE \
-(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
-
-/* old format directories have this size when empty */
-#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
-
-#define DEH_Statdata 0         /* not used now */
-#define DEH_Visible 2
-
-/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
-#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
-#   define ADDR_UNALIGNED_BITS  (3)
-#endif
-
-/* These are only used to manipulate deh_state.
- * Because of this, we'll use the ext2_ bit routines,
- * since they are little endian */
-#ifdef ADDR_UNALIGNED_BITS
-
-#   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
-#   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
-
-#   define set_bit_unaligned(nr, addr) \
-       __test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define clear_bit_unaligned(nr, addr)       \
-       __test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define test_bit_unaligned(nr, addr)        \
-       test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
-
-#else
-
-#   define set_bit_unaligned(nr, addr) __test_and_set_bit_le(nr, addr)
-#   define clear_bit_unaligned(nr, addr)       __test_and_clear_bit_le(nr, addr)
-#   define test_bit_unaligned(nr, addr)        test_bit_le(nr, addr)
-
-#endif
-
-#define mark_de_with_sd(deh)        set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define mark_de_without_sd(deh)     clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define mark_de_visible(deh)       set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-#define mark_de_hidden(deh)        clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-
-#define de_with_sd(deh)                    test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
-#define de_visible(deh)                    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-#define de_hidden(deh)             !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-
-extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
-                                  __le32 par_dirid, __le32 par_objid);
-extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
-                               __le32 par_dirid, __le32 par_objid);
-
-/* array of the entry headers */
- /* get item body */
-#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
-#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
-
-/* length of the directory entry in directory item. This define
-   calculates length of i-th directory entry using directory entry
-   locations from dir entry head. When it calculates length of 0-th
-   directory entry, it uses length of whole item in place of entry
-   location of the non-existent following entry in the calculation.
-   See picture above.*/
-/*
-#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
-((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
-*/
-static inline int entry_length(const struct buffer_head *bh,
-                              const struct item_head *ih, int pos_in_item)
-{
-       struct reiserfs_de_head *deh;
-
-       deh = B_I_DEH(bh, ih) + pos_in_item;
-       if (pos_in_item)
-               return deh_location(deh - 1) - deh_location(deh);
-
-       return ih_item_len(ih) - deh_location(deh);
-}
-
-/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
-#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
-
-/* name by bh, ih and entry_num */
-#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
-
-// two entries per block (at least)
-#define REISERFS_MAX_NAME(block_size) 255
-
-/* this structure is used for operations on directory entries. It is
-   not a disk structure. */
-/* When reiserfs_find_entry or search_by_entry_key find directory
-   entry, they return filled reiserfs_dir_entry structure */
-struct reiserfs_dir_entry {
-       struct buffer_head *de_bh;
-       int de_item_num;
-       struct item_head *de_ih;
-       int de_entry_num;
-       struct reiserfs_de_head *de_deh;
-       int de_entrylen;
-       int de_namelen;
-       char *de_name;
-       unsigned long *de_gen_number_bit_string;
-
-       __u32 de_dir_id;
-       __u32 de_objectid;
-
-       struct cpu_key de_entry_key;
-};
-
-/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
-
-/* pointer to file name, stored in entry */
-#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
-
-/* length of name */
-#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
-(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
-
-/* hash value occupies bits from 7 up to 30 */
-#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
-/* generation number occupies 7 bits starting from 0 up to 6 */
-#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
-#define MAX_GENERATION_NUMBER  127
-
-#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
-
-/*
- * Picture represents an internal node of the reiserfs tree
- *  ______________________________________________________
- * |      |  Array of     |  Array of         |  Free     |
- * |block |    keys       |  pointers         | space     |
- * | head |      N        |      N+1          |           |
- * |______|_______________|___________________|___________|
- */
-
-/***************************************************************************/
-/*                      DISK CHILD                                         */
-/***************************************************************************/
-/* Disk child pointer: The pointer from an internal node of the tree
-   to a node that is on disk. */
-struct disk_child {
-       __le32 dc_block_number; /* Disk child's block number. */
-       __le16 dc_size;         /* Disk child's used space.   */
-       __le16 dc_reserved;
-};
-
-#define DC_SIZE (sizeof(struct disk_child))
-#define dc_block_number(dc_p)  (le32_to_cpu((dc_p)->dc_block_number))
-#define dc_size(dc_p)          (le16_to_cpu((dc_p)->dc_size))
-#define put_dc_block_number(dc_p, val)   do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0)
-#define put_dc_size(dc_p, val)   do { (dc_p)->dc_size = cpu_to_le16(val); } while(0)
-
-/* Get disk child by buffer header and position in the tree node. */
-#define B_N_CHILD(bh, n_pos)  ((struct disk_child *)\
-((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos)))
-
-/* Get disk child number by buffer header and position in the tree node. */
-#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos)))
-#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \
-                               (put_dc_block_number(B_N_CHILD(bh, n_pos), val))
-
- /* maximal value of field child_size in structure disk_child */
- /* child size is the combined size of all items and their headers */
-#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
-
-/* amount of used space in buffer (not including block head) */
-#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
-
-/* max and min number of keys in internal node */
-#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
-#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
-
-/***************************************************************************/
-/*                      PATH STRUCTURES AND DEFINES                        */
-/***************************************************************************/
-
-/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
-   key.  It uses reiserfs_bread to try to find buffers in the cache given their block number.  If it
-   does not find them in the cache it reads them from disk.  For each node search_by_key finds using
-   reiserfs_bread it then uses bin_search to look through that node.  bin_search will find the
-   position of the block_number of the next node if it is looking through an internal node.  If it
-   is looking through a leaf node bin_search will find the position of the item which has key either
-   equal to given key, or which is the maximal key less than the given key. */
-
-struct path_element {
-       struct buffer_head *pe_buffer;  /* Pointer to the buffer at the path in the tree. */
-       int pe_position;        /* Position in the tree node which is placed in the */
-       /* buffer above.                                  */
-};
-
-#define MAX_HEIGHT 5           /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
-#define EXTENDED_MAX_HEIGHT         7  /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
-#define FIRST_PATH_ELEMENT_OFFSET   2  /* Must be equal to at least 2. */
-
-#define ILLEGAL_PATH_ELEMENT_OFFSET 1  /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
-#define MAX_FEB_SIZE 6         /* this MUST be MAX_HEIGHT + 1. See about FEB below */
-
-/* We need to keep track of who the ancestors of nodes are.  When we
-   perform a search we record which nodes were visited while
-   descending the tree looking for the node we searched for. This list
-   of nodes is called the path.  This information is used while
-   performing balancing.  Note that this path information may become
-   invalid, and this means we must check it when using it to see if it
-   is still valid. You'll need to read search_by_key and the comments
-   in it, especially about decrement_counters_in_path(), to understand
-   this structure.  
-
-Paths make the code so much harder to work with and debug.... An
-enormous number of bugs are due to them, and trying to write or modify
-code that uses them just makes my head hurt.  They are based on an
-excessive effort to avoid disturbing the precious VFS code.:-( The
-gods only know how we are going to SMP the code that uses them.
-znodes are the way! */
-
-#define PATH_READA     0x1     /* do read ahead */
-#define PATH_READA_BACK 0x2    /* read backwards */
-
-struct treepath {
-       int path_length;        /* Length of the array above.   */
-       int reada;
-       struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements.  */
-       int pos_in_item;
-};
-
-#define pos_in_item(path) ((path)->pos_in_item)
-
-#define INITIALIZE_PATH(var) \
-struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
-
-/* Get path element by path and path position. */
-#define PATH_OFFSET_PELEMENT(path, n_offset)  ((path)->path_elements + (n_offset))
-
-/* Get buffer header at the path by path and path position. */
-#define PATH_OFFSET_PBUFFER(path, n_offset)   (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer)
-
-/* Get position in the element at the path by path and path position. */
-#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position)
-
-#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length))
-                               /* you know, to the person who didn't
-                                  write this the macro name does not
-                                  at first suggest what it does.
-                                  Maybe POSITION_FROM_PATH_END? Or
-                                  maybe we should just focus on
-                                  dumping paths... -Hans */
-#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length))
-
-#define PATH_PITEM_HEAD(path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path))
-
-/* in do_balance leaf has h == 0 in contrast with path structure,
-   where root has level == 0. That is why we need these defines */
-#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h))    /* tb->S[h] */
-#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
-#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
-#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)      /* tb->S[h]->b_item_order */
-
-#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h))
-
-#define get_last_bh(path) PATH_PLAST_BUFFER(path)
-#define get_ih(path) PATH_PITEM_HEAD(path)
-#define get_item_pos(path) PATH_LAST_POSITION(path)
-#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
-#define item_moved(ih,path) comp_items(ih, path)
-#define path_changed(ih,path) comp_items (ih, path)
-
-/***************************************************************************/
-/*                       MISC                                              */
-/***************************************************************************/
-
-/* Size of pointer to the unformatted node. */
-#define UNFM_P_SIZE (sizeof(unp_t))
-#define UNFM_P_SHIFT 2
-
-// in in-core inode key is stored on le form
-#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
-
-#define MAX_UL_INT 0xffffffff
-#define MAX_INT    0x7ffffff
-#define MAX_US_INT 0xffff
-
-// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
-#define U32_MAX (~(__u32)0)
-
-static inline loff_t max_reiserfs_offset(struct inode *inode)
-{
-       if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
-               return (loff_t) U32_MAX;
-
-       return (loff_t) ((~(__u64) 0) >> 4);
-}
-
-/*#define MAX_KEY_UNIQUENESS   MAX_UL_INT*/
-#define MAX_KEY_OBJECTID       MAX_UL_INT
-
-#define MAX_B_NUM  MAX_UL_INT
-#define MAX_FC_NUM MAX_US_INT
-
-/* the purpose is to detect overflow of an unsigned short */
-#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
-
-/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
-#define REISERFS_KERNEL_MEM            0       /* reiserfs kernel memory mode  */
-#define REISERFS_USER_MEM              1       /* reiserfs user memory mode            */
-
-#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
-#define get_generation(s) atomic_read (&fs_generation(s))
-#define FILESYSTEM_CHANGED_TB(tb)  (get_generation((tb)->tb_sb) != (tb)->fs_gen)
-#define __fs_changed(gen,s) (gen != get_generation (s))
-#define fs_changed(gen,s)              \
-({                                     \
-       reiserfs_cond_resched(s);       \
-       __fs_changed(gen, s);           \
-})
-
-/***************************************************************************/
-/*                  FIXATE NODES                                           */
-/***************************************************************************/
-
-#define VI_TYPE_LEFT_MERGEABLE 1
-#define VI_TYPE_RIGHT_MERGEABLE 2
-
-/* To make any changes in the tree we always first find node, that
-   contains item to be changed/deleted or place to insert a new
-   item. We call this node S. To do balancing we need to decide what
-   we will shift to left/right neighbor, or to a new node, where new
-   item will be etc. To make this analysis simpler we build virtual
-   node. Virtual node is an array of items, that will replace items of
-   node S. (For instance if we are going to delete an item, virtual
-   node does not contain it). Virtual node keeps information about
-   item sizes and types, mergeability of first and last items, sizes
-   of all entries in directory item. We use this array of items when
-   calculating what we can shift to neighbors and how many nodes we
-   have to have if we do not any shiftings, if we shift to left/right
-   neighbor or to both. */
-struct virtual_item {
-       int vi_index;           // index in the array of item operations
-       unsigned short vi_type; // left/right mergeability
-       unsigned short vi_item_len;     /* length of item that it will have after balancing */
-       struct item_head *vi_ih;
-       const char *vi_item;    // body of item (old or new)
-       const void *vi_new_data;        // 0 always but paste mode
-       void *vi_uarea;         // item specific area
-};
-
-struct virtual_node {
-       char *vn_free_ptr;      /* this is a pointer to the free space in the buffer */
-       unsigned short vn_nr_item;      /* number of items in virtual node */
-       short vn_size;          /* size of node , that node would have if it has unlimited size and no balancing is performed */
-       short vn_mode;          /* mode of balancing (paste, insert, delete, cut) */
-       short vn_affected_item_num;
-       short vn_pos_in_item;
-       struct item_head *vn_ins_ih;    /* item header of inserted item, 0 for other modes */
-       const void *vn_data;
-       struct virtual_item *vn_vi;     /* array of items (including a new one, excluding item to be deleted) */
-};
-
-/* used by directory items when creating virtual nodes */
-struct direntry_uarea {
-       int flags;
-       __u16 entry_count;
-       __u16 entry_sizes[1];
-} __attribute__ ((__packed__));
-
-/***************************************************************************/
-/*                  TREE BALANCE                                           */
-/***************************************************************************/
-
-/* This temporary structure is used in tree balance algorithms, and
-   constructed as we go to the extent that its various parts are
-   needed.  It contains arrays of nodes that can potentially be
-   involved in the balancing of node S, and parameters that define how
-   each of the nodes must be balanced.  Note that in these algorithms
-   for balancing the worst case is to need to balance the current node
-   S and the left and right neighbors and all of their parents plus
-   create a new node.  We implement S1 balancing for the leaf nodes
-   and S0 balancing for the internal nodes (S1 and S0 are defined in
-   our papers.)*/
-
-#define MAX_FREE_BLOCK 7       /* size of the array of buffers to free at end of do_balance */
-
-/* maximum number of FEB blocknrs on a single level */
-#define MAX_AMOUNT_NEEDED 2
-
-/* someday somebody will prefix every field in this struct with tb_ */
-struct tree_balance {
-       int tb_mode;
-       int need_balance_dirty;
-       struct super_block *tb_sb;
-       struct reiserfs_transaction_handle *transaction_handle;
-       struct treepath *tb_path;
-       struct buffer_head *L[MAX_HEIGHT];      /* array of left neighbors of nodes in the path */
-       struct buffer_head *R[MAX_HEIGHT];      /* array of right neighbors of nodes in the path */
-       struct buffer_head *FL[MAX_HEIGHT];     /* array of fathers of the left  neighbors      */
-       struct buffer_head *FR[MAX_HEIGHT];     /* array of fathers of the right neighbors      */
-       struct buffer_head *CFL[MAX_HEIGHT];    /* array of common parents of center node and its left neighbor  */
-       struct buffer_head *CFR[MAX_HEIGHT];    /* array of common parents of center node and its right neighbor */
-
-       struct buffer_head *FEB[MAX_FEB_SIZE];  /* array of empty buffers. Number of buffers in array equals
-                                                  cur_blknum. */
-       struct buffer_head *used[MAX_FEB_SIZE];
-       struct buffer_head *thrown[MAX_FEB_SIZE];
-       int lnum[MAX_HEIGHT];   /* array of number of items which must be
-                                  shifted to the left in order to balance the
-                                  current node; for leaves includes item that
-                                  will be partially shifted; for internal
-                                  nodes, it is the number of child pointers
-                                  rather than items. It includes the new item
-                                  being created. The code sometimes subtracts
-                                  one to get the number of wholly shifted
-                                  items for other purposes. */
-       int rnum[MAX_HEIGHT];   /* substitute right for left in comment above */
-       int lkey[MAX_HEIGHT];   /* array indexed by height h mapping the key delimiting L[h] and
-                                  S[h] to its item number within the node CFL[h] */
-       int rkey[MAX_HEIGHT];   /* substitute r for l in comment above */
-       int insert_size[MAX_HEIGHT];    /* the number of bytes by we are trying to add or remove from
-                                          S[h]. A negative value means removing.  */
-       int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
-                                  balancing on the level h of the tree.  If 0 then S is
-                                  being deleted, if 1 then S is remaining and no new nodes
-                                  are being created, if 2 or 3 then 1 or 2 new nodes is
-                                  being created */
-
-       /* fields that are used only for balancing leaves of the tree */
-       int cur_blknum;         /* number of empty blocks having been already allocated                 */
-       int s0num;              /* number of items that fall into left most  node when S[0] splits     */
-       int s1num;              /* number of items that fall into first  new node when S[0] splits     */
-       int s2num;              /* number of items that fall into second new node when S[0] splits     */
-       int lbytes;             /* number of bytes which can flow to the left neighbor from the        left    */
-       /* most liquid item that cannot be shifted from S[0] entirely         */
-       /* if -1 then nothing will be partially shifted */
-       int rbytes;             /* number of bytes which will flow to the right neighbor from the right        */
-       /* most liquid item that cannot be shifted from S[0] entirely         */
-       /* if -1 then nothing will be partially shifted                           */
-       int s1bytes;            /* number of bytes which flow to the first  new node when S[0] splits   */
-       /* note: if S[0] splits into 3 nodes, then items do not need to be cut  */
-       int s2bytes;
-       struct buffer_head *buf_to_free[MAX_FREE_BLOCK];        /* buffers which are to be freed after do_balance finishes by unfix_nodes */
-       char *vn_buf;           /* kmalloced memory. Used to create
-                                  virtual node and keep map of
-                                  dirtied bitmap blocks */
-       int vn_buf_size;        /* size of the vn_buf */
-       struct virtual_node *tb_vn;     /* VN starts after bitmap of bitmap blocks */
-
-       int fs_gen;             /* saved value of `reiserfs_generation' counter
-                                  see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
-#ifdef DISPLACE_NEW_PACKING_LOCALITIES
-       struct in_core_key key; /* key pointer, to pass to block allocator or
-                                  another low-level subsystem */
-#endif
-};
-
-/* These are modes of balancing */
-
-/* When inserting an item. */
-#define M_INSERT       'i'
-/* When inserting into (directories only) or appending onto an already
-   existent item. */
-#define M_PASTE                'p'
-/* When deleting an item. */
-#define M_DELETE       'd'
-/* When truncating an item or removing an entry from a (directory) item. */
-#define M_CUT          'c'
-
-/* used when balancing on leaf level skipped (in reiserfsck) */
-#define M_INTERNAL     'n'
-
-/* When further balancing is not needed, then do_balance does not need
-   to be called. */
-#define M_SKIP_BALANCING               's'
-#define M_CONVERT      'v'
-
-/* modes of leaf_move_items */
-#define LEAF_FROM_S_TO_L 0
-#define LEAF_FROM_S_TO_R 1
-#define LEAF_FROM_R_TO_L 2
-#define LEAF_FROM_L_TO_R 3
-#define LEAF_FROM_S_TO_SNEW 4
-
-#define FIRST_TO_LAST 0
-#define LAST_TO_FIRST 1
-
-/* used in do_balance for passing parent of node information that has
-   been gotten from tb struct */
-struct buffer_info {
-       struct tree_balance *tb;
-       struct buffer_head *bi_bh;
-       struct buffer_head *bi_parent;
-       int bi_position;
-};
-
-static inline struct super_block *sb_from_tb(struct tree_balance *tb)
-{
-       return tb ? tb->tb_sb : NULL;
-}
-
-static inline struct super_block *sb_from_bi(struct buffer_info *bi)
-{
-       return bi ? sb_from_tb(bi->tb) : NULL;
-}
-
-/* there are 4 types of items: stat data, directory item, indirect, direct.
-+-------------------+------------+--------------+------------+
-|                  |  k_offset  | k_uniqueness | mergeable? |
-+-------------------+------------+--------------+------------+
-|     stat data     |  0        |      0       |   no       |
-+-------------------+------------+--------------+------------+
-| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
-| non 1st directory | hash value |              |   yes      |
-|     item          |            |              |            |
-+-------------------+------------+--------------+------------+
-| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
-+-------------------+------------+--------------+------------+
-| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
-+-------------------+------------+--------------+------------+
-*/
-
-struct item_operations {
-       int (*bytes_number) (struct item_head * ih, int block_size);
-       void (*decrement_key) (struct cpu_key *);
-       int (*is_left_mergeable) (struct reiserfs_key * ih,
-                                 unsigned long bsize);
-       void (*print_item) (struct item_head *, char *item);
-       void (*check_item) (struct item_head *, char *item);
-
-       int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
-                         int is_affected, int insert_size);
-       int (*check_left) (struct virtual_item * vi, int free,
-                          int start_skip, int end_skip);
-       int (*check_right) (struct virtual_item * vi, int free);
-       int (*part_size) (struct virtual_item * vi, int from, int to);
-       int (*unit_num) (struct virtual_item * vi);
-       void (*print_vi) (struct virtual_item * vi);
-};
-
-extern struct item_operations *item_ops[TYPE_ANY + 1];
-
-#define op_bytes_number(ih,bsize)                    item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
-#define op_is_left_mergeable(key,bsize)              item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
-#define op_print_item(ih,item)                       item_ops[le_ih_k_type (ih)]->print_item (ih, item)
-#define op_check_item(ih,item)                       item_ops[le_ih_k_type (ih)]->check_item (ih, item)
-#define op_create_vi(vn,vi,is_affected,insert_size)  item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
-#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
-#define op_check_right(vi,free)                      item_ops[(vi)->vi_index]->check_right (vi, free)
-#define op_part_size(vi,from,to)                     item_ops[(vi)->vi_index]->part_size (vi, from, to)
-#define op_unit_num(vi)                                     item_ops[(vi)->vi_index]->unit_num (vi)
-#define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
-
-#define COMP_SHORT_KEYS comp_short_keys
-
-/* number of blocks pointed to by the indirect item */
-#define I_UNFM_NUM(ih) (ih_item_len(ih) / UNFM_P_SIZE)
-
-/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
-#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
-
-/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
-
-/* get the item header */
-#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
-
-/* get key */
-#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
-
-/* get the key */
-#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
-
-/* get item body */
-#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
-
-/* get the stat data by the buffer header and the item order */
-#define B_N_STAT_DATA(bh,nr) \
-( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
-
-    /* following defines use reiserfs buffer header and item header */
-
-/* get stat-data */
-#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
-
-// this is 3976 for size==4096
-#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
-
-/* indirect items consist of entries which contain blocknrs, pos
-   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
-   blocknr contained by the entry pos points to */
-#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
-#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
-
-struct reiserfs_iget_args {
-       __u32 objectid;
-       __u32 dirid;
-};
-
-/***************************************************************************/
-/*                    FUNCTION DECLARATIONS                                */
-/***************************************************************************/
-
-#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
-
-#define journal_trans_half(blocksize) \
-       ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
-
-/* journal.c see journal.c for all the comments here */
-
-/* first block written in a commit.  */
-struct reiserfs_journal_desc {
-       __le32 j_trans_id;      /* id of commit */
-       __le32 j_len;           /* length of commit. len +1 is the commit block */
-       __le32 j_mount_id;      /* mount id of this trans */
-       __le32 j_realblock[1];  /* real locations for each block */
-};
-
-#define get_desc_trans_id(d)   le32_to_cpu((d)->j_trans_id)
-#define get_desc_trans_len(d)  le32_to_cpu((d)->j_len)
-#define get_desc_mount_id(d)   le32_to_cpu((d)->j_mount_id)
-
-#define set_desc_trans_id(d,val)       do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
-#define set_desc_trans_len(d,val)      do { (d)->j_len = cpu_to_le32 (val); } while (0)
-#define set_desc_mount_id(d,val)       do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
-
-/* last block written in a commit */
-struct reiserfs_journal_commit {
-       __le32 j_trans_id;      /* must match j_trans_id from the desc block */
-       __le32 j_len;           /* ditto */
-       __le32 j_realblock[1];  /* real locations for each block */
-};
-
-#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
-#define get_commit_trans_len(c)        le32_to_cpu((c)->j_len)
-#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
-
-#define set_commit_trans_id(c,val)     do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
-#define set_commit_trans_len(c,val)    do { (c)->j_len = cpu_to_le32 (val); } while (0)
-
-/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
-** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
-** and this transaction does not need to be replayed.
-*/
-struct reiserfs_journal_header {
-       __le32 j_last_flush_trans_id;   /* id of last fully flushed transaction */
-       __le32 j_first_unflushed_offset;        /* offset in the log of where to start replay after a crash */
-       __le32 j_mount_id;
-       /* 12 */ struct journal_params jh_journal;
-};
-
-/* biggest tunable defines are right here */
-#define JOURNAL_BLOCK_COUNT 8192       /* number of blocks in the journal */
-#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
-#define JOURNAL_TRANS_MIN_DEFAULT 256
-#define JOURNAL_MAX_BATCH_DEFAULT   900        /* max blocks to batch into one transaction, don't make this any bigger than 900 */
-#define JOURNAL_MIN_RATIO 2
-#define JOURNAL_MAX_COMMIT_AGE 30
-#define JOURNAL_MAX_TRANS_AGE 30
-#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
-#define JOURNAL_BLOCKS_PER_OBJECT(sb)  (JOURNAL_PER_BALANCE_CNT * 3 + \
-                                        2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \
-                                             REISERFS_QUOTA_TRANS_BLOCKS(sb)))
-
-#ifdef CONFIG_QUOTA
-#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA))
-/* We need to update data and inode (atime) */
-#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0)
-/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
-#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
-(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
-/* same as with INIT */
-#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \
-(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
-#else
-#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
-#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
-#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
-#endif
-
-/* both of these can be as low as 1, or as high as you want.  The min is the
-** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
-** as needed, and released when transactions are committed.  On release, if 
-** the current number of nodes is > max, the node is freed, otherwise, 
-** it is put on a free list for faster use later.
-*/
-#define REISERFS_MIN_BITMAP_NODES 10
-#define REISERFS_MAX_BITMAP_NODES 100
-
-#define JBH_HASH_SHIFT 13      /* these are based on journal hash size of 8192 */
-#define JBH_HASH_MASK 8191
-
-#define _jhashfn(sb,block)     \
-       (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
-        (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
-#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
-
-// We need these to make journal.c code more readable
-#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
-
-enum reiserfs_bh_state_bits {
-       BH_JDirty = BH_PrivateStart,    /* buffer is in current transaction */
-       BH_JDirty_wait,
-       BH_JNew,                /* disk block was taken off free list before
-                                * being in a finished transaction, or
-                                * written to disk. Can be reused immed. */
-       BH_JPrepared,
-       BH_JRestore_dirty,
-       BH_JTest,               // debugging only will go away
-};
-
-BUFFER_FNS(JDirty, journaled);
-TAS_BUFFER_FNS(JDirty, journaled);
-BUFFER_FNS(JDirty_wait, journal_dirty);
-TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
-BUFFER_FNS(JNew, journal_new);
-TAS_BUFFER_FNS(JNew, journal_new);
-BUFFER_FNS(JPrepared, journal_prepared);
-TAS_BUFFER_FNS(JPrepared, journal_prepared);
-BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
-TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
-BUFFER_FNS(JTest, journal_test);
-TAS_BUFFER_FNS(JTest, journal_test);
-
-/*
-** transaction handle which is passed around for all journal calls
-*/
-struct reiserfs_transaction_handle {
-       struct super_block *t_super;    /* super for this FS when journal_begin was
-                                          called. saves calls to reiserfs_get_super
-                                          also used by nested transactions to make
-                                          sure they are nesting on the right FS
-                                          _must_ be first in the handle
-                                        */
-       int t_refcount;
-       int t_blocks_logged;    /* number of blocks this writer has logged */
-       int t_blocks_allocated; /* number of blocks this writer allocated */
-       unsigned int t_trans_id;        /* sanity check, equals the current trans id */
-       void *t_handle_save;    /* save existing current->journal_info */
-       unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
-                                          should be displaced from others */
-       struct list_head t_list;
-};
-
-/* used to keep track of ordered and tail writes, attached to the buffer
- * head through b_journal_head.
- */
-struct reiserfs_jh {
-       struct reiserfs_journal_list *jl;
-       struct buffer_head *bh;
-       struct list_head list;
-};
-
-void reiserfs_free_jh(struct buffer_head *bh);
-int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
-int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
-int journal_mark_dirty(struct reiserfs_transaction_handle *,
-                      struct super_block *, struct buffer_head *bh);
-
-static inline int reiserfs_file_data_log(struct inode *inode)
-{
-       if (reiserfs_data_log(inode->i_sb) ||
-           (REISERFS_I(inode)->i_flags & i_data_log))
-               return 1;
-       return 0;
-}
-
-static inline int reiserfs_transaction_running(struct super_block *s)
-{
-       struct reiserfs_transaction_handle *th = current->journal_info;
-       if (th && th->t_super == s)
-               return 1;
-       if (th && th->t_super == NULL)
-               BUG();
-       return 0;
-}
-
-static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th)
-{
-       return th->t_blocks_allocated - th->t_blocks_logged;
-}
-
-struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
-                                                                   super_block
-                                                                   *,
-                                                                   int count);
-int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
-int reiserfs_commit_page(struct inode *inode, struct page *page,
-                        unsigned from, unsigned to);
-int reiserfs_flush_old_commits(struct super_block *);
-int reiserfs_commit_for_inode(struct inode *);
-int reiserfs_inode_needs_commit(struct inode *);
-void reiserfs_update_inode_transaction(struct inode *);
-void reiserfs_wait_on_write_block(struct super_block *s);
-void reiserfs_block_writes(struct reiserfs_transaction_handle *th);
-void reiserfs_allow_writes(struct super_block *s);
-void reiserfs_check_lock_depth(struct super_block *s, char *caller);
-int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh,
-                                int wait);
-void reiserfs_restore_prepared_buffer(struct super_block *,
-                                     struct buffer_head *bh);
-int journal_init(struct super_block *, const char *j_dev_name, int old_format,
-                unsigned int);
-int journal_release(struct reiserfs_transaction_handle *, struct super_block *);
-int journal_release_error(struct reiserfs_transaction_handle *,
-                         struct super_block *);
-int journal_end(struct reiserfs_transaction_handle *, struct super_block *,
-               unsigned long);
-int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
-                    unsigned long);
-int journal_mark_freed(struct reiserfs_transaction_handle *,
-                      struct super_block *, b_blocknr_t blocknr);
-int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
-int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr,
-                        int bit_nr, int searchall, b_blocknr_t *next);
-int journal_begin(struct reiserfs_transaction_handle *,
-                 struct super_block *sb, unsigned long);
-int journal_join_abort(struct reiserfs_transaction_handle *,
-                      struct super_block *sb, unsigned long);
-void reiserfs_abort_journal(struct super_block *sb, int errno);
-void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
-int reiserfs_allocate_list_bitmaps(struct super_block *s,
-                                  struct reiserfs_list_bitmap *, unsigned int);
-
-void add_save_link(struct reiserfs_transaction_handle *th,
-                  struct inode *inode, int truncate);
-int remove_save_link(struct inode *inode, int truncate);
-
-/* objectid.c */
-__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th);
-void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
-                              __u32 objectid_to_release);
-int reiserfs_convert_objectid_map_v1(struct super_block *);
-
-/* stree.c */
-int B_IS_IN_TREE(const struct buffer_head *);
-extern void copy_item_head(struct item_head *to,
-                          const struct item_head *from);
-
-// first key is in cpu form, second - le
-extern int comp_short_keys(const struct reiserfs_key *le_key,
-                          const struct cpu_key *cpu_key);
-extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from);
-
-// both are in le form
-extern int comp_le_keys(const struct reiserfs_key *,
-                       const struct reiserfs_key *);
-extern int comp_short_le_keys(const struct reiserfs_key *,
-                             const struct reiserfs_key *);
-
-//
-// get key version from on disk key - kludge
-//
-static inline int le_key_version(const struct reiserfs_key *key)
-{
-       int type;
-
-       type = offset_v2_k_type(&(key->u.k_offset_v2));
-       if (type != TYPE_DIRECT && type != TYPE_INDIRECT
-           && type != TYPE_DIRENTRY)
-               return KEY_FORMAT_3_5;
-
-       return KEY_FORMAT_3_6;
-
-}
-
-static inline void copy_key(struct reiserfs_key *to,
-                           const struct reiserfs_key *from)
-{
-       memcpy(to, from, KEY_SIZE);
-}
-
-int comp_items(const struct item_head *stored_ih, const struct treepath *path);
-const struct reiserfs_key *get_rkey(const struct treepath *chk_path,
-                                   const struct super_block *sb);
-int search_by_key(struct super_block *, const struct cpu_key *,
-                 struct treepath *, int);
-#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
-int search_for_position_by_key(struct super_block *sb,
-                              const struct cpu_key *cpu_key,
-                              struct treepath *search_path);
-extern void decrement_bcount(struct buffer_head *bh);
-void decrement_counters_in_path(struct treepath *search_path);
-void pathrelse(struct treepath *search_path);
-int reiserfs_check_path(struct treepath *p);
-void pathrelse_and_restore(struct super_block *s, struct treepath *search_path);
-
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
-                        struct treepath *path,
-                        const struct cpu_key *key,
-                        struct item_head *ih,
-                        struct inode *inode, const char *body);
-
-int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
-                            struct treepath *path,
-                            const struct cpu_key *key,
-                            struct inode *inode,
-                            const char *body, int paste_size);
-
-int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
-                          struct treepath *path,
-                          struct cpu_key *key,
-                          struct inode *inode,
-                          struct page *page, loff_t new_file_size);
-
-int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
-                        struct treepath *path,
-                        const struct cpu_key *key,
-                        struct inode *inode, struct buffer_head *un_bh);
-
-void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
-                               struct inode *inode, struct reiserfs_key *key);
-int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
-                          struct inode *inode);
-int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
-                        struct inode *inode, struct page *,
-                        int update_timestamps);
-
-#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
-#define file_size(inode) ((inode)->i_size)
-#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
-
-#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
-!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
-
-void padd_item(char *item, int total_length, int length);
-
-/* inode.c */
-/* args for the create parameter of reiserfs_get_block */
-#define GET_BLOCK_NO_CREATE 0  /* don't create new blocks or convert tails */
-#define GET_BLOCK_CREATE 1     /* add anything you need to find block */
-#define GET_BLOCK_NO_HOLE 2    /* return -ENOENT for file holes */
-#define GET_BLOCK_READ_DIRECT 4        /* read the tail if indirect item not found */
-#define GET_BLOCK_NO_IMUX     8        /* i_mutex is not held, don't preallocate */
-#define GET_BLOCK_NO_DANGLE   16       /* don't leave any transactions running */
-
-void reiserfs_read_locked_inode(struct inode *inode,
-                               struct reiserfs_iget_args *args);
-int reiserfs_find_actor(struct inode *inode, void *p);
-int reiserfs_init_locked_inode(struct inode *inode, void *p);
-void reiserfs_evict_inode(struct inode *inode);
-int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc);
-int reiserfs_get_block(struct inode *inode, sector_t block,
-                      struct buffer_head *bh_result, int create);
-struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
-                                    int fh_len, int fh_type);
-struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
-                                    int fh_len, int fh_type);
-int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
-                      int connectable);
-
-int reiserfs_truncate_file(struct inode *, int update_timestamps);
-void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
-                 int type, int key_length);
-void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
-                      int version,
-                      loff_t offset, int type, int length, int entry_count);
-struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
-
-struct reiserfs_security_handle;
-int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
-                      struct inode *dir, umode_t mode,
-                      const char *symname, loff_t i_size,
-                      struct dentry *dentry, struct inode *inode,
-                      struct reiserfs_security_handle *security);
-
-void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
-                            struct inode *inode, loff_t size);
-
-static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
-                                     struct inode *inode)
-{
-       reiserfs_update_sd_size(th, inode, inode->i_size);
-}
-
-void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
-void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
-int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
-
-int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len);
-
-/* namei.c */
-void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
-int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
-                       struct treepath *path, struct reiserfs_dir_entry *de);
-struct dentry *reiserfs_get_parent(struct dentry *);
-
-#ifdef CONFIG_REISERFS_PROC_INFO
-int reiserfs_proc_info_init(struct super_block *sb);
-int reiserfs_proc_info_done(struct super_block *sb);
-int reiserfs_proc_info_global_init(void);
-int reiserfs_proc_info_global_done(void);
-
-#define PROC_EXP( e )   e
-
-#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data
-#define PROC_INFO_MAX( sb, field, value )                                                              \
-    __PINFO( sb ).field =                                                                                              \
-        max( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
-#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
-#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
-#define PROC_INFO_BH_STAT( sb, bh, level )                                                     \
-    PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] );                                             \
-    PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );     \
-    PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
-#else
-static inline int reiserfs_proc_info_init(struct super_block *sb)
-{
-       return 0;
-}
-
-static inline int reiserfs_proc_info_done(struct super_block *sb)
-{
-       return 0;
-}
-
-static inline int reiserfs_proc_info_global_init(void)
-{
-       return 0;
-}
-
-static inline int reiserfs_proc_info_global_done(void)
-{
-       return 0;
-}
-
-#define PROC_EXP( e )
-#define VOID_V ( ( void ) 0 )
-#define PROC_INFO_MAX( sb, field, value ) VOID_V
-#define PROC_INFO_INC( sb, field ) VOID_V
-#define PROC_INFO_ADD( sb, field, val ) VOID_V
-#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V
-#endif
-
-/* dir.c */
-extern const struct inode_operations reiserfs_dir_inode_operations;
-extern const struct inode_operations reiserfs_symlink_inode_operations;
-extern const struct inode_operations reiserfs_special_inode_operations;
-extern const struct file_operations reiserfs_dir_operations;
-int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
-
-/* tail_conversion.c */
-int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
-                   struct treepath *, struct buffer_head *, loff_t);
-int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
-                   struct page *, struct treepath *, const struct cpu_key *,
-                   loff_t, char *);
-void reiserfs_unmap_buffer(struct buffer_head *);
-
-/* file.c */
-extern const struct inode_operations reiserfs_file_inode_operations;
-extern const struct file_operations reiserfs_file_operations;
-extern const struct address_space_operations reiserfs_address_space_operations;
-
-/* fix_nodes.c */
-
-int fix_nodes(int n_op_mode, struct tree_balance *tb,
-             struct item_head *ins_ih, const void *);
-void unfix_nodes(struct tree_balance *);
-
-/* prints.c */
-void __reiserfs_panic(struct super_block *s, const char *id,
-                     const char *function, const char *fmt, ...)
-    __attribute__ ((noreturn));
-#define reiserfs_panic(s, id, fmt, args...) \
-       __reiserfs_panic(s, id, __func__, fmt, ##args)
-void __reiserfs_error(struct super_block *s, const char *id,
-                     const char *function, const char *fmt, ...);
-#define reiserfs_error(s, id, fmt, args...) \
-        __reiserfs_error(s, id, __func__, fmt, ##args)
-void reiserfs_info(struct super_block *s, const char *fmt, ...);
-void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
-void print_indirect_item(struct buffer_head *bh, int item_num);
-void store_print_tb(struct tree_balance *tb);
-void print_cur_tb(char *mes);
-void print_de(struct reiserfs_dir_entry *de);
-void print_bi(struct buffer_info *bi, char *mes);
-#define PRINT_LEAF_ITEMS 1     /* print all items */
-#define PRINT_DIRECTORY_ITEMS 2        /* print directory items */
-#define PRINT_DIRECT_ITEMS 4   /* print contents of direct items */
-void print_block(struct buffer_head *bh, ...);
-void print_bmap(struct super_block *s, int silent);
-void print_bmap_block(int i, char *data, int size, int silent);
-/*void print_super_block (struct super_block * s, char * mes);*/
-void print_objectid_map(struct super_block *s);
-void print_block_head(struct buffer_head *bh, char *mes);
-void check_leaf(struct buffer_head *bh);
-void check_internal(struct buffer_head *bh);
-void print_statistics(struct super_block *s);
-char *reiserfs_hashname(int code);
-
-/* lbalance.c */
-int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
-                   int mov_bytes, struct buffer_head *Snew);
-int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes);
-int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
-void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
-                      int del_num, int del_bytes);
-void leaf_insert_into_buf(struct buffer_info *bi, int before,
-                         struct item_head *inserted_item_ih,
-                         const char *inserted_item_body, int zeros_number);
-void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
-                         int pos_in_item, int paste_size, const char *body,
-                         int zeros_number);
-void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
-                         int pos_in_item, int cut_size);
-void leaf_paste_entries(struct buffer_info *bi, int item_num, int before,
-                       int new_entry_count, struct reiserfs_de_head *new_dehs,
-                       const char *records, int paste_size);
-/* ibalance.c */
-int balance_internal(struct tree_balance *, int, int, struct item_head *,
-                    struct buffer_head **);
-
-/* do_balance.c */
-void do_balance_mark_leaf_dirty(struct tree_balance *tb,
-                               struct buffer_head *bh, int flag);
-#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
-#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
-
-void do_balance(struct tree_balance *tb, struct item_head *ih,
-               const char *body, int flag);
-void reiserfs_invalidate_buffer(struct tree_balance *tb,
-                               struct buffer_head *bh);
-
-int get_left_neighbor_position(struct tree_balance *tb, int h);
-int get_right_neighbor_position(struct tree_balance *tb, int h);
-void replace_key(struct tree_balance *tb, struct buffer_head *, int,
-                struct buffer_head *, int);
-void make_empty_node(struct buffer_info *);
-struct buffer_head *get_FEB(struct tree_balance *);
-
-/* bitmap.c */
-
-/* structure contains hints for block allocator, and it is a container for
- * arguments, such as node, search path, transaction_handle, etc. */
-struct __reiserfs_blocknr_hint {
-       struct inode *inode;    /* inode passed to allocator, if we allocate unf. nodes */
-       sector_t block;         /* file offset, in blocks */
-       struct in_core_key key;
-       struct treepath *path;  /* search path, used by allocator to deternine search_start by
-                                * various ways */
-       struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
-                                                * bitmap blocks changes  */
-       b_blocknr_t beg, end;
-       b_blocknr_t search_start;       /* a field used to transfer search start value (block number)
-                                        * between different block allocator procedures
-                                        * (determine_search_start() and others) */
-       int prealloc_size;      /* is set in determine_prealloc_size() function, used by underlayed
-                                * function that do actual allocation */
-
-       unsigned formatted_node:1;      /* the allocator uses different polices for getting disk space for
-                                        * formatted/unformatted blocks with/without preallocation */
-       unsigned preallocate:1;
-};
-
-typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
-
-int reiserfs_parse_alloc_options(struct super_block *, char *);
-void reiserfs_init_alloc_options(struct super_block *s);
-
-/*
- * given a directory, this will tell you what packing locality
- * to use for a new object underneat it.  The locality is returned
- * in disk byte order (le).
- */
-__le32 reiserfs_choose_packing(struct inode *dir);
-
-int reiserfs_init_bitmap_cache(struct super_block *sb);
-void reiserfs_free_bitmap_cache(struct super_block *sb);
-void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
-struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
-int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
-void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
-                        b_blocknr_t, int for_unformatted);
-int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int,
-                              int);
-static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
-                                            b_blocknr_t * new_blocknrs,
-                                            int amount_needed)
-{
-       reiserfs_blocknr_hint_t hint = {
-               .th = tb->transaction_handle,
-               .path = tb->tb_path,
-               .inode = NULL,
-               .key = tb->key,
-               .block = 0,
-               .formatted_node = 1
-       };
-       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed,
-                                         0);
-}
-
-static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
-                                           *th, struct inode *inode,
-                                           b_blocknr_t * new_blocknrs,
-                                           struct treepath *path,
-                                           sector_t block)
-{
-       reiserfs_blocknr_hint_t hint = {
-               .th = th,
-               .path = path,
-               .inode = inode,
-               .block = block,
-               .formatted_node = 0,
-               .preallocate = 0
-       };
-       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
-}
-
-#ifdef REISERFS_PREALLOCATE
-static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
-                                            *th, struct inode *inode,
-                                            b_blocknr_t * new_blocknrs,
-                                            struct treepath *path,
-                                            sector_t block)
-{
-       reiserfs_blocknr_hint_t hint = {
-               .th = th,
-               .path = path,
-               .inode = inode,
-               .block = block,
-               .formatted_node = 0,
-               .preallocate = 1
-       };
-       return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
-}
-
-void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
-                              struct inode *inode);
-void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th);
-#endif
-
-/* hashes.c */
-__u32 keyed_hash(const signed char *msg, int len);
-__u32 yura_hash(const signed char *msg, int len);
-__u32 r5_hash(const signed char *msg, int len);
-
-#define reiserfs_set_le_bit            __set_bit_le
-#define reiserfs_test_and_set_le_bit   __test_and_set_bit_le
-#define reiserfs_clear_le_bit          __clear_bit_le
-#define reiserfs_test_and_clear_le_bit __test_and_clear_bit_le
-#define reiserfs_test_le_bit           test_bit_le
-#define reiserfs_find_next_zero_le_bit find_next_zero_bit_le
-
-/* sometimes reiserfs_truncate may require to allocate few new blocks
-   to perform indirect2direct conversion. People probably used to
-   think, that truncate should work without problems on a filesystem
-   without free disk space. They may complain that they can not
-   truncate due to lack of free disk space. This spare space allows us
-   to not worry about it. 500 is probably too much, but it should be
-   absolutely safe */
-#define SPARE_SPACE 500
-
-/* prototypes from ioctl.c */
-long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-long reiserfs_compat_ioctl(struct file *filp,
-                  unsigned int cmd, unsigned long arg);
-int reiserfs_unpack(struct inode *inode, struct file *filp);
-
-#endif /* __KERNEL__ */
-
 #endif                         /* _LINUX_REISER_FS_H */
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
deleted file mode 100644 (file)
index 97959bd..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _REISER_FS_I
-#define _REISER_FS_I
-
-#include <linux/list.h>
-
-struct reiserfs_journal_list;
-
-/** bitmasks for i_flags field in reiserfs-specific part of inode */
-typedef enum {
-    /** this says what format of key do all items (but stat data) of
-      an object have.  If this is set, that format is 3.6 otherwise
-      - 3.5 */
-       i_item_key_version_mask = 0x0001,
-    /** If this is unset, object has 3.5 stat data, otherwise, it has
-      3.6 stat data with 64bit size, 32bit nlink etc. */
-       i_stat_data_version_mask = 0x0002,
-    /** file might need tail packing on close */
-       i_pack_on_close_mask = 0x0004,
-    /** don't pack tail of file */
-       i_nopack_mask = 0x0008,
-    /** If those is set, "safe link" was created for this file during
-      truncate or unlink. Safe link is used to avoid leakage of disk
-      space on crash with some files open, but unlinked. */
-       i_link_saved_unlink_mask = 0x0010,
-       i_link_saved_truncate_mask = 0x0020,
-       i_has_xattr_dir = 0x0040,
-       i_data_log = 0x0080,
-} reiserfs_inode_flags;
-
-struct reiserfs_inode_info {
-       __u32 i_key[4];         /* key is still 4 32 bit integers */
-    /** transient inode flags that are never stored on disk. Bitmasks
-      for this field are defined above. */
-       __u32 i_flags;
-
-       __u32 i_first_direct_byte;      // offset of first byte stored in direct item.
-
-       /* copy of persistent inode flags read from sd_attrs. */
-       __u32 i_attrs;
-
-       int i_prealloc_block;   /* first unused block of a sequence of unused blocks */
-       int i_prealloc_count;   /* length of that sequence */
-       struct list_head i_prealloc_list;       /* per-transaction list of inodes which
-                                                * have preallocated blocks */
-
-       unsigned new_packing_locality:1;        /* new_packig_locality is created; new blocks
-                                                * for the contents of this directory should be
-                                                * displaced */
-
-       /* we use these for fsync or O_SYNC to decide which transaction
-        ** needs to be committed in order for this inode to be properly
-        ** flushed */
-       unsigned int i_trans_id;
-       struct reiserfs_journal_list *i_jl;
-       atomic_t openers;
-       struct mutex tailpack;
-#ifdef CONFIG_REISERFS_FS_XATTR
-       struct rw_semaphore i_xattr_sem;
-#endif
-       struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
deleted file mode 100644 (file)
index 8c9e85c..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/* Copyright 1996-2000 Hans Reiser, see reiserfs/README for licensing
- * and copyright details */
-
-#ifndef _LINUX_REISER_FS_SB
-#define _LINUX_REISER_FS_SB
-
-#ifdef __KERNEL__
-#include <linux/workqueue.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#endif
-
-typedef enum {
-       reiserfs_attrs_cleared = 0x00000001,
-} reiserfs_super_block_flags;
-
-/* struct reiserfs_super_block accessors/mutators
- * since this is a disk structure, it will always be in
- * little endian format. */
-#define sb_block_count(sbp)         (le32_to_cpu((sbp)->s_v1.s_block_count))
-#define set_sb_block_count(sbp,v)   ((sbp)->s_v1.s_block_count = cpu_to_le32(v))
-#define sb_free_blocks(sbp)         (le32_to_cpu((sbp)->s_v1.s_free_blocks))
-#define set_sb_free_blocks(sbp,v)   ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v))
-#define sb_root_block(sbp)          (le32_to_cpu((sbp)->s_v1.s_root_block))
-#define set_sb_root_block(sbp,v)    ((sbp)->s_v1.s_root_block = cpu_to_le32(v))
-
-#define sb_jp_journal_1st_block(sbp)  \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block))
-#define set_sb_jp_journal_1st_block(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v))
-#define sb_jp_journal_dev(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev))
-#define set_sb_jp_journal_dev(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v))
-#define sb_jp_journal_size(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size))
-#define set_sb_jp_journal_size(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v))
-#define sb_jp_journal_trans_max(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max))
-#define set_sb_jp_journal_trans_max(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v))
-#define sb_jp_journal_magic(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic))
-#define set_sb_jp_journal_magic(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v))
-#define sb_jp_journal_max_batch(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch))
-#define set_sb_jp_journal_max_batch(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v))
-#define sb_jp_jourmal_max_commit_age(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age))
-#define set_sb_jp_journal_max_commit_age(sbp,v) \
-              ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v))
-
-#define sb_blocksize(sbp)          (le16_to_cpu((sbp)->s_v1.s_blocksize))
-#define set_sb_blocksize(sbp,v)    ((sbp)->s_v1.s_blocksize = cpu_to_le16(v))
-#define sb_oid_maxsize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_maxsize))
-#define set_sb_oid_maxsize(sbp,v)  ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v))
-#define sb_oid_cursize(sbp)        (le16_to_cpu((sbp)->s_v1.s_oid_cursize))
-#define set_sb_oid_cursize(sbp,v)  ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v))
-#define sb_umount_state(sbp)       (le16_to_cpu((sbp)->s_v1.s_umount_state))
-#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
-#define sb_fs_state(sbp)           (le16_to_cpu((sbp)->s_v1.s_fs_state))
-#define set_sb_fs_state(sbp,v)     ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
-#define sb_hash_function_code(sbp) \
-              (le32_to_cpu((sbp)->s_v1.s_hash_function_code))
-#define set_sb_hash_function_code(sbp,v) \
-              ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v))
-#define sb_tree_height(sbp)        (le16_to_cpu((sbp)->s_v1.s_tree_height))
-#define set_sb_tree_height(sbp,v)  ((sbp)->s_v1.s_tree_height = cpu_to_le16(v))
-#define sb_bmap_nr(sbp)            (le16_to_cpu((sbp)->s_v1.s_bmap_nr))
-#define set_sb_bmap_nr(sbp,v)      ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v))
-#define sb_version(sbp)            (le16_to_cpu((sbp)->s_v1.s_version))
-#define set_sb_version(sbp,v)      ((sbp)->s_v1.s_version = cpu_to_le16(v))
-
-#define sb_mnt_count(sbp)         (le16_to_cpu((sbp)->s_mnt_count))
-#define set_sb_mnt_count(sbp, v)   ((sbp)->s_mnt_count = cpu_to_le16(v))
-
-#define sb_reserved_for_journal(sbp) \
-              (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal))
-#define set_sb_reserved_for_journal(sbp,v) \
-              ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v))
-
-/* LOGGING -- */
-
-/* These all interelate for performance.
-**
-** If the journal block count is smaller than n transactions, you lose speed.
-** I don't know what n is yet, I'm guessing 8-16.
-**
-** typical transaction size depends on the application, how often fsync is
-** called, and how many metadata blocks you dirty in a 30 second period.
-** The more small files (<16k) you use, the larger your transactions will
-** be.
-**
-** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal
-** to wrap, which slows things down.  If you need high speed meta data updates, the journal should be big enough
-** to prevent wrapping before dirty meta blocks get to disk.
-**
-** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal
-** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping.
-**
-** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash.
-**
-*/
-
-/* don't mess with these for a while */
-                               /* we have a node size define somewhere in reiserfs_fs.h. -Hans */
-#define JOURNAL_BLOCK_SIZE  4096       /* BUG gotta get rid of this */
-#define JOURNAL_MAX_CNODE   1500       /* max cnodes to allocate. */
-#define JOURNAL_HASH_SIZE 8192
-#define JOURNAL_NUM_BITMAPS 5  /* number of copies of the bitmaps to have floating.  Must be >= 2 */
-
-/* One of these for every block in every transaction
-** Each one is in two hash tables.  First, a hash of the current transaction, and after journal_end, a
-** hash of all the in memory transactions.
-** next and prev are used by the current transaction (journal_hash).
-** hnext and hprev are used by journal_list_hash.  If a block is in more than one transaction, the journal_list_hash
-** links it in multiple times.  This allows flush_journal_list to remove just the cnode belonging
-** to a given transaction.
-*/
-struct reiserfs_journal_cnode {
-       struct buffer_head *bh; /* real buffer head */
-       struct super_block *sb; /* dev of real buffer head */
-       __u32 blocknr;          /* block number of real buffer head, == 0 when buffer on disk */
-       unsigned long state;
-       struct reiserfs_journal_list *jlist;    /* journal list this cnode lives in */
-       struct reiserfs_journal_cnode *next;    /* next in transaction list */
-       struct reiserfs_journal_cnode *prev;    /* prev in transaction list */
-       struct reiserfs_journal_cnode *hprev;   /* prev in hash list */
-       struct reiserfs_journal_cnode *hnext;   /* next in hash list */
-};
-
-struct reiserfs_bitmap_node {
-       int id;
-       char *data;
-       struct list_head list;
-};
-
-struct reiserfs_list_bitmap {
-       struct reiserfs_journal_list *journal_list;
-       struct reiserfs_bitmap_node **bitmaps;
-};
-
-/*
-** one of these for each transaction.  The most important part here is the j_realblock.
-** this list of cnodes is used to hash all the blocks in all the commits, to mark all the
-** real buffer heads dirty once all the commits hit the disk,
-** and to make sure every real block in a transaction is on disk before allowing the log area
-** to be overwritten */
-struct reiserfs_journal_list {
-       unsigned long j_start;
-       unsigned long j_state;
-       unsigned long j_len;
-       atomic_t j_nonzerolen;
-       atomic_t j_commit_left;
-       atomic_t j_older_commits_done;  /* all commits older than this on disk */
-       struct mutex j_commit_mutex;
-       unsigned int j_trans_id;
-       time_t j_timestamp;
-       struct reiserfs_list_bitmap *j_list_bitmap;
-       struct buffer_head *j_commit_bh;        /* commit buffer head */
-       struct reiserfs_journal_cnode *j_realblock;
-       struct reiserfs_journal_cnode *j_freedlist;     /* list of buffers that were freed during this trans.  free each of these on flush */
-       /* time ordered list of all active transactions */
-       struct list_head j_list;
-
-       /* time ordered list of all transactions we haven't tried to flush yet */
-       struct list_head j_working_list;
-
-       /* list of tail conversion targets in need of flush before commit */
-       struct list_head j_tail_bh_list;
-       /* list of data=ordered buffers in need of flush before commit */
-       struct list_head j_bh_list;
-       int j_refcount;
-};
-
-struct reiserfs_journal {
-       struct buffer_head **j_ap_blocks;       /* journal blocks on disk */
-       struct reiserfs_journal_cnode *j_last;  /* newest journal block */
-       struct reiserfs_journal_cnode *j_first; /*  oldest journal block.  start here for traverse */
-
-       struct block_device *j_dev_bd;
-       fmode_t j_dev_mode;
-       int j_1st_reserved_block;       /* first block on s_dev of reserved area journal */
-
-       unsigned long j_state;
-       unsigned int j_trans_id;
-       unsigned long j_mount_id;
-       unsigned long j_start;  /* start of current waiting commit (index into j_ap_blocks) */
-       unsigned long j_len;    /* length of current waiting commit */
-       unsigned long j_len_alloc;      /* number of buffers requested by journal_begin() */
-       atomic_t j_wcount;      /* count of writers for current commit */
-       unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
-       unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */
-       unsigned j_last_flush_trans_id; /* last fully flushed journal timestamp */
-       struct buffer_head *j_header_bh;
-
-       time_t j_trans_start_time;      /* time this transaction started */
-       struct mutex j_mutex;
-       struct mutex j_flush_mutex;
-       wait_queue_head_t j_join_wait;  /* wait for current transaction to finish before starting new one */
-       atomic_t j_jlock;       /* lock for j_join_wait */
-       int j_list_bitmap_index;        /* number of next list bitmap to use */
-       int j_must_wait;        /* no more journal begins allowed. MUST sleep on j_join_wait */
-       int j_next_full_flush;  /* next journal_end will flush all journal list */
-       int j_next_async_flush; /* next journal_end will flush all async commits */
-
-       int j_cnode_used;       /* number of cnodes on the used list */
-       int j_cnode_free;       /* number of cnodes on the free list */
-
-       unsigned int j_trans_max;       /* max number of blocks in a transaction.  */
-       unsigned int j_max_batch;       /* max number of blocks to batch into a trans */
-       unsigned int j_max_commit_age;  /* in seconds, how old can an async commit be */
-       unsigned int j_max_trans_age;   /* in seconds, how old can a transaction be */
-       unsigned int j_default_max_commit_age;  /* the default for the max commit age */
-
-       struct reiserfs_journal_cnode *j_cnode_free_list;
-       struct reiserfs_journal_cnode *j_cnode_free_orig;       /* orig pointer returned from vmalloc */
-
-       struct reiserfs_journal_list *j_current_jl;
-       int j_free_bitmap_nodes;
-       int j_used_bitmap_nodes;
-
-       int j_num_lists;        /* total number of active transactions */
-       int j_num_work_lists;   /* number that need attention from kreiserfsd */
-
-       /* debugging to make sure things are flushed in order */
-       unsigned int j_last_flush_id;
-
-       /* debugging to make sure things are committed in order */
-       unsigned int j_last_commit_id;
-
-       struct list_head j_bitmap_nodes;
-       struct list_head j_dirty_buffers;
-       spinlock_t j_dirty_buffers_lock;        /* protects j_dirty_buffers */
-
-       /* list of all active transactions */
-       struct list_head j_journal_list;
-       /* lists that haven't been touched by writeback attempts */
-       struct list_head j_working_list;
-
-       struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */
-       struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */
-       struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE];    /* hash table for all the real buffer heads in all
-                                                                                  the transactions */
-       struct list_head j_prealloc_list;       /* list of inodes which have preallocated blocks */
-       int j_persistent_trans;
-       unsigned long j_max_trans_size;
-       unsigned long j_max_batch_size;
-
-       int j_errno;
-
-       /* when flushing ordered buffers, throttle new ordered writers */
-       struct delayed_work j_work;
-       struct super_block *j_work_sb;
-       atomic_t j_async_throttle;
-};
-
-enum journal_state_bits {
-       J_WRITERS_BLOCKED = 1,  /* set when new writers not allowed */
-       J_WRITERS_QUEUED,       /* set when log is full due to too many writers */
-       J_ABORTED,              /* set when log is aborted */
-};
-
-#define JOURNAL_DESC_MAGIC "ReIsErLB"  /* ick.  magic string to find desc blocks in the journal */
-
-typedef __u32(*hashf_t) (const signed char *, int);
-
-struct reiserfs_bitmap_info {
-       __u32 free_count;
-};
-
-struct proc_dir_entry;
-
-#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
-typedef unsigned long int stat_cnt_t;
-typedef struct reiserfs_proc_info_data {
-       spinlock_t lock;
-       int exiting;
-       int max_hash_collisions;
-
-       stat_cnt_t breads;
-       stat_cnt_t bread_miss;
-       stat_cnt_t search_by_key;
-       stat_cnt_t search_by_key_fs_changed;
-       stat_cnt_t search_by_key_restarted;
-
-       stat_cnt_t insert_item_restarted;
-       stat_cnt_t paste_into_item_restarted;
-       stat_cnt_t cut_from_item_restarted;
-       stat_cnt_t delete_solid_item_restarted;
-       stat_cnt_t delete_item_restarted;
-
-       stat_cnt_t leaked_oid;
-       stat_cnt_t leaves_removable;
-
-       /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
-       stat_cnt_t balance_at[5];       /* XXX */
-       /* sbk == search_by_key */
-       stat_cnt_t sbk_read_at[5];      /* XXX */
-       stat_cnt_t sbk_fs_changed[5];
-       stat_cnt_t sbk_restarted[5];
-       stat_cnt_t items_at[5]; /* XXX */
-       stat_cnt_t free_at[5];  /* XXX */
-       stat_cnt_t can_node_be_removed[5];      /* XXX */
-       long int lnum[5];       /* XXX */
-       long int rnum[5];       /* XXX */
-       long int lbytes[5];     /* XXX */
-       long int rbytes[5];     /* XXX */
-       stat_cnt_t get_neighbors[5];
-       stat_cnt_t get_neighbors_restart[5];
-       stat_cnt_t need_l_neighbor[5];
-       stat_cnt_t need_r_neighbor[5];
-
-       stat_cnt_t free_block;
-       struct __scan_bitmap_stats {
-               stat_cnt_t call;
-               stat_cnt_t wait;
-               stat_cnt_t bmap;
-               stat_cnt_t retry;
-               stat_cnt_t in_journal_hint;
-               stat_cnt_t in_journal_nohint;
-               stat_cnt_t stolen;
-       } scan_bitmap;
-       struct __journal_stats {
-               stat_cnt_t in_journal;
-               stat_cnt_t in_journal_bitmap;
-               stat_cnt_t in_journal_reusable;
-               stat_cnt_t lock_journal;
-               stat_cnt_t lock_journal_wait;
-               stat_cnt_t journal_being;
-               stat_cnt_t journal_relock_writers;
-               stat_cnt_t journal_relock_wcount;
-               stat_cnt_t mark_dirty;
-               stat_cnt_t mark_dirty_already;
-               stat_cnt_t mark_dirty_notjournal;
-               stat_cnt_t restore_prepared;
-               stat_cnt_t prepare;
-               stat_cnt_t prepare_retry;
-       } journal;
-} reiserfs_proc_info_data_t;
-#else
-typedef struct reiserfs_proc_info_data {
-} reiserfs_proc_info_data_t;
-#endif
-
-/* reiserfs union of in-core super block data */
-struct reiserfs_sb_info {
-       struct buffer_head *s_sbh;      /* Buffer containing the super block */
-       /* both the comment and the choice of
-          name are unclear for s_rs -Hans */
-       struct reiserfs_super_block *s_rs;      /* Pointer to the super block in the buffer */
-       struct reiserfs_bitmap_info *s_ap_bitmap;
-       struct reiserfs_journal *s_journal;     /* pointer to journal information */
-       unsigned short s_mount_state;   /* reiserfs state (valid, invalid) */
-
-       /* Serialize writers access, replace the old bkl */
-       struct mutex lock;
-       /* Owner of the lock (can be recursive) */
-       struct task_struct *lock_owner;
-       /* Depth of the lock, start from -1 like the bkl */
-       int lock_depth;
-
-       /* Comment? -Hans */
-       void (*end_io_handler) (struct buffer_head *, int);
-       hashf_t s_hash_function;        /* pointer to function which is used
-                                          to sort names in directory. Set on
-                                          mount */
-       unsigned long s_mount_opt;      /* reiserfs's mount options are set
-                                          here (currently - NOTAIL, NOLOG,
-                                          REPLAYONLY) */
-
-       struct {                /* This is a structure that describes block allocator options */
-               unsigned long bits;     /* Bitfield for enable/disable kind of options */
-               unsigned long large_file_size;  /* size started from which we consider file to be a large one(in blocks) */
-               int border;     /* percentage of disk, border takes */
-               int preallocmin;        /* Minimal file size (in blocks) starting from which we do preallocations */
-               int preallocsize;       /* Number of blocks we try to prealloc when file
-                                          reaches preallocmin size (in blocks) or
-                                          prealloc_list is empty. */
-       } s_alloc_options;
-
-       /* Comment? -Hans */
-       wait_queue_head_t s_wait;
-       /* To be obsoleted soon by per buffer seals.. -Hans */
-       atomic_t s_generation_counter;  // increased by one every time the
-       // tree gets re-balanced
-       unsigned long s_properties;     /* File system properties. Currently holds
-                                          on-disk FS format */
-
-       /* session statistics */
-       int s_disk_reads;
-       int s_disk_writes;
-       int s_fix_nodes;
-       int s_do_balance;
-       int s_unneeded_left_neighbor;
-       int s_good_search_by_key_reada;
-       int s_bmaps;
-       int s_bmaps_without_search;
-       int s_direct2indirect;
-       int s_indirect2direct;
-       /* set up when it's ok for reiserfs_read_inode2() to read from
-          disk inode with nlink==0. Currently this is only used during
-          finish_unfinished() processing at mount time */
-       int s_is_unlinked_ok;
-       reiserfs_proc_info_data_t s_proc_info_data;
-       struct proc_dir_entry *procdir;
-       int reserved_blocks;    /* amount of blocks reserved for further allocations */
-       spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
-       struct dentry *priv_root;       /* root of /.reiserfs_priv */
-       struct dentry *xattr_root;      /* root of /.reiserfs_priv/xattrs */
-       int j_errno;
-#ifdef CONFIG_QUOTA
-       char *s_qf_names[MAXQUOTAS];
-       int s_jquota_fmt;
-#endif
-       char *s_jdev;           /* Stored jdev for mount option showing */
-#ifdef CONFIG_REISERFS_CHECK
-
-       struct tree_balance *cur_tb;    /*
-                                        * Detects whether more than one
-                                        * copy of tb exists per superblock
-                                        * as a means of checking whether
-                                        * do_balance is executing concurrently
-                                        * against another tree reader/writer
-                                        * on a same mount point.
-                                        */
-#endif
-};
-
-/* Definitions of reiserfs on-disk properties: */
-#define REISERFS_3_5 0
-#define REISERFS_3_6 1
-#define REISERFS_OLD_FORMAT 2
-
-enum reiserfs_mount_options {
-/* Mount options */
-       REISERFS_LARGETAIL,     /* large tails will be created in a session */
-       REISERFS_SMALLTAIL,     /* small (for files less than block size) tails will be created in a session */
-       REPLAYONLY,             /* replay journal and return 0. Use by fsck */
-       REISERFS_CONVERT,       /* -o conv: causes conversion of old
-                                  format super block to the new
-                                  format. If not specified - old
-                                  partition will be dealt with in a
-                                  manner of 3.5.x */
-
-/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
-** reiserfs disks from 3.5.19 or earlier.  99% of the time, this option
-** is not required.  If the normal autodection code can't determine which
-** hash to use (because both hashes had the same value for a file)
-** use this option to force a specific hash.  It won't allow you to override
-** the existing hash on the FS, so if you have a tea hash disk, and mount
-** with -o hash=rupasov, the mount will fail.
-*/
-       FORCE_TEA_HASH,         /* try to force tea hash on mount */
-       FORCE_RUPASOV_HASH,     /* try to force rupasov hash on mount */
-       FORCE_R5_HASH,          /* try to force rupasov hash on mount */
-       FORCE_HASH_DETECT,      /* try to detect hash function on mount */
-
-       REISERFS_DATA_LOG,
-       REISERFS_DATA_ORDERED,
-       REISERFS_DATA_WRITEBACK,
-
-/* used for testing experimental features, makes benchmarking new
-   features with and without more convenient, should never be used by
-   users in any code shipped to users (ideally) */
-
-       REISERFS_NO_BORDER,
-       REISERFS_NO_UNHASHED_RELOCATION,
-       REISERFS_HASHED_RELOCATION,
-       REISERFS_ATTRS,
-       REISERFS_XATTRS_USER,
-       REISERFS_POSIXACL,
-       REISERFS_EXPOSE_PRIVROOT,
-       REISERFS_BARRIER_NONE,
-       REISERFS_BARRIER_FLUSH,
-
-       /* Actions on error */
-       REISERFS_ERROR_PANIC,
-       REISERFS_ERROR_RO,
-       REISERFS_ERROR_CONTINUE,
-
-       REISERFS_USRQUOTA,      /* User quota option specified */
-       REISERFS_GRPQUOTA,      /* Group quota option specified */
-
-       REISERFS_TEST1,
-       REISERFS_TEST2,
-       REISERFS_TEST3,
-       REISERFS_TEST4,
-       REISERFS_UNSUPPORTED_OPT,
-};
-
-#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH))
-#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH))
-#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH))
-#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT))
-#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER))
-#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
-#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
-#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4))
-
-#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL))
-#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
-#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
-#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS))
-#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
-#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT))
-#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG))
-#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED))
-#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK))
-#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
-#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
-#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT))
-#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
-#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
-#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
-
-#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
-#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
-
-void reiserfs_file_buffer(struct buffer_head *bh, int list);
-extern struct file_system_type reiserfs_fs_type;
-int reiserfs_resize(struct super_block *, unsigned long);
-
-#define CARRY_ON                0
-#define SCHEDULE_OCCURRED       1
-
-#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh)
-#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal)
-#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
-#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
-#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap)
-
-#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
-
-/* A safe version of the "bdevname", which returns the "s_id" field of
- * a superblock or else "Null superblock" if the super block is NULL.
- */
-static inline char *reiserfs_bdevname(struct super_block *s)
-{
-       return (s == NULL) ? "Null superblock" : s->s_id;
-}
-
-#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
-static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
-                                               *journal)
-{
-       return test_bit(J_ABORTED, &journal->j_state);
-}
-
-#endif                         /* _LINUX_REISER_FS_SB */
index c2b7147..d8ce17c 100644 (file)
@@ -21,132 +21,4 @@ struct reiserfs_security_handle {
        size_t length;
 };
 
-#ifdef __KERNEL__
-
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/rwsem.h>
-#include <linux/reiserfs_fs_i.h>
-#include <linux/reiserfs_fs.h>
-
-struct inode;
-struct dentry;
-struct iattr;
-struct super_block;
-struct nameidata;
-
-int reiserfs_xattr_register_handlers(void) __init;
-void reiserfs_xattr_unregister_handlers(void);
-int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
-int reiserfs_lookup_privroot(struct super_block *sb);
-int reiserfs_delete_xattrs(struct inode *inode);
-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
-int reiserfs_permission(struct inode *inode, int mask);
-
-#ifdef CONFIG_REISERFS_FS_XATTR
-#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
-ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
-                         void *buffer, size_t size);
-int reiserfs_setxattr(struct dentry *dentry, const char *name,
-                     const void *value, size_t size, int flags);
-ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int reiserfs_removexattr(struct dentry *dentry, const char *name);
-
-int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
-int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
-int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
-                             struct inode *, const char *, const void *,
-                             size_t, int);
-
-extern const struct xattr_handler reiserfs_xattr_user_handler;
-extern const struct xattr_handler reiserfs_xattr_trusted_handler;
-extern const struct xattr_handler reiserfs_xattr_security_handler;
-#ifdef CONFIG_REISERFS_FS_SECURITY
-int reiserfs_security_init(struct inode *dir, struct inode *inode,
-                          const struct qstr *qstr,
-                          struct reiserfs_security_handle *sec);
-int reiserfs_security_write(struct reiserfs_transaction_handle *th,
-                           struct inode *inode,
-                           struct reiserfs_security_handle *sec);
-void reiserfs_security_free(struct reiserfs_security_handle *sec);
-#endif
-
-static inline int reiserfs_xattrs_initialized(struct super_block *sb)
-{
-       return REISERFS_SB(sb)->priv_root != NULL;
-}
-
-#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
-static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
-{
-       loff_t ret = 0;
-       if (reiserfs_file_data_log(inode)) {
-               ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize);
-               ret >>= inode->i_sb->s_blocksize_bits;
-       }
-       return ret;
-}
-
-/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file.
- * Let's try to be smart about it.
- * xattr root: We cache it. If it's not cached, we may need to create it.
- * xattr dir: If anything has been loaded for this inode, we can set a flag
- *            saying so.
- * xattr file: Since we don't cache xattrs, we can't tell. We always include
- *             blocks for it.
- *
- * However, since root and dir can be created between calls - YOU MUST SAVE
- * THIS VALUE.
- */
-static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode)
-{
-       size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-
-       if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) {
-               nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-               if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode)
-                       nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
-       }
-
-       return nblocks;
-}
-
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
-       init_rwsem(&REISERFS_I(inode)->i_xattr_sem);
-}
-
-#else
-
-#define reiserfs_getxattr NULL
-#define reiserfs_setxattr NULL
-#define reiserfs_listxattr NULL
-#define reiserfs_removexattr NULL
-
-static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
-{
-}
-#endif  /*  CONFIG_REISERFS_FS_XATTR  */
-
-#ifndef CONFIG_REISERFS_FS_SECURITY
-static inline int reiserfs_security_init(struct inode *dir,
-                                        struct inode *inode,
-                                        const struct qstr *qstr,
-                                        struct reiserfs_security_handle *sec)
-{
-       return 0;
-}
-static inline int
-reiserfs_security_write(struct reiserfs_transaction_handle *th,
-                       struct inode *inode,
-                       struct reiserfs_security_handle *sec)
-{
-       return 0;
-}
-static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
-{}
-#endif
-
-#endif  /*  __KERNEL__  */
-
 #endif  /*  _LINUX_REISERFS_XATTR_H  */
index c894938..673afbb 100644 (file)
 #ifndef __LINUX_SECURITY_H
 #define __LINUX_SECURITY_H
 
-#include <linux/fs.h>
-#include <linux/fsnotify.h>
-#include <linux/binfmts.h>
-#include <linux/dcache.h>
-#include <linux/signal.h>
-#include <linux/resource.h>
-#include <linux/sem.h>
-#include <linux/shm.h>
-#include <linux/mm.h> /* PAGE_ALIGN */
-#include <linux/msg.h>
-#include <linux/sched.h>
 #include <linux/key.h>
-#include <linux/xfrm.h>
+#include <linux/capability.h>
 #include <linux/slab.h>
-#include <linux/xattr.h>
-#include <net/flow.h>
+#include <linux/err.h>
+
+struct linux_binprm;
+struct cred;
+struct rlimit;
+struct siginfo;
+struct sem_array;
+struct sembuf;
+struct kern_ipc_perm;
+struct audit_context;
+struct super_block;
+struct inode;
+struct dentry;
+struct file;
+struct vfsmount;
+struct path;
+struct qstr;
+struct nameidata;
+struct iattr;
+struct fown_struct;
+struct file_operations;
+struct shmid_kernel;
+struct msg_msg;
+struct msg_queue;
+struct xattr;
+struct xfrm_sec_ctx;
+struct mm_struct;
 
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX      10
@@ -49,6 +63,7 @@
 struct ctl_table;
 struct audit_krule;
 struct user_namespace;
+struct timezone;
 
 /*
  * These functions are in security/capability.c and are used
@@ -131,18 +146,6 @@ struct request_sock;
 #define LSM_UNSAFE_PTRACE_CAP  4
 
 #ifdef CONFIG_MMU
-/*
- * If a hint addr is less than mmap_min_addr change hint to be as
- * low as possible but still greater than mmap_min_addr
- */
-static inline unsigned long round_hint_to_min(unsigned long hint)
-{
-       hint &= PAGE_MASK;
-       if (((void *)hint != NULL) &&
-           (hint < mmap_min_addr))
-               return PAGE_ALIGN(mmap_min_addr);
-       return hint;
-}
 extern int mmap_min_addr_handler(struct ctl_table *table, int write,
                                 void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
@@ -651,6 +654,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     manual page for definitions of the @clone_flags.
  *     @clone_flags contains the flags indicating what should be shared.
  *     Return 0 if permission is granted.
+ * @task_free:
+ *     @task task being freed
+ *     Handle release of task-related resources. (Note that this can be called
+ *     from interrupt context.)
  * @cred_alloc_blank:
  *     @cred points to the credentials.
  *     @gfp indicates the atomicity of any memory allocations.
@@ -1493,6 +1500,7 @@ struct security_operations {
        int (*dentry_open) (struct file *file, const struct cred *cred);
 
        int (*task_create) (unsigned long clone_flags);
+       void (*task_free) (struct task_struct *task);
        int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp);
        void (*cred_free) (struct cred *cred);
        int (*cred_prepare)(struct cred *new, const struct cred *old,
@@ -1674,9 +1682,7 @@ int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
 int security_syslog(int type);
 int security_settime(const struct timespec *ts, const struct timezone *tz);
-int security_vm_enough_memory(long pages);
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
-int security_vm_enough_memory_kern(long pages);
 int security_bprm_set_creds(struct linux_binprm *bprm);
 int security_bprm_check(struct linux_binprm *bprm);
 void security_bprm_committing_creds(struct linux_binprm *bprm);
@@ -1752,6 +1758,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
 int security_file_receive(struct file *file);
 int security_dentry_open(struct file *file, const struct cred *cred);
 int security_task_create(unsigned long clone_flags);
+void security_task_free(struct task_struct *task);
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
 void security_cred_free(struct cred *cred);
 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
@@ -1896,25 +1903,11 @@ static inline int security_settime(const struct timespec *ts,
        return cap_settime(ts, tz);
 }
 
-static inline int security_vm_enough_memory(long pages)
-{
-       WARN_ON(current->mm == NULL);
-       return cap_vm_enough_memory(current->mm, pages);
-}
-
 static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
 {
-       WARN_ON(mm == NULL);
        return cap_vm_enough_memory(mm, pages);
 }
 
-static inline int security_vm_enough_memory_kern(long pages)
-{
-       /* If current->mm is a kernel thread then we will pass NULL,
-          for this specific case that is fine */
-       return cap_vm_enough_memory(current->mm, pages);
-}
-
 static inline int security_bprm_set_creds(struct linux_binprm *bprm)
 {
        return cap_bprm_set_creds(bprm);
@@ -2245,6 +2238,9 @@ static inline int security_task_create(unsigned long clone_flags)
        return 0;
 }
 
+static inline void security_task_free(struct task_struct *task)
+{ }
+
 static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
        return 0;
index 7dadc3d..a32d86e 100644 (file)
@@ -44,7 +44,7 @@ extern int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len);
 extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
                                size_t len);
 extern void *trace_seq_reserve(struct trace_seq *s, size_t len);
-extern int trace_seq_path(struct trace_seq *s, struct path *path);
+extern int trace_seq_path(struct trace_seq *s, const struct path *path);
 
 #else /* CONFIG_TRACING */
 static inline int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@@ -88,7 +88,7 @@ static inline void *trace_seq_reserve(struct trace_seq *s, size_t len)
 {
        return NULL;
 }
-static inline int trace_seq_path(struct trace_seq *s, struct path *path)
+static inline int trace_seq_path(struct trace_seq *s, const struct path *path)
 {
        return 0;
 }
index 5a4e29b..ca68e2c 100644 (file)
@@ -49,8 +49,7 @@ struct unix_sock {
        /* WARNING: sk has to be the first member */
        struct sock             sk;
        struct unix_address     *addr;
-       struct dentry           *dentry;
-       struct vfsmount         *mnt;
+       struct path             path;
        struct mutex            readlock;
        struct sock             *peer;
        struct sock             *other;
index f84be9e..04bc0b3 100644 (file)
@@ -56,6 +56,8 @@
 #include <linux/memcontrol.h>
 #include <linux/res_counter.h>
 #include <linux/static_key.h>
+#include <linux/aio.h>
+#include <linux/sched.h>
 
 #include <linux/filter.h>
 #include <linux/rculist_nulls.h>
index 887629e..01f1306 100644 (file)
@@ -178,7 +178,7 @@ int __init rd_load_image(char *from)
        char *buf = NULL;
        unsigned short rotate = 0;
        decompress_fn decompressor = NULL;
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
+#if !defined(CONFIG_S390)
        char rotator[4] = { '|' , '/' , '-' , '\\' };
 #endif
 
@@ -264,7 +264,7 @@ int __init rd_load_image(char *from)
                }
                sys_read(in_fd, buf, BLOCK_SIZE);
                sys_write(out_fd, buf, BLOCK_SIZE);
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
+#if !defined(CONFIG_S390)
                if (!(i % 16)) {
                        printk("%c\b", rotator[rotate & 0x3]);
                        rotate++;
index 86ee272..28bd64d 100644 (file)
@@ -188,30 +188,20 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
        struct ipc_namespace *ns = data;
-       int error;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
        sb->s_magic = MQUEUE_MAGIC;
        sb->s_op = &mqueue_super_ops;
 
-       inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO,
-                               NULL);
-       if (IS_ERR(inode)) {
-               error = PTR_ERR(inode);
-               goto out;
-       }
+       inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
 
-       sb->s_root = d_alloc_root(inode);
-       if (!sb->s_root) {
-               iput(inode);
-               error = -ENOMEM;
-               goto out;
-       }
-       error = 0;
-
-out:
-       return error;
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
+               return -ENOMEM;
+       return 0;
 }
 
 static struct dentry *mqueue_mount(struct file_system_type *fs_type,
index 5652101..26143d3 100644 (file)
@@ -13,7 +13,9 @@
 #include <linux/security.h>
 #include <linux/slab.h>
 #include <linux/ipc.h>
+#include <linux/msg.h>
 #include <linux/ipc_namespace.h>
+#include <linux/utsname.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
index bb0eb5b..1c7f2c6 100644 (file)
@@ -1418,7 +1418,7 @@ void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
 
 /* This is a helper-function to print the escaped d_path */
 void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
-                     struct path *path)
+                     const struct path *path)
 {
        char *p, *pathname;
 
index 391d5e9..f4ea4b6 100644 (file)
@@ -1472,7 +1472,6 @@ static int cgroup_get_rootdir(struct super_block *sb)
 
        struct inode *inode =
                cgroup_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, sb);
-       struct dentry *dentry;
 
        if (!inode)
                return -ENOMEM;
@@ -1481,12 +1480,9 @@ static int cgroup_get_rootdir(struct super_block *sb)
        inode->i_op = &cgroup_dir_inode_operations;
        /* directories start off with i_nlink == 2 (for "." entry) */
        inc_nlink(inode);
-       dentry = d_alloc_root(inode);
-       if (!dentry) {
-               iput(inode);
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
                return -ENOMEM;
-       }
-       sb->s_root = dentry;
        /* for everything else we want ->d_op set */
        sb->s_d_op = &cgroup_dops;
        return 0;
index 5791612..97b36ee 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/keyctl.h>
 #include <linux/init_task.h>
 #include <linux/security.h>
+#include <linux/binfmts.h>
 #include <linux/cn_proc.h>
 
 #if 0
index d26acd3..16b07bf 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/oom.h>
 #include <linux/writeback.h>
+#include <linux/shm.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
index 9cc227d..37674ec 100644 (file)
@@ -193,6 +193,7 @@ void __put_task_struct(struct task_struct *tsk)
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
+       security_task_free(tsk);
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
        put_signal_struct(tsk->signal);
@@ -355,7 +356,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                charge = 0;
                if (mpnt->vm_flags & VM_ACCOUNT) {
                        unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-                       if (security_vm_enough_memory(len))
+                       if (security_vm_enough_memory_mm(oldmm, len)) /* sic */
                                goto fail_nomem;
                        charge = len;
                }
index b452599..6f10eb2 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/sysfs.h>
 #include <linux/rcupdate.h>
 
-#define MAX_SEQ_NR (INT_MAX - NR_CPUS)
 #define MAX_OBJ_NUM 1000
 
 static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
@@ -43,18 +42,19 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
        return target_cpu;
 }
 
-static int padata_cpu_hash(struct padata_priv *padata)
+static int padata_cpu_hash(struct parallel_data *pd)
 {
        int cpu_index;
-       struct parallel_data *pd;
-
-       pd =  padata->pd;
 
        /*
         * Hash the sequence numbers to the cpus by taking
         * seq_nr mod. number of cpus in use.
         */
-       cpu_index =  padata->seq_nr % cpumask_weight(pd->cpumask.pcpu);
+
+       spin_lock(&pd->seq_lock);
+       cpu_index =  pd->seq_nr % cpumask_weight(pd->cpumask.pcpu);
+       pd->seq_nr++;
+       spin_unlock(&pd->seq_lock);
 
        return padata_index_to_cpu(pd, cpu_index);
 }
@@ -132,12 +132,7 @@ int padata_do_parallel(struct padata_instance *pinst,
        padata->pd = pd;
        padata->cb_cpu = cb_cpu;
 
-       if (unlikely(atomic_read(&pd->seq_nr) == pd->max_seq_nr))
-               atomic_set(&pd->seq_nr, -1);
-
-       padata->seq_nr = atomic_inc_return(&pd->seq_nr);
-
-       target_cpu = padata_cpu_hash(padata);
+       target_cpu = padata_cpu_hash(pd);
        queue = per_cpu_ptr(pd->pqueue, target_cpu);
 
        spin_lock(&queue->parallel.lock);
@@ -173,7 +168,7 @@ EXPORT_SYMBOL(padata_do_parallel);
 static struct padata_priv *padata_get_next(struct parallel_data *pd)
 {
        int cpu, num_cpus;
-       int next_nr, next_index;
+       unsigned int next_nr, next_index;
        struct padata_parallel_queue *queue, *next_queue;
        struct padata_priv *padata;
        struct padata_list *reorder;
@@ -189,14 +184,6 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd)
        cpu = padata_index_to_cpu(pd, next_index);
        next_queue = per_cpu_ptr(pd->pqueue, cpu);
 
-       if (unlikely(next_nr > pd->max_seq_nr)) {
-               next_nr = next_nr - pd->max_seq_nr - 1;
-               next_index = next_nr % num_cpus;
-               cpu = padata_index_to_cpu(pd, next_index);
-               next_queue = per_cpu_ptr(pd->pqueue, cpu);
-               pd->processed = 0;
-       }
-
        padata = NULL;
 
        reorder = &next_queue->reorder;
@@ -205,8 +192,6 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd)
                padata = list_entry(reorder->list.next,
                                    struct padata_priv, list);
 
-               BUG_ON(next_nr != padata->seq_nr);
-
                spin_lock(&reorder->lock);
                list_del_init(&padata->list);
                atomic_dec(&pd->reorder_objects);
@@ -230,6 +215,7 @@ out:
 
 static void padata_reorder(struct parallel_data *pd)
 {
+       int cb_cpu;
        struct padata_priv *padata;
        struct padata_serial_queue *squeue;
        struct padata_instance *pinst = pd->pinst;
@@ -270,13 +256,14 @@ static void padata_reorder(struct parallel_data *pd)
                        return;
                }
 
-               squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu);
+               cb_cpu = padata->cb_cpu;
+               squeue = per_cpu_ptr(pd->squeue, cb_cpu);
 
                spin_lock(&squeue->serial.lock);
                list_add_tail(&padata->list, &squeue->serial.list);
                spin_unlock(&squeue->serial.lock);
 
-               queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work);
+               queue_work_on(cb_cpu, pinst->wq, &squeue->work);
        }
 
        spin_unlock_bh(&pd->lock);
@@ -400,7 +387,7 @@ static void padata_init_squeues(struct parallel_data *pd)
 /* Initialize all percpu queues used by parallel workers */
 static void padata_init_pqueues(struct parallel_data *pd)
 {
-       int cpu_index, num_cpus, cpu;
+       int cpu_index, cpu;
        struct padata_parallel_queue *pqueue;
 
        cpu_index = 0;
@@ -415,9 +402,6 @@ static void padata_init_pqueues(struct parallel_data *pd)
                INIT_WORK(&pqueue->work, padata_parallel_worker);
                atomic_set(&pqueue->num_obj, 0);
        }
-
-       num_cpus = cpumask_weight(pd->cpumask.pcpu);
-       pd->max_seq_nr = num_cpus ? (MAX_SEQ_NR / num_cpus) * num_cpus - 1 : 0;
 }
 
 /* Allocate and initialize the internal cpumask dependend resources. */
@@ -444,7 +428,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,
        padata_init_pqueues(pd);
        padata_init_squeues(pd);
        setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd);
-       atomic_set(&pd->seq_nr, -1);
+       pd->seq_nr = 0;
        atomic_set(&pd->reorder_objects, 0);
        atomic_set(&pd->refcnt, 0);
        pd->pinst = pinst;
index a35cb8d..503d642 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/ftrace.h>
 #include <linux/slab.h>
 #include <linux/init_task.h>
+#include <linux/binfmts.h>
 
 #include <asm/tlb.h>
 #include <asm/irq_regs.h>
index f487f25..11d5304 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/oom.h>
 #include <linux/kmod.h>
 #include <linux/capability.h>
+#include <linux/binfmts.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
index c5a0187..859fae6 100644 (file)
@@ -264,7 +264,7 @@ void *trace_seq_reserve(struct trace_seq *s, size_t len)
        return ret;
 }
 
-int trace_seq_path(struct trace_seq *s, struct path *path)
+int trace_seq_path(struct trace_seq *s, const struct path *path)
 {
        unsigned char *p;
 
index 1e0561e..3416b6e 100644 (file)
@@ -1267,10 +1267,10 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
        return addr;
 }
 
-static unsigned long unmap_page_range(struct mmu_gather *tlb,
-                               struct vm_area_struct *vma,
-                               unsigned long addr, unsigned long end,
-                               struct zap_details *details)
+static void unmap_page_range(struct mmu_gather *tlb,
+                            struct vm_area_struct *vma,
+                            unsigned long addr, unsigned long end,
+                            struct zap_details *details)
 {
        pgd_t *pgd;
        unsigned long next;
@@ -1290,8 +1290,47 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
        } while (pgd++, addr = next, addr != end);
        tlb_end_vma(tlb, vma);
        mem_cgroup_uncharge_end();
+}
 
-       return addr;
+
+static void unmap_single_vma(struct mmu_gather *tlb,
+               struct vm_area_struct *vma, unsigned long start_addr,
+               unsigned long end_addr, unsigned long *nr_accounted,
+               struct zap_details *details)
+{
+       unsigned long start = max(vma->vm_start, start_addr);
+       unsigned long end;
+
+       if (start >= vma->vm_end)
+               return;
+       end = min(vma->vm_end, end_addr);
+       if (end <= vma->vm_start)
+               return;
+
+       if (vma->vm_flags & VM_ACCOUNT)
+               *nr_accounted += (end - start) >> PAGE_SHIFT;
+
+       if (unlikely(is_pfn_mapping(vma)))
+               untrack_pfn_vma(vma, 0, 0);
+
+       if (start != end) {
+               if (unlikely(is_vm_hugetlb_page(vma))) {
+                       /*
+                        * It is undesirable to test vma->vm_file as it
+                        * should be non-null for valid hugetlb area.
+                        * However, vm_file will be NULL in the error
+                        * cleanup path of do_mmap_pgoff. When
+                        * hugetlbfs ->mmap method fails,
+                        * do_mmap_pgoff() nullifies vma->vm_file
+                        * before calling this function to clean up.
+                        * Since no pte has actually been setup, it is
+                        * safe to do nothing in this case.
+                        */
+                       if (vma->vm_file)
+                               unmap_hugepage_range(vma, start, end, NULL);
+               } else
+                       unmap_page_range(tlb, vma, start, end, details);
+       }
 }
 
 /**
@@ -1303,8 +1342,6 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
  * @nr_accounted: Place number of unmapped pages in vm-accountable vma's here
  * @details: details of nonlinear truncation or shared cache invalidation
  *
- * Returns the end address of the unmapping (restart addr if interrupted).
- *
  * Unmap all pages in the vma list.
  *
  * Only addresses between `start' and `end' will be unmapped.
@@ -1316,55 +1353,18 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
  * ensure that any thus-far unmapped pages are flushed before unmap_vmas()
  * drops the lock and schedules.
  */
-unsigned long unmap_vmas(struct mmu_gather *tlb,
+void unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *details)
 {
-       unsigned long start = start_addr;
        struct mm_struct *mm = vma->vm_mm;
 
        mmu_notifier_invalidate_range_start(mm, start_addr, end_addr);
-       for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) {
-               unsigned long end;
-
-               start = max(vma->vm_start, start_addr);
-               if (start >= vma->vm_end)
-                       continue;
-               end = min(vma->vm_end, end_addr);
-               if (end <= vma->vm_start)
-                       continue;
-
-               if (vma->vm_flags & VM_ACCOUNT)
-                       *nr_accounted += (end - start) >> PAGE_SHIFT;
-
-               if (unlikely(is_pfn_mapping(vma)))
-                       untrack_pfn_vma(vma, 0, 0);
-
-               while (start != end) {
-                       if (unlikely(is_vm_hugetlb_page(vma))) {
-                               /*
-                                * It is undesirable to test vma->vm_file as it
-                                * should be non-null for valid hugetlb area.
-                                * However, vm_file will be NULL in the error
-                                * cleanup path of do_mmap_pgoff. When
-                                * hugetlbfs ->mmap method fails,
-                                * do_mmap_pgoff() nullifies vma->vm_file
-                                * before calling this function to clean up.
-                                * Since no pte has actually been setup, it is
-                                * safe to do nothing in this case.
-                                */
-                               if (vma->vm_file)
-                                       unmap_hugepage_range(vma, start, end, NULL);
-
-                               start = end;
-                       } else
-                               start = unmap_page_range(tlb, vma, start, end, details);
-               }
-       }
-
+       for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next)
+               unmap_single_vma(tlb, vma, start_addr, end_addr, nr_accounted,
+                                details);
        mmu_notifier_invalidate_range_end(mm, start_addr, end_addr);
-       return start;   /* which is now the end (or restart) address */
 }
 
 /**
@@ -1373,8 +1373,34 @@ unsigned long unmap_vmas(struct mmu_gather *tlb,
  * @address: starting address of pages to zap
  * @size: number of bytes to zap
  * @details: details of nonlinear truncation or shared cache invalidation
+ *
+ * Caller must protect the VMA list
+ */
+void zap_page_range(struct vm_area_struct *vma, unsigned long address,
+               unsigned long size, struct zap_details *details)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       struct mmu_gather tlb;
+       unsigned long end = address + size;
+       unsigned long nr_accounted = 0;
+
+       lru_add_drain();
+       tlb_gather_mmu(&tlb, mm, 0);
+       update_hiwater_rss(mm);
+       unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
+       tlb_finish_mmu(&tlb, address, end);
+}
+
+/**
+ * zap_page_range_single - remove user pages in a given range
+ * @vma: vm_area_struct holding the applicable pages
+ * @address: starting address of pages to zap
+ * @size: number of bytes to zap
+ * @details: details of nonlinear truncation or shared cache invalidation
+ *
+ * The range must fit into one VMA.
  */
-unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
+static void zap_page_range_single(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *details)
 {
        struct mm_struct *mm = vma->vm_mm;
@@ -1385,9 +1411,10 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
        lru_add_drain();
        tlb_gather_mmu(&tlb, mm, 0);
        update_hiwater_rss(mm);
-       end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
+       mmu_notifier_invalidate_range_start(mm, address, end);
+       unmap_single_vma(&tlb, vma, address, end, &nr_accounted, details);
+       mmu_notifier_invalidate_range_end(mm, address, end);
        tlb_finish_mmu(&tlb, address, end);
-       return end;
 }
 
 /**
@@ -1408,7 +1435,7 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
        if (address < vma->vm_start || address + size > vma->vm_end ||
                        !(vma->vm_flags & VM_PFNMAP))
                return -1;
-       zap_page_range(vma, address, size, NULL);
+       zap_page_range_single(vma, address, size, NULL);
        return 0;
 }
 EXPORT_SYMBOL_GPL(zap_vma_ptes);
@@ -2755,7 +2782,7 @@ static void unmap_mapping_range_vma(struct vm_area_struct *vma,
                unsigned long start_addr, unsigned long end_addr,
                struct zap_details *details)
 {
-       zap_page_range(vma, start_addr, end_addr - start_addr, details);
+       zap_page_range_single(vma, start_addr, end_addr - start_addr, details);
 }
 
 static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
index 230f0ba..a7bf6a3 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -934,6 +934,19 @@ void vm_stat_account(struct mm_struct *mm, unsigned long flags,
 }
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * If a hint addr is less than mmap_min_addr change hint to be as
+ * low as possible but still greater than mmap_min_addr
+ */
+static inline unsigned long round_hint_to_min(unsigned long hint)
+{
+       hint &= PAGE_MASK;
+       if (((void *)hint != NULL) &&
+           (hint < mmap_min_addr))
+               return PAGE_ALIGN(mmap_min_addr);
+       return hint;
+}
+
 /*
  * The caller must hold down_write(&current->mm->mmap_sem).
  */
@@ -1234,7 +1247,7 @@ munmap_back:
         */
        if (accountable_mapping(file, vm_flags)) {
                charged = len >> PAGE_SHIFT;
-               if (security_vm_enough_memory(charged))
+               if (security_vm_enough_memory_mm(mm, charged))
                        return -ENOMEM;
                vm_flags |= VM_ACCOUNT;
        }
@@ -2183,7 +2196,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
        if (mm->map_count > sysctl_max_map_count)
                return -ENOMEM;
 
-       if (security_vm_enough_memory(len >> PAGE_SHIFT))
+       if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
                return -ENOMEM;
 
        /* Can we just expand an old private anonymous mapping? */
@@ -2227,7 +2240,6 @@ void exit_mmap(struct mm_struct *mm)
        struct mmu_gather tlb;
        struct vm_area_struct *vma;
        unsigned long nr_accounted = 0;
-       unsigned long end;
 
        /* mm's last user has gone, and its about to be pulled down */
        mmu_notifier_release(mm);
@@ -2252,11 +2264,11 @@ void exit_mmap(struct mm_struct *mm)
        tlb_gather_mmu(&tlb, mm, 1);
        /* update_hiwater_rss(mm) here? but nobody should be looking */
        /* Use -1 here to ensure all VMAs in the mm are unmapped */
-       end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
+       unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
        vm_unacct_memory(nr_accounted);
 
        free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
-       tlb_finish_mmu(&tlb, 0, end);
+       tlb_finish_mmu(&tlb, 0, -1);
 
        /*
         * Walk the list again, actually closing and freeing it,
index c621e99..a409926 100644 (file)
@@ -168,7 +168,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
                if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_HUGETLB|
                                                VM_SHARED|VM_NORESERVE))) {
                        charged = nrpages;
-                       if (security_vm_enough_memory(charged))
+                       if (security_vm_enough_memory_mm(mm, charged))
                                return -ENOMEM;
                        newflags |= VM_ACCOUNT;
                }
index 87bb839..db8d983 100644 (file)
@@ -329,7 +329,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
 
        if (vma->vm_flags & VM_ACCOUNT) {
                unsigned long charged = (new_len - old_len) >> PAGE_SHIFT;
-               if (security_vm_enough_memory(charged))
+               if (security_vm_enough_memory_mm(mm, charged))
                        goto Efault;
                *p = charged;
        }
index 7cc8083..f99ff3e 100644 (file)
@@ -127,7 +127,7 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
 static inline int shmem_acct_size(unsigned long flags, loff_t size)
 {
        return (flags & VM_NORESERVE) ?
-               0 : security_vm_enough_memory_kern(VM_ACCT(size));
+               0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size));
 }
 
 static inline void shmem_unacct_size(unsigned long flags, loff_t size)
@@ -145,7 +145,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
 static inline int shmem_acct_block(unsigned long flags)
 {
        return (flags & VM_NORESERVE) ?
-               security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0;
+               security_vm_enough_memory_mm(current->mm, VM_ACCT(PAGE_CACHE_SIZE)) : 0;
 }
 
 static inline void shmem_unacct_blocks(unsigned long flags, long pages)
@@ -2231,7 +2231,6 @@ static void shmem_put_super(struct super_block *sb)
 int shmem_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
-       struct dentry *root;
        struct shmem_sb_info *sbinfo;
        int err = -ENOMEM;
 
@@ -2288,14 +2287,11 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
                goto failed;
        inode->i_uid = sbinfo->uid;
        inode->i_gid = sbinfo->gid;
-       root = d_alloc_root(inode);
-       if (!root)
-               goto failed_iput;
-       sb->s_root = root;
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root)
+               goto failed;
        return 0;
 
-failed_iput:
-       iput(inode);
 failed:
        shmem_put_super(sb);
        return err;
index 21b5694..dae42f3 100644 (file)
@@ -1561,6 +1561,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
+       BUG_ON(!current->mm);
+
        pathname = getname(specialfile);
        err = PTR_ERR(pathname);
        if (IS_ERR(pathname))
@@ -1588,7 +1590,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
                spin_unlock(&swap_lock);
                goto out_dput;
        }
-       if (!security_vm_enough_memory(p->pages))
+       if (!security_vm_enough_memory_mm(current->mm, p->pages))
                vm_unacct_memory(p->pages);
        else {
                err = -ENOMEM;
index fa000d2..c73bba3 100644 (file)
@@ -281,6 +281,7 @@ static int __init init_dns_resolver(void)
 
        /* instruct request_key() to use this special keyring as a cache for
         * the results it looks up */
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
        cred->thread_keyring = keyring;
        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
        dns_resolver_cache = cred;
index 63a7a7a..7d6dd6e 100644 (file)
@@ -1033,13 +1033,9 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_time_gran = 1;
 
        inode = rpc_get_inode(sb, S_IFDIR | 0755);
-       if (!inode)
-               return -ENOMEM;
-       sb->s_root = root = d_alloc_root(inode);
-       if (!root) {
-               iput(inode);
+       sb->s_root = root = d_make_root(inode);
+       if (!root)
                return -ENOMEM;
-       }
        if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
                return -ENOMEM;
        return 0;
index 8ee85aa..eb4277c 100644 (file)
@@ -293,7 +293,7 @@ static struct sock *unix_find_socket_byinode(struct inode *i)
        spin_lock(&unix_table_lock);
        sk_for_each(s, node,
                    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
-               struct dentry *dentry = unix_sk(s)->dentry;
+               struct dentry *dentry = unix_sk(s)->path.dentry;
 
                if (dentry && dentry->d_inode == i) {
                        sock_hold(s);
@@ -377,8 +377,7 @@ static void unix_sock_destructor(struct sock *sk)
 static int unix_release_sock(struct sock *sk, int embrion)
 {
        struct unix_sock *u = unix_sk(sk);
-       struct dentry *dentry;
-       struct vfsmount *mnt;
+       struct path path;
        struct sock *skpair;
        struct sk_buff *skb;
        int state;
@@ -389,10 +388,9 @@ static int unix_release_sock(struct sock *sk, int embrion)
        unix_state_lock(sk);
        sock_orphan(sk);
        sk->sk_shutdown = SHUTDOWN_MASK;
-       dentry       = u->dentry;
-       u->dentry    = NULL;
-       mnt          = u->mnt;
-       u->mnt       = NULL;
+       path         = u->path;
+       u->path.dentry = NULL;
+       u->path.mnt = NULL;
        state = sk->sk_state;
        sk->sk_state = TCP_CLOSE;
        unix_state_unlock(sk);
@@ -425,10 +423,8 @@ static int unix_release_sock(struct sock *sk, int embrion)
                kfree_skb(skb);
        }
 
-       if (dentry) {
-               dput(dentry);
-               mntput(mnt);
-       }
+       if (path.dentry)
+               path_put(&path);
 
        sock_put(sk);
 
@@ -641,8 +637,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
        sk->sk_max_ack_backlog  = net->unx.sysctl_max_dgram_qlen;
        sk->sk_destruct         = unix_sock_destructor;
        u         = unix_sk(sk);
-       u->dentry = NULL;
-       u->mnt    = NULL;
+       u->path.dentry = NULL;
+       u->path.mnt = NULL;
        spin_lock_init(&u->lock);
        atomic_long_set(&u->inflight, 0);
        INIT_LIST_HEAD(&u->link);
@@ -788,7 +784,7 @@ static struct sock *unix_find_other(struct net *net,
                        goto put_fail;
 
                if (u->sk_type == type)
-                       touch_atime(path.mnt, path.dentry);
+                       touch_atime(&path);
 
                path_put(&path);
 
@@ -802,9 +798,9 @@ static struct sock *unix_find_other(struct net *net,
                u = unix_find_socket_byname(net, sunname, len, type, hash);
                if (u) {
                        struct dentry *dentry;
-                       dentry = unix_sk(u)->dentry;
+                       dentry = unix_sk(u)->path.dentry;
                        if (dentry)
-                               touch_atime(unix_sk(u)->mnt, dentry);
+                               touch_atime(&unix_sk(u)->path);
                } else
                        goto fail;
        }
@@ -910,8 +906,7 @@ out_mknod_drop_write:
                list = &unix_socket_table[addr->hash];
        } else {
                list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
-               u->dentry = path.dentry;
-               u->mnt    = path.mnt;
+               u->path = path;
        }
 
        err = 0;
@@ -1193,9 +1188,9 @@ restart:
                atomic_inc(&otheru->addr->refcnt);
                newu->addr = otheru->addr;
        }
-       if (otheru->dentry) {
-               newu->dentry    = dget(otheru->dentry);
-               newu->mnt       = mntget(otheru->mnt);
+       if (otheru->path.dentry) {
+               path_get(&otheru->path);
+               newu->path = otheru->path;
        }
 
        /* Set credentials */
index 4195555..f0486ae 100644 (file)
@@ -29,7 +29,7 @@ rtattr_failure:
 
 static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
 {
-       struct dentry *dentry = unix_sk(sk)->dentry;
+       struct dentry *dentry = unix_sk(sk)->path.dentry;
        struct unix_diag_vfs *uv;
 
        if (dentry) {
index 51bd5a0..ccc61f8 100644 (file)
@@ -187,6 +187,7 @@ source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
+source security/yama/Kconfig
 
 source security/integrity/Kconfig
 
@@ -196,6 +197,7 @@ choice
        default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
        default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
        default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
+       default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
        default DEFAULT_SECURITY_DAC
 
        help
@@ -214,6 +216,9 @@ choice
        config DEFAULT_SECURITY_APPARMOR
                bool "AppArmor" if SECURITY_APPARMOR=y
 
+       config DEFAULT_SECURITY_YAMA
+               bool "Yama" if SECURITY_YAMA=y
+
        config DEFAULT_SECURITY_DAC
                bool "Unix Discretionary Access Controls"
 
@@ -225,6 +230,7 @@ config DEFAULT_SECURITY
        default "smack" if DEFAULT_SECURITY_SMACK
        default "tomoyo" if DEFAULT_SECURITY_TOMOYO
        default "apparmor" if DEFAULT_SECURITY_APPARMOR
+       default "yama" if DEFAULT_SECURITY_YAMA
        default "" if DEFAULT_SECURITY_DAC
 
 endmenu
index a5e502f..c26c81e 100644 (file)
@@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX)       += selinux
 subdir-$(CONFIG_SECURITY_SMACK)                += smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor
+subdir-$(CONFIG_SECURITY_YAMA)         += yama
 
 # always enable default capabilities
 obj-y                                  += commoncap.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_SECURITY_SMACK)          += smack/built-in.o
 obj-$(CONFIG_AUDIT)                    += lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
 obj-$(CONFIG_SECURITY_APPARMOR)                += apparmor/built-in.o
+obj-$(CONFIG_SECURITY_YAMA)            += yama/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
 
 # Object integrity file lists
index 2dafe50..806bd19 100644 (file)
@@ -15,7 +15,7 @@ clean-files := capability_names.h rlim_names.h
 # to
 #    [1] = "dac_override",
 quiet_cmd_make-caps = GEN     $@
-cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\
+cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
        sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \
        -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
        echo "};" >> $@
@@ -28,25 +28,38 @@ cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\
 #    [RLIMIT_STACK] = "stack",
 #
 # and build a second integer table (with the second sed cmd), that maps
-# RLIMIT defines to the order defined in asm-generic/resource.h  Thi is
+# RLIMIT defines to the order defined in asm-generic/resource.h  This is
 # required by policy load to map policy ordering of RLIMITs to internal
 # ordering for architectures that redefine an RLIMIT.
 # Transforms lines from
 #    #define RLIMIT_STACK              3       /* max stack size */
 # to
 # RLIMIT_STACK, 
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+#    #define RLIMIT_FSIZE        1   /* Maximum filesize */
+#    #define RLIMIT_STACK              3       /* max stack size */
+# to
+# #define AA_FS_RLIMIT_MASK "fsize stack"
 quiet_cmd_make-rlim = GEN     $@
-cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\
+cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
+       > $@ ;\
        sed $< >> $@ -r -n \
            -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\
        echo "};" >> $@ ;\
-       echo "static const int rlim_map[] = {" >> $@ ;\
+       echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\
        sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\
-       echo "};" >> $@
+       echo "};" >> $@ ; \
+       echo -n '\#define AA_FS_RLIMIT_MASK "' >> $@ ;\
+       sed -r -n 's/^\# ?define[ \t]+RLIMIT_([A-Z0-9_]+).*/\L\1/p' $< | \
+           tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
 
 $(obj)/capability.o : $(obj)/capability_names.h
 $(obj)/resource.o : $(obj)/rlim_names.h
-$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \
+                           $(src)/Makefile
        $(call cmd,make-caps)
-$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
+$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \
+                     $(src)/Makefile
        $(call cmd,make-rlim)
index e39df6d..16c15ec 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/namei.h>
+#include <linux/capability.h>
 
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
 #include "include/audit.h"
 #include "include/context.h"
 #include "include/policy.h"
+#include "include/resource.h"
 
 /**
  * aa_simple_write_to_buffer - common routine for getting policy from user
@@ -142,38 +144,166 @@ static const struct file_operations aa_fs_profile_remove = {
        .llseek = default_llseek,
 };
 
-/** Base file system setup **/
+static int aa_fs_seq_show(struct seq_file *seq, void *v)
+{
+       struct aa_fs_entry *fs_file = seq->private;
+
+       if (!fs_file)
+               return 0;
 
-static struct dentry *aa_fs_dentry __initdata;
+       switch (fs_file->v_type) {
+       case AA_FS_TYPE_BOOLEAN:
+               seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
+               break;
+       case AA_FS_TYPE_STRING:
+               seq_printf(seq, "%s\n", fs_file->v.string);
+               break;
+       case AA_FS_TYPE_U64:
+               seq_printf(seq, "%#08lx\n", fs_file->v.u64);
+               break;
+       default:
+               /* Ignore unpritable entry types. */
+               break;
+       }
+
+       return 0;
+}
 
-static void __init aafs_remove(const char *name)
+static int aa_fs_seq_open(struct inode *inode, struct file *file)
 {
-       struct dentry *dentry;
+       return single_open(file, aa_fs_seq_show, inode->i_private);
+}
+
+const struct file_operations aa_fs_seq_file_ops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/** Base file system setup **/
+
+static struct aa_fs_entry aa_fs_entry_file[] = {
+       AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
+                                 "link lock"),
+       { }
+};
 
-       dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
-       if (!IS_ERR(dentry)) {
-               securityfs_remove(dentry);
-               dput(dentry);
+static struct aa_fs_entry aa_fs_entry_domain[] = {
+       AA_FS_FILE_BOOLEAN("change_hat",        1),
+       AA_FS_FILE_BOOLEAN("change_hatv",       1),
+       AA_FS_FILE_BOOLEAN("change_onexec",     1),
+       AA_FS_FILE_BOOLEAN("change_profile",    1),
+       { }
+};
+
+static struct aa_fs_entry aa_fs_entry_features[] = {
+       AA_FS_DIR("domain",                     aa_fs_entry_domain),
+       AA_FS_DIR("file",                       aa_fs_entry_file),
+       AA_FS_FILE_U64("capability",            VFS_CAP_FLAGS_MASK),
+       AA_FS_DIR("rlimit",                     aa_fs_entry_rlimit),
+       { }
+};
+
+static struct aa_fs_entry aa_fs_entry_apparmor[] = {
+       AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
+       AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
+       AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
+       AA_FS_DIR("features", aa_fs_entry_features),
+       { }
+};
+
+static struct aa_fs_entry aa_fs_entry =
+       AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
+
+/**
+ * aafs_create_file - create a file entry in the apparmor securityfs
+ * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
+ * @parent: the parent dentry in the securityfs
+ *
+ * Use aafs_remove_file to remove entries created with this fn.
+ */
+static int __init aafs_create_file(struct aa_fs_entry *fs_file,
+                                  struct dentry *parent)
+{
+       int error = 0;
+
+       fs_file->dentry = securityfs_create_file(fs_file->name,
+                                                S_IFREG | fs_file->mode,
+                                                parent, fs_file,
+                                                fs_file->file_ops);
+       if (IS_ERR(fs_file->dentry)) {
+               error = PTR_ERR(fs_file->dentry);
+               fs_file->dentry = NULL;
        }
+       return error;
 }
 
 /**
- * aafs_create - create an entry in the apparmor filesystem
- * @name: name of the entry (NOT NULL)
- * @mask: file permission mask of the file
- * @fops: file operations for the file (NOT NULL)
+ * aafs_create_dir - recursively create a directory entry in the securityfs
+ * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
+ * @parent: the parent dentry in the securityfs
  *
- * Used aafs_remove to remove entries created with this fn.
+ * Use aafs_remove_dir to remove entries created with this fn.
  */
-static int __init aafs_create(const char *name, umode_t mask,
-                             const struct file_operations *fops)
+static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
+                                 struct dentry *parent)
 {
-       struct dentry *dentry;
+       int error;
+       struct aa_fs_entry *fs_file;
 
-       dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
-                                       NULL, fops);
+       fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent);
+       if (IS_ERR(fs_dir->dentry)) {
+               error = PTR_ERR(fs_dir->dentry);
+               fs_dir->dentry = NULL;
+               goto failed;
+       }
 
-       return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+       for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) {
+               if (fs_file->v_type == AA_FS_TYPE_DIR)
+                       error = aafs_create_dir(fs_file, fs_dir->dentry);
+               else
+                       error = aafs_create_file(fs_file, fs_dir->dentry);
+               if (error)
+                       goto failed;
+       }
+
+       return 0;
+
+failed:
+       return error;
+}
+
+/**
+ * aafs_remove_file - drop a single file entry in the apparmor securityfs
+ * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
+ */
+static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
+{
+       if (!fs_file->dentry)
+               return;
+
+       securityfs_remove(fs_file->dentry);
+       fs_file->dentry = NULL;
+}
+
+/**
+ * aafs_remove_dir - recursively drop a directory entry from the securityfs
+ * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
+ */
+static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
+{
+       struct aa_fs_entry *fs_file;
+
+       for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) {
+               if (fs_file->v_type == AA_FS_TYPE_DIR)
+                       aafs_remove_dir(fs_file);
+               else
+                       aafs_remove_file(fs_file);
+       }
+
+       aafs_remove_file(fs_dir);
 }
 
 /**
@@ -183,14 +313,7 @@ static int __init aafs_create(const char *name, umode_t mask,
  */
 void __init aa_destroy_aafs(void)
 {
-       if (aa_fs_dentry) {
-               aafs_remove(".remove");
-               aafs_remove(".replace");
-               aafs_remove(".load");
-
-               securityfs_remove(aa_fs_dentry);
-               aa_fs_dentry = NULL;
-       }
+       aafs_remove_dir(&aa_fs_entry);
 }
 
 /**
@@ -207,25 +330,13 @@ static int __init aa_create_aafs(void)
        if (!apparmor_initialized)
                return 0;
 
-       if (aa_fs_dentry) {
+       if (aa_fs_entry.dentry) {
                AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
                return -EEXIST;
        }
 
-       aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
-       if (IS_ERR(aa_fs_dentry)) {
-               error = PTR_ERR(aa_fs_dentry);
-               aa_fs_dentry = NULL;
-               goto error;
-       }
-
-       error = aafs_create(".load", 0640, &aa_fs_profile_load);
-       if (error)
-               goto error;
-       error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
-       if (error)
-               goto error;
-       error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
+       /* Populate fs tree. */
+       error = aafs_create_dir(&aa_fs_entry, NULL);
        if (error)
                goto error;
 
index f3fafed..5ff6777 100644 (file)
@@ -19,7 +19,7 @@
 #include "include/audit.h"
 #include "include/policy.h"
 
-const char *op_table[] = {
+const char *const op_table[] = {
        "null",
 
        "sysctl",
@@ -73,7 +73,7 @@ const char *op_table[] = {
        "profile_remove"
 };
 
-const char *audit_mode_names[] = {
+const char *const audit_mode_names[] = {
        "normal",
        "quiet_denied",
        "quiet",
@@ -81,7 +81,7 @@ const char *audit_mode_names[] = {
        "all"
 };
 
-static char *aa_audit_type[] = {
+static const char *const aa_audit_type[] = {
        "AUDIT",
        "ALLOWED",
        "DENIED",
@@ -89,6 +89,7 @@ static char *aa_audit_type[] = {
        "STATUS",
        "ERROR",
        "KILLED"
+       "AUTO"
 };
 
 /*
index c1e18ba..7c69599 100644 (file)
@@ -372,13 +372,12 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        state = profile->file.start;
 
        /* buffer freed below, name is pointer into buffer */
-       error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer,
-                           &name);
+       error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer,
+                            &name, &info);
        if (error) {
                if (profile->flags &
                    (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED))
                        error = 0;
-               info = "Exec failed name resolution";
                name = bprm->filename;
                goto audit;
        }
index 7312db7..3022c0f 100644 (file)
@@ -173,8 +173,6 @@ static u32 map_old_perms(u32 old)
        if (old & 0x40) /* AA_EXEC_MMAP */
                new |= AA_EXEC_MMAP;
 
-       new |= AA_MAY_META_READ;
-
        return new;
 }
 
@@ -212,6 +210,7 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
                perms.quiet = map_old_perms(dfa_other_quiet(dfa, state));
                perms.xindex = dfa_other_xindex(dfa, state);
        }
+       perms.allow |= AA_MAY_META_READ;
 
        /* change_profile wasn't determined by ownership in old mapping */
        if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
@@ -279,22 +278,16 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
        int error;
 
        flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
-       error = aa_get_name(path, flags, &buffer, &name);
+       error = aa_path_name(path, flags, &buffer, &name, &info);
        if (error) {
                if (error == -ENOENT && is_deleted(path->dentry)) {
                        /* Access to open files that are deleted are
                         * give a pass (implicit delegation)
                         */
                        error = 0;
+                       info = NULL;
                        perms.allow = request;
-               } else if (error == -ENOENT)
-                       info = "Failed name lookup - deleted entry";
-               else if (error == -ESTALE)
-                       info = "Failed name lookup - disconnected path";
-               else if (error == -ENAMETOOLONG)
-                       info = "Failed name lookup - name too long";
-               else
-                       info = "Failed name lookup";
+               }
        } else {
                aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
                             &perms);
@@ -365,12 +358,14 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
        lperms = nullperms;
 
        /* buffer freed below, lname is pointer in buffer */
-       error = aa_get_name(&link, profile->path_flags, &buffer, &lname);
+       error = aa_path_name(&link, profile->path_flags, &buffer, &lname,
+                            &info);
        if (error)
                goto audit;
 
        /* buffer2 freed below, tname is pointer in buffer2 */
-       error = aa_get_name(&target, profile->path_flags, &buffer2, &tname);
+       error = aa_path_name(&target, profile->path_flags, &buffer2, &tname,
+                            &info);
        if (error)
                goto audit;
 
index df36495..40aedd9 100644 (file)
 
 #include "match.h"
 
+/*
+ * Class of mediation types in the AppArmor policy db
+ */
+#define AA_CLASS_ENTRY         0
+#define AA_CLASS_UNKNOWN       1
+#define AA_CLASS_FILE          2
+#define AA_CLASS_CAP           3
+#define AA_CLASS_NET           4
+#define AA_CLASS_RLIMITS       5
+#define AA_CLASS_DOMAIN                6
+
+#define AA_CLASS_LAST          AA_CLASS_DOMAIN
+
 /* Control parameters settable through module/boot flags */
 extern enum audit_mode aa_g_audit;
 extern bool aa_g_audit_header;
@@ -81,7 +94,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
                                                  unsigned int start)
 {
        /* the null transition only needs the string's null terminator byte */
-       return aa_dfa_match_len(dfa, start, "", 1);
+       return aa_dfa_next(dfa, start, 0);
 }
 
 static inline bool mediated_filesystem(struct inode *inode)
index cb1e93a..7ea4769 100644 (file)
 #ifndef __AA_APPARMORFS_H
 #define __AA_APPARMORFS_H
 
+enum aa_fs_type {
+       AA_FS_TYPE_BOOLEAN,
+       AA_FS_TYPE_STRING,
+       AA_FS_TYPE_U64,
+       AA_FS_TYPE_FOPS,
+       AA_FS_TYPE_DIR,
+};
+
+struct aa_fs_entry;
+
+struct aa_fs_entry {
+       const char *name;
+       struct dentry *dentry;
+       umode_t mode;
+       enum aa_fs_type v_type;
+       union {
+               bool boolean;
+               char *string;
+               unsigned long u64;
+               struct aa_fs_entry *files;
+       } v;
+       const struct file_operations *file_ops;
+};
+
+extern const struct file_operations aa_fs_seq_file_ops;
+
+#define AA_FS_FILE_BOOLEAN(_name, _value) \
+       { .name = (_name), .mode = 0444, \
+         .v_type = AA_FS_TYPE_BOOLEAN, .v.boolean = (_value), \
+         .file_ops = &aa_fs_seq_file_ops }
+#define AA_FS_FILE_STRING(_name, _value) \
+       { .name = (_name), .mode = 0444, \
+         .v_type = AA_FS_TYPE_STRING, .v.string = (_value), \
+         .file_ops = &aa_fs_seq_file_ops }
+#define AA_FS_FILE_U64(_name, _value) \
+       { .name = (_name), .mode = 0444, \
+         .v_type = AA_FS_TYPE_U64, .v.u64 = (_value), \
+         .file_ops = &aa_fs_seq_file_ops }
+#define AA_FS_FILE_FOPS(_name, _mode, _fops) \
+       { .name = (_name), .v_type = AA_FS_TYPE_FOPS, \
+         .mode = (_mode), .file_ops = (_fops) }
+#define AA_FS_DIR(_name, _value) \
+       { .name = (_name), .v_type = AA_FS_TYPE_DIR, .v.files = (_value) }
+
 extern void __init aa_destroy_aafs(void);
 
 #endif /* __AA_APPARMORFS_H */
index 1951786..4ba78c2 100644 (file)
 
 struct aa_profile;
 
-extern const char *audit_mode_names[];
+extern const char *const audit_mode_names[];
 #define AUDIT_MAX_INDEX 5
 
-#define AUDIT_APPARMOR_AUTO 0  /* auto choose audit message type */
-
 enum audit_mode {
        AUDIT_NORMAL,           /* follow normal auditing of accesses */
        AUDIT_QUIET_DENIED,     /* quiet all denied access messages */
@@ -45,10 +43,11 @@ enum audit_type {
        AUDIT_APPARMOR_HINT,
        AUDIT_APPARMOR_STATUS,
        AUDIT_APPARMOR_ERROR,
-       AUDIT_APPARMOR_KILL
+       AUDIT_APPARMOR_KILL,
+       AUDIT_APPARMOR_AUTO
 };
 
-extern const char *op_table[];
+extern const char *const op_table[];
 enum aa_ops {
        OP_NULL,
 
index ab8c6d8..f98fd47 100644 (file)
@@ -117,7 +117,7 @@ static inline u16 dfa_map_xindex(u16 mask)
                index |= AA_X_NAME;
        } else if (old_index == 3) {
                index |= AA_X_NAME | AA_X_CHILD;
-       } else {
+       } else if (old_index) {
                index |= AA_X_TABLE;
                index |= old_index - 4;
        }
index a4a8639..775843e 100644 (file)
@@ -116,6 +116,9 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
                              const char *str, int len);
 unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                          const char *str);
+unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
+                        const char c);
+
 void aa_dfa_free_kref(struct kref *kref);
 
 /**
index 27b327a..286ac75 100644 (file)
@@ -26,6 +26,7 @@ enum path_flags {
        PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
 };
 
-int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
+int aa_path_name(struct path *path, int flags, char **buffer,
+                const char **name, const char **info);
 
 #endif /* __AA_PATH_H */
index aeda5cf..bda4569 100644 (file)
@@ -29,7 +29,7 @@
 #include "file.h"
 #include "resource.h"
 
-extern const char *profile_mode_names[];
+extern const char *const profile_mode_names[];
 #define APPARMOR_NAMES_MAX_INDEX 3
 
 #define COMPLAIN_MODE(_profile)        \
@@ -129,6 +129,17 @@ struct aa_namespace {
        struct list_head sub_ns;
 };
 
+/* struct aa_policydb - match engine for a policy
+ * dfa: dfa pattern match
+ * start: set of start states for the different classes of data
+ */
+struct aa_policydb {
+       /* Generic policy DFA specific rule types will be subsections of it */
+       struct aa_dfa *dfa;
+       unsigned int start[AA_CLASS_LAST + 1];
+
+};
+
 /* struct aa_profile - basic confinement data
  * @base - base components of the profile (name, refcount, lists, lock ...)
  * @parent: parent of profile
@@ -143,6 +154,7 @@ struct aa_namespace {
  * @flags: flags controlling profile behavior
  * @path_flags: flags controlling path generation behavior
  * @size: the memory consumed by this profiles rules
+ * @policy: general match rules governing policy
  * @file: The set of rules governing basic file access and domain transitions
  * @caps: capabilities for the profile
  * @rlimits: rlimits for the profile
@@ -179,6 +191,7 @@ struct aa_profile {
        u32 path_flags;
        int size;
 
+       struct aa_policydb policy;
        struct aa_file_rules file;
        struct aa_caps caps;
        struct aa_rlimit rlimits;
index 02baec7..d3f4cf0 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/resource.h>
 #include <linux/sched.h>
 
+#include "apparmorfs.h"
+
 struct aa_profile;
 
 /* struct aa_rlimit - rlimit settings for the profile
@@ -32,6 +34,8 @@ struct aa_rlimit {
        struct rlimit limits[RLIM_NLIMITS];
 };
 
+extern struct aa_fs_entry aa_fs_entry_rlimit[];
+
 int aa_map_resource(int resource);
 int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *,
                      unsigned int resource, struct rlimit *new_rlim);
index 94de6b4..90971a8 100644 (file)
@@ -335,12 +335,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
 }
 
 /**
- * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * aa_dfa_match - traverse @dfa to find state @str stops at
  * @dfa: the dfa to match @str against  (NOT NULL)
  * @start: the state of the dfa to start matching in
  * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
  *
- * aa_dfa_next_state will match @str against the dfa and return the state it
+ * aa_dfa_match will match @str against the dfa and return the state it
  * finished matching in. The final state can be used to look up the accepting
  * label, or as the start state of a continuing match.
  *
@@ -349,5 +349,79 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
 unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                          const char *str)
 {
-       return aa_dfa_match_len(dfa, start, str, strlen(str));
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       unsigned int state = start, pos;
+
+       if (state == 0)
+               return 0;
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               /* default is direct to next state */
+               while (*str) {
+                       pos = base[state] + equiv[(u8) *str++];
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+               }
+       } else {
+               /* default is direct to next state */
+               while (*str) {
+                       pos = base[state] + (u8) *str++;
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+               }
+       }
+
+       return state;
+}
+
+/**
+ * aa_dfa_next - step one character to the next state in the dfa
+ * @dfa: the dfa to tranverse (NOT NULL)
+ * @state: the state to start in
+ * @c: the input character to transition on
+ *
+ * aa_dfa_match will step through the dfa by one input character @c
+ *
+ * Returns: state reach after input @c
+ */
+unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
+                         const char c)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       unsigned int pos;
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               /* default is direct to next state */
+
+               pos = base[state] + equiv[(u8) c];
+               if (check[pos] == state)
+                       state = next[pos];
+               else
+                       state = def[state];
+       } else {
+               /* default is direct to next state */
+               pos = base[state] + (u8) c;
+               if (check[pos] == state)
+                       state = next[pos];
+               else
+                       state = def[state];
+       }
+
+       return state;
 }
index 9d070a7..2daeea4 100644 (file)
@@ -83,31 +83,29 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
                struct path root;
                get_fs_root(current->fs, &root);
                res = __d_path(path, &root, buf, buflen);
-               if (res && !IS_ERR(res)) {
-                       /* everything's fine */
-                       *name = res;
-                       path_put(&root);
-                       goto ok;
-               }
                path_put(&root);
-               connected = 0;
+       } else {
+               res = d_absolute_path(path, buf, buflen);
+               if (!our_mnt(path->mnt))
+                       connected = 0;
        }
 
-       res = d_absolute_path(path, buf, buflen);
-
-       *name = res;
        /* handle error conditions - and still allow a partial path to
         * be returned.
         */
-       if (IS_ERR(res)) {
-               error = PTR_ERR(res);
-               *name = buf;
-               goto out;
-       }
-       if (!our_mnt(path->mnt))
+       if (!res || IS_ERR(res)) {
                connected = 0;
+               res = dentry_path_raw(path->dentry, buf, buflen);
+               if (IS_ERR(res)) {
+                       error = PTR_ERR(res);
+                       *name = buf;
+                       goto out;
+               };
+       } else if (!our_mnt(path->mnt))
+               connected = 0;
+
+       *name = res;
 
-ok:
        /* Handle two cases:
         * 1. A deleted dentry && profile is not allowing mediation of deleted
         * 2. On some filesystems, newly allocated dentries appear to the
@@ -138,7 +136,7 @@ ok:
                        /* disconnected path, don't return pathname starting
                         * with '/'
                         */
-                       error = -ESTALE;
+                       error = -EACCES;
                        if (*res == '/')
                                *name = res + 1;
                }
@@ -159,7 +157,7 @@ out:
  * Returns: %0 else error on failure
  */
 static int get_name_to_buffer(struct path *path, int flags, char *buffer,
-                             int size, char **name)
+                             int size, char **name, const char **info)
 {
        int adjust = (flags & PATH_IS_DIR) ? 1 : 0;
        int error = d_namespace_path(path, buffer, size - adjust, name, flags);
@@ -171,15 +169,27 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
                 */
                strcpy(&buffer[size - 2], "/");
 
+       if (info && error) {
+               if (error == -ENOENT)
+                       *info = "Failed name lookup - deleted entry";
+               else if (error == -ESTALE)
+                       *info = "Failed name lookup - disconnected path";
+               else if (error == -ENAMETOOLONG)
+                       *info = "Failed name lookup - name too long";
+               else
+                       *info = "Failed name lookup";
+       }
+
        return error;
 }
 
 /**
- * aa_get_name - compute the pathname of a file
+ * aa_path_name - compute the pathname of a file
  * @path: path the file  (NOT NULL)
  * @flags: flags controlling path name generation
  * @buffer: buffer that aa_get_name() allocated  (NOT NULL)
  * @name: Returns - the generated path name if !error (NOT NULL)
+ * @info: Returns - information on why the path lookup failed (MAYBE NULL)
  *
  * @name is a pointer to the beginning of the pathname (which usually differs
  * from the beginning of the buffer), or NULL.  If there is an error @name
@@ -192,7 +202,8 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
  *
  * Returns: %0 else error code if could retrieve name
  */
-int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
+int aa_path_name(struct path *path, int flags, char **buffer, const char **name,
+                const char **info)
 {
        char *buf, *str = NULL;
        int size = 256;
@@ -206,7 +217,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
                if (!buf)
                        return -ENOMEM;
 
-               error = get_name_to_buffer(path, flags, buf, size, &str);
+               error = get_name_to_buffer(path, flags, buf, size, &str, info);
                if (error != -ENAMETOOLONG)
                        break;
 
@@ -214,6 +225,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
                size <<= 1;
                if (size > aa_g_path_max)
                        return -ENAMETOOLONG;
+               *info = NULL;
        }
        *buffer = buf;
        *name = str;
index 4f0eade..9064143 100644 (file)
@@ -93,7 +93,7 @@
 /* root profile namespace */
 struct aa_namespace *root_ns;
 
-const char *profile_mode_names[] = {
+const char *const profile_mode_names[] = {
        "enforce",
        "complain",
        "kill",
@@ -749,6 +749,7 @@ static void free_profile(struct aa_profile *profile)
 
        aa_free_sid(profile->sid);
        aa_put_dfa(profile->xmatch);
+       aa_put_dfa(profile->policy.dfa);
 
        aa_put_profile(profile->replacedby);
 
index 741dd13..25fd51e 100644 (file)
@@ -84,7 +84,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
  * @new: profile if it has been allocated (MAYBE NULL)
  * @name: name of the profile being manipulated (MAYBE NULL)
  * @info: any extra info about the failure (MAYBE NULL)
- * @e: buffer position info (NOT NULL)
+ * @e: buffer position info
  * @error: error code
  *
  * Returns: %0 or error
@@ -95,7 +95,8 @@ static int audit_iface(struct aa_profile *new, const char *name,
        struct aa_profile *profile = __aa_current_profile();
        struct common_audit_data sa;
        COMMON_AUDIT_DATA_INIT(&sa, NONE);
-       sa.aad.iface.pos = e->pos - e->start;
+       if (e)
+               sa.aad.iface.pos = e->pos - e->start;
        sa.aad.iface.target = new;
        sa.aad.name = name;
        sa.aad.info = info;
@@ -468,7 +469,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
 {
        struct aa_profile *profile = NULL;
        const char *name = NULL;
-       int error = -EPROTO;
+       int i, error = -EPROTO;
        kernel_cap_t tmpcap;
        u32 tmp;
 
@@ -554,11 +555,35 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
                        goto fail;
                if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
                        goto fail;
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
        }
 
        if (!unpack_rlimits(e, profile))
                goto fail;
 
+       if (unpack_nameX(e, AA_STRUCT, "policydb")) {
+               /* generic policy dfa - optional and may be NULL */
+               profile->policy.dfa = unpack_dfa(e);
+               if (IS_ERR(profile->policy.dfa)) {
+                       error = PTR_ERR(profile->policy.dfa);
+                       profile->policy.dfa = NULL;
+                       goto fail;
+               }
+               if (!unpack_u32(e, &profile->policy.start[0], "start"))
+                       /* default start state */
+                       profile->policy.start[0] = DFA_START;
+               /* setup class index */
+               for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) {
+                       profile->policy.start[i] =
+                               aa_dfa_next(profile->policy.dfa,
+                                           profile->policy.start[0],
+                                           i);
+               }
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+
        /* get file rules */
        profile->file.dfa = unpack_dfa(e);
        if (IS_ERR(profile->file.dfa)) {
index a4136c1..72c25a4 100644 (file)
  */
 #include "rlim_names.h"
 
+struct aa_fs_entry aa_fs_entry_rlimit[] = {
+       AA_FS_FILE_STRING("mask", AA_FS_RLIMIT_MASK),
+       { }
+};
+
 /* audit callback for resource specific fields */
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
index 2f680eb..5bb21b1 100644 (file)
@@ -358,6 +358,10 @@ static int cap_task_create(unsigned long clone_flags)
        return 0;
 }
 
+static void cap_task_free(struct task_struct *task)
+{
+}
+
 static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
        return 0;
@@ -954,6 +958,7 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, file_receive);
        set_to_cap_if_null(ops, dentry_open);
        set_to_cap_if_null(ops, task_create);
+       set_to_cap_if_null(ops, task_free);
        set_to_cap_if_null(ops, cred_alloc_blank);
        set_to_cap_if_null(ops, cred_free);
        set_to_cap_if_null(ops, cred_prepare);
index 7ce191e..0cf4b53 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/prctl.h>
 #include <linux/securebits.h>
 #include <linux/user_namespace.h>
+#include <linux/binfmts.h>
 
 /*
  * If a non-root user executes a setuid-root binary in
index 4f554f2..35664fe 100644 (file)
@@ -9,8 +9,8 @@ config IMA
        select CRYPTO_HMAC
        select CRYPTO_MD5
        select CRYPTO_SHA1
-       select TCG_TPM if !S390 && !UML
-       select TCG_TIS if TCG_TPM
+       select TCG_TPM if HAS_IOMEM && !UML
+       select TCG_TIS if TCG_TPM && X86
        help
          The Trusted Computing Group(TCG) runtime Integrity
          Measurement Architecture(IMA) maintains a list of hash
index 2ad942f..21e96bf 100644 (file)
@@ -61,6 +61,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
                audit_log_untrustedstring(ab, inode->i_sb->s_id);
                audit_log_format(ab, " ino=%lu", inode->i_ino);
        }
-       audit_log_format(ab, " res=%d", !result ? 0 : 1);
+       audit_log_format(ab, " res=%d", !result);
        audit_log_end(ab);
 }
index d45061d..d8edff2 100644 (file)
@@ -62,6 +62,7 @@ static struct ima_measure_rule_entry default_rules[] = {
        {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC},
+       {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC},
        {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC},
        {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC,
@@ -417,7 +418,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry)
        if (!result && (entry->action == UNKNOWN))
                result = -EINVAL;
 
-       audit_log_format(ab, "res=%d", !!result);
+       audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
        return result;
 }
index 0b3f5d7..6523599 100644 (file)
@@ -388,11 +388,24 @@ long keyctl_keyring_clear(key_serial_t ringid)
        keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
+
+               /* Root is permitted to invalidate certain special keyrings */
+               if (capable(CAP_SYS_ADMIN)) {
+                       keyring_ref = lookup_user_key(ringid, 0, 0);
+                       if (IS_ERR(keyring_ref))
+                               goto error;
+                       if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR,
+                                    &key_ref_to_ptr(keyring_ref)->flags))
+                               goto clear;
+                       goto error_put;
+               }
+
                goto error;
        }
 
+clear:
        ret = keyring_clear(key_ref_to_ptr(keyring_ref));
-
+error_put:
        key_ref_put(keyring_ref);
 error:
        return ret;
index 1068cb1..be7ecb2 100644 (file)
@@ -657,7 +657,8 @@ try_again:
                        goto error;
 
                down_read(&cred->request_key_auth->sem);
-               if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
+               if (test_bit(KEY_FLAG_REVOKED,
+                            &cred->request_key_auth->flags)) {
                        key_ref = ERR_PTR(-EKEYREVOKED);
                        key = NULL;
                } else {
index 293b8c4..8b8f090 100644 (file)
@@ -313,12 +313,8 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                        }
                        case AF_UNIX:
                                u = unix_sk(sk);
-                               if (u->dentry) {
-                                       struct path path = {
-                                               .dentry = u->dentry,
-                                               .mnt = u->mnt
-                                       };
-                                       audit_log_d_path(ab, " path=", &path);
+                               if (u->path.dentry) {
+                                       audit_log_d_path(ab, " path=", &u->path);
                                        break;
                                }
                                if (!u->addr)
index d754249..bf619ff 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/integrity.h>
 #include <linux/ima.h>
 #include <linux/evm.h>
+#include <linux/fsnotify.h>
+#include <net/flow.h>
 
 #define MAX_LSM_EVM_XATTR      2
 
@@ -187,25 +189,11 @@ int security_settime(const struct timespec *ts, const struct timezone *tz)
        return security_ops->settime(ts, tz);
 }
 
-int security_vm_enough_memory(long pages)
-{
-       WARN_ON(current->mm == NULL);
-       return security_ops->vm_enough_memory(current->mm, pages);
-}
-
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
 {
-       WARN_ON(mm == NULL);
        return security_ops->vm_enough_memory(mm, pages);
 }
 
-int security_vm_enough_memory_kern(long pages)
-{
-       /* If current->mm is a kernel thread then we will pass NULL,
-          for this specific case that is fine */
-       return security_ops->vm_enough_memory(current->mm, pages);
-}
-
 int security_bprm_set_creds(struct linux_binprm *bprm)
 {
        return security_ops->bprm_set_creds(bprm);
@@ -729,6 +717,11 @@ int security_task_create(unsigned long clone_flags)
        return security_ops->task_create(clone_flags);
 }
 
+void security_task_free(struct task_struct *task)
+{
+       security_ops->task_free(task);
+}
+
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
        return security_ops->cred_alloc_blank(cred, gfp);
index 6a3683e..3049299 100644 (file)
@@ -81,6 +81,8 @@
 #include <linux/syslog.h>
 #include <linux/user_namespace.h>
 #include <linux/export.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
 
 #include "avc.h"
 #include "objsec.h"
index e8af5b0..cd667b4 100644 (file)
@@ -36,6 +36,9 @@
 #include <linux/magic.h>
 #include <linux/dcache.h>
 #include <linux/personality.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/binfmts.h>
 #include "smack.h"
 
 #define task_security(task)    (task_cred_xxx((task), security))
index 5ca47ea..7ef9fa3 100644 (file)
@@ -446,11 +446,11 @@ void tomoyo_read_log(struct tomoyo_io_buffer *head)
  * tomoyo_poll_log - Wait for an audit log.
  *
  * @file: Pointer to "struct file".
- * @wait: Pointer to "poll_table".
+ * @wait: Pointer to "poll_table". Maybe NULL.
  *
  * Returns POLLIN | POLLRDNORM when ready to read an audit log.
  */
-int tomoyo_poll_log(struct file *file, poll_table *wait)
+unsigned int tomoyo_poll_log(struct file *file, poll_table *wait)
 {
        if (tomoyo_log_count)
                return POLLIN | POLLRDNORM;
index c47d3ce..8656b16 100644 (file)
@@ -1069,7 +1069,7 @@ static int tomoyo_write_task(struct tomoyo_acl_param *param)
  *
  * @domainname: The name of domain.
  *
- * Returns 0.
+ * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
@@ -1081,7 +1081,7 @@ static int tomoyo_delete_domain(char *domainname)
        name.name = domainname;
        tomoyo_fill_path_info(&name);
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               return 0;
+               return -EINTR;
        /* Is there an active domain? */
        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                /* Never delete tomoyo_kernel_domain */
@@ -1164,15 +1164,16 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
        bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
        unsigned int profile;
        if (*data == '<') {
+               int ret = 0;
                domain = NULL;
                if (is_delete)
-                       tomoyo_delete_domain(data);
+                       ret = tomoyo_delete_domain(data);
                else if (is_select)
                        domain = tomoyo_find_domain(data);
                else
                        domain = tomoyo_assign_domain(data, false);
                head->w.domain = domain;
-               return 0;
+               return ret;
        }
        if (!domain)
                return -EINVAL;
@@ -2111,7 +2112,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
        struct tomoyo_domain_info *domain = NULL;
        spin_lock(&tomoyo_query_list_lock);
        list_for_each_entry(ptr, &tomoyo_query_list, list) {
-               if (ptr->serial != serial || ptr->answer)
+               if (ptr->serial != serial)
                        continue;
                domain = ptr->domain;
                break;
@@ -2130,28 +2131,13 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
  *
  * Waits for access requests which violated policy in enforcing mode.
  */
-static int tomoyo_poll_query(struct file *file, poll_table *wait)
+static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait)
 {
-       struct list_head *tmp;
-       bool found = false;
-       u8 i;
-       for (i = 0; i < 2; i++) {
-               spin_lock(&tomoyo_query_list_lock);
-               list_for_each(tmp, &tomoyo_query_list) {
-                       struct tomoyo_query *ptr =
-                               list_entry(tmp, typeof(*ptr), list);
-                       if (ptr->answer)
-                               continue;
-                       found = true;
-                       break;
-               }
-               spin_unlock(&tomoyo_query_list_lock);
-               if (found)
-                       return POLLIN | POLLRDNORM;
-               if (i)
-                       break;
-               poll_wait(file, &tomoyo_query_wait, wait);
-       }
+       if (!list_empty(&tomoyo_query_list))
+               return POLLIN | POLLRDNORM;
+       poll_wait(file, &tomoyo_query_wait, wait);
+       if (!list_empty(&tomoyo_query_list))
+               return POLLIN | POLLRDNORM;
        return 0;
 }
 
@@ -2175,8 +2161,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
-               if (ptr->answer)
-                       continue;
                if (pos++ != head->r.query_index)
                        continue;
                len = ptr->query_len;
@@ -2194,8 +2178,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
-               if (ptr->answer)
-                       continue;
                if (pos++ != head->r.query_index)
                        continue;
                /*
@@ -2243,8 +2225,10 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
                if (ptr->serial != serial)
                        continue;
-               if (!ptr->answer)
-                       ptr->answer = answer;
+               ptr->answer = answer;
+               /* Remove from tomoyo_query_list. */
+               if (ptr->answer)
+                       list_del_init(&ptr->list);
                break;
        }
        spin_unlock(&tomoyo_query_list_lock);
@@ -2477,18 +2461,17 @@ int tomoyo_open_control(const u8 type, struct file *file)
  * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
  *
  * @file: Pointer to "struct file".
- * @wait: Pointer to "poll_table".
+ * @wait: Pointer to "poll_table". Maybe NULL.
  *
- * Waits for read readiness.
- * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and
- * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd.
+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
+ * POLLOUT | POLLWRNORM otherwise.
  */
-int tomoyo_poll_control(struct file *file, poll_table *wait)
+unsigned int tomoyo_poll_control(struct file *file, poll_table *wait)
 {
        struct tomoyo_io_buffer *head = file->private_data;
-       if (!head->poll)
-               return -ENOSYS;
-       return head->poll(file, wait);
+       if (head->poll)
+               return head->poll(file, wait) | POLLOUT | POLLWRNORM;
+       return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
 }
 
 /**
index 9512222..30fd983 100644 (file)
@@ -788,7 +788,7 @@ struct tomoyo_acl_param {
 struct tomoyo_io_buffer {
        void (*read) (struct tomoyo_io_buffer *);
        int (*write) (struct tomoyo_io_buffer *);
-       int (*poll) (struct file *file, poll_table *wait);
+       unsigned int (*poll) (struct file *file, poll_table *wait);
        /* Exclusive lock for this structure.   */
        struct mutex io_sem;
        char __user *read_user_buf;
@@ -981,8 +981,8 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path,
                            unsigned long number);
 int tomoyo_path_perm(const u8 operation, struct path *path,
                     const char *target);
-int tomoyo_poll_control(struct file *file, poll_table *wait);
-int tomoyo_poll_log(struct file *file, poll_table *wait);
+unsigned int tomoyo_poll_control(struct file *file, poll_table *wait);
+unsigned int tomoyo_poll_log(struct file *file, poll_table *wait);
 int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
                                  int addr_len);
 int tomoyo_socket_connect_permission(struct socket *sock,
index bee09d0..fe00cdf 100644 (file)
@@ -199,30 +199,32 @@ int tomoyo_mount_permission(char *dev_name, struct path *path,
        if (flags & MS_REMOUNT) {
                type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
                flags &= ~MS_REMOUNT;
-       }
-       if (flags & MS_MOVE) {
-               type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
-               flags &= ~MS_MOVE;
-       }
-       if (flags & MS_BIND) {
+       } else if (flags & MS_BIND) {
                type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
                flags &= ~MS_BIND;
-       }
-       if (flags & MS_UNBINDABLE) {
-               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
-               flags &= ~MS_UNBINDABLE;
-       }
-       if (flags & MS_PRIVATE) {
+       } else if (flags & MS_SHARED) {
+               if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+                       return -EINVAL;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
+               flags &= ~MS_SHARED;
+       } else if (flags & MS_PRIVATE) {
+               if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
+                       return -EINVAL;
                type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
                flags &= ~MS_PRIVATE;
-       }
-       if (flags & MS_SLAVE) {
+       } else if (flags & MS_SLAVE) {
+               if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
+                       return -EINVAL;
                type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
                flags &= ~MS_SLAVE;
-       }
-       if (flags & MS_SHARED) {
-               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
-               flags &= ~MS_SHARED;
+       } else if (flags & MS_UNBINDABLE) {
+               if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
+                       return -EINVAL;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
+               flags &= ~MS_UNBINDABLE;
+       } else if (flags & MS_MOVE) {
+               type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
+               flags &= ~MS_MOVE;
        }
        if (!type)
                type = "<NULL>";
index 482b2a5..8592f2f 100644 (file)
@@ -157,9 +157,10 @@ static int tomoyo_release(struct inode *inode, struct file *file)
  * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface.
  *
  * @file: Pointer to "struct file".
- * @wait: Pointer to "poll_table".
+ * @wait: Pointer to "poll_table". Maybe NULL.
  *
- * Returns 0 on success, negative value otherwise.
+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
+ * POLLOUT | POLLWRNORM otherwise.
  */
 static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
 {
diff --git a/security/yama/Kconfig b/security/yama/Kconfig
new file mode 100644 (file)
index 0000000..51d6709
--- /dev/null
@@ -0,0 +1,13 @@
+config SECURITY_YAMA
+       bool "Yama support"
+       depends on SECURITY
+       select SECURITYFS
+       select SECURITY_PATH
+       default n
+       help
+         This selects Yama, which extends DAC support with additional
+         system-wide security settings beyond regular Linux discretionary
+         access controls. Currently available is ptrace scope restriction.
+         Further information can be found in Documentation/security/Yama.txt.
+
+         If you are unsure how to answer this question, answer N.
diff --git a/security/yama/Makefile b/security/yama/Makefile
new file mode 100644 (file)
index 0000000..8b5e065
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_YAMA) := yama.o
+
+yama-y := yama_lsm.o
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
new file mode 100644 (file)
index 0000000..5737238
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Yama Linux Security Module
+ *
+ * Author: Kees Cook <keescook@chromium.org>
+ *
+ * Copyright (C) 2010 Canonical, Ltd.
+ * Copyright (C) 2011 The Chromium OS Authors.
+ *
+ * This program is free software; you can 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/security.h>
+#include <linux/sysctl.h>
+#include <linux/ptrace.h>
+#include <linux/prctl.h>
+#include <linux/ratelimit.h>
+
+static int ptrace_scope = 1;
+
+/* describe a ptrace relationship for potential exception */
+struct ptrace_relation {
+       struct task_struct *tracer;
+       struct task_struct *tracee;
+       struct list_head node;
+};
+
+static LIST_HEAD(ptracer_relations);
+static DEFINE_SPINLOCK(ptracer_relations_lock);
+
+/**
+ * yama_ptracer_add - add/replace an exception for this tracer/tracee pair
+ * @tracer: the task_struct of the process doing the ptrace
+ * @tracee: the task_struct of the process to be ptraced
+ *
+ * Each tracee can have, at most, one tracer registered. Each time this
+ * is called, the prior registered tracer will be replaced for the tracee.
+ *
+ * Returns 0 if relationship was added, -ve on error.
+ */
+static int yama_ptracer_add(struct task_struct *tracer,
+                           struct task_struct *tracee)
+{
+       int rc = 0;
+       struct ptrace_relation *added;
+       struct ptrace_relation *entry, *relation = NULL;
+
+       added = kmalloc(sizeof(*added), GFP_KERNEL);
+       if (!added)
+               return -ENOMEM;
+
+       spin_lock_bh(&ptracer_relations_lock);
+       list_for_each_entry(entry, &ptracer_relations, node)
+               if (entry->tracee == tracee) {
+                       relation = entry;
+                       break;
+               }
+       if (!relation) {
+               relation = added;
+               relation->tracee = tracee;
+               list_add(&relation->node, &ptracer_relations);
+       }
+       relation->tracer = tracer;
+
+       spin_unlock_bh(&ptracer_relations_lock);
+       if (added != relation)
+               kfree(added);
+
+       return rc;
+}
+
+/**
+ * yama_ptracer_del - remove exceptions related to the given tasks
+ * @tracer: remove any relation where tracer task matches
+ * @tracee: remove any relation where tracee task matches
+ */
+static void yama_ptracer_del(struct task_struct *tracer,
+                            struct task_struct *tracee)
+{
+       struct ptrace_relation *relation, *safe;
+
+       spin_lock_bh(&ptracer_relations_lock);
+       list_for_each_entry_safe(relation, safe, &ptracer_relations, node)
+               if (relation->tracee == tracee ||
+                   (tracer && relation->tracer == tracer)) {
+                       list_del(&relation->node);
+                       kfree(relation);
+               }
+       spin_unlock_bh(&ptracer_relations_lock);
+}
+
+/**
+ * yama_task_free - check for task_pid to remove from exception list
+ * @task: task being removed
+ */
+static void yama_task_free(struct task_struct *task)
+{
+       yama_ptracer_del(task, task);
+}
+
+/**
+ * yama_task_prctl - check for Yama-specific prctl operations
+ * @option: operation
+ * @arg2: argument
+ * @arg3: argument
+ * @arg4: argument
+ * @arg5: argument
+ *
+ * Return 0 on success, -ve on error.  -ENOSYS is returned when Yama
+ * does not handle the given option.
+ */
+static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+                          unsigned long arg4, unsigned long arg5)
+{
+       int rc;
+       struct task_struct *myself = current;
+
+       rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
+       if (rc != -ENOSYS)
+               return rc;
+
+       switch (option) {
+       case PR_SET_PTRACER:
+               /* Since a thread can call prctl(), find the group leader
+                * before calling _add() or _del() on it, since we want
+                * process-level granularity of control. The tracer group
+                * leader checking is handled later when walking the ancestry
+                * at the time of PTRACE_ATTACH check.
+                */
+               rcu_read_lock();
+               if (!thread_group_leader(myself))
+                       myself = rcu_dereference(myself->group_leader);
+               get_task_struct(myself);
+               rcu_read_unlock();
+
+               if (arg2 == 0) {
+                       yama_ptracer_del(NULL, myself);
+                       rc = 0;
+               } else if (arg2 == PR_SET_PTRACER_ANY) {
+                       rc = yama_ptracer_add(NULL, myself);
+               } else {
+                       struct task_struct *tracer;
+
+                       rcu_read_lock();
+                       tracer = find_task_by_vpid(arg2);
+                       if (tracer)
+                               get_task_struct(tracer);
+                       else
+                               rc = -EINVAL;
+                       rcu_read_unlock();
+
+                       if (tracer) {
+                               rc = yama_ptracer_add(tracer, myself);
+                               put_task_struct(tracer);
+                       }
+               }
+
+               put_task_struct(myself);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * task_is_descendant - walk up a process family tree looking for a match
+ * @parent: the process to compare against while walking up from child
+ * @child: the process to start from while looking upwards for parent
+ *
+ * Returns 1 if child is a descendant of parent, 0 if not.
+ */
+static int task_is_descendant(struct task_struct *parent,
+                             struct task_struct *child)
+{
+       int rc = 0;
+       struct task_struct *walker = child;
+
+       if (!parent || !child)
+               return 0;
+
+       rcu_read_lock();
+       if (!thread_group_leader(parent))
+               parent = rcu_dereference(parent->group_leader);
+       while (walker->pid > 0) {
+               if (!thread_group_leader(walker))
+                       walker = rcu_dereference(walker->group_leader);
+               if (walker == parent) {
+                       rc = 1;
+                       break;
+               }
+               walker = rcu_dereference(walker->real_parent);
+       }
+       rcu_read_unlock();
+
+       return rc;
+}
+
+/**
+ * ptracer_exception_found - tracer registered as exception for this tracee
+ * @tracer: the task_struct of the process attempting ptrace
+ * @tracee: the task_struct of the process to be ptraced
+ *
+ * Returns 1 if tracer has is ptracer exception ancestor for tracee.
+ */
+static int ptracer_exception_found(struct task_struct *tracer,
+                                  struct task_struct *tracee)
+{
+       int rc = 0;
+       struct ptrace_relation *relation;
+       struct task_struct *parent = NULL;
+       bool found = false;
+
+       spin_lock_bh(&ptracer_relations_lock);
+       rcu_read_lock();
+       if (!thread_group_leader(tracee))
+               tracee = rcu_dereference(tracee->group_leader);
+       list_for_each_entry(relation, &ptracer_relations, node)
+               if (relation->tracee == tracee) {
+                       parent = relation->tracer;
+                       found = true;
+                       break;
+               }
+
+       if (found && (parent == NULL || task_is_descendant(parent, tracer)))
+               rc = 1;
+       rcu_read_unlock();
+       spin_unlock_bh(&ptracer_relations_lock);
+
+       return rc;
+}
+
+/**
+ * yama_ptrace_access_check - validate PTRACE_ATTACH calls
+ * @child: task that current task is attempting to ptrace
+ * @mode: ptrace attach mode
+ *
+ * Returns 0 if following the ptrace is allowed, -ve on error.
+ */
+static int yama_ptrace_access_check(struct task_struct *child,
+                                   unsigned int mode)
+{
+       int rc;
+
+       /* If standard caps disallows it, so does Yama.  We should
+        * only tighten restrictions further.
+        */
+       rc = cap_ptrace_access_check(child, mode);
+       if (rc)
+               return rc;
+
+       /* require ptrace target be a child of ptracer on attach */
+       if (mode == PTRACE_MODE_ATTACH &&
+           ptrace_scope &&
+           !task_is_descendant(current, child) &&
+           !ptracer_exception_found(current, child) &&
+           !capable(CAP_SYS_PTRACE))
+               rc = -EPERM;
+
+       if (rc) {
+               char name[sizeof(current->comm)];
+               printk_ratelimited(KERN_NOTICE "ptrace of non-child"
+                       " pid %d was attempted by: %s (pid %d)\n",
+                       child->pid,
+                       get_task_comm(name, current),
+                       current->pid);
+       }
+
+       return rc;
+}
+
+static struct security_operations yama_ops = {
+       .name =                 "yama",
+
+       .ptrace_access_check =  yama_ptrace_access_check,
+       .task_prctl =           yama_task_prctl,
+       .task_free =            yama_task_free,
+};
+
+#ifdef CONFIG_SYSCTL
+static int zero;
+static int one = 1;
+
+struct ctl_path yama_sysctl_path[] = {
+       { .procname = "kernel", },
+       { .procname = "yama", },
+       { }
+};
+
+static struct ctl_table yama_sysctl_table[] = {
+       {
+               .procname       = "ptrace_scope",
+               .data           = &ptrace_scope,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+       { }
+};
+#endif /* CONFIG_SYSCTL */
+
+static __init int yama_init(void)
+{
+       if (!security_module_enable(&yama_ops))
+               return 0;
+
+       printk(KERN_INFO "Yama: becoming mindful.\n");
+
+       if (register_security(&yama_ops))
+               panic("Yama: kernel registration failed.\n");
+
+#ifdef CONFIG_SYSCTL
+       if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
+               panic("Yama: sysctl registration failed.\n");
+#endif
+
+       return 0;
+}
+
+security_initcall(yama_init);