Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Mar 2012 01:55:10 +0000 (18:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Mar 2012 01:55:10 +0000 (18:55 -0700)
Pull powerpc merge from Benjamin Herrenschmidt:
 "Here's the powerpc batch for this merge window.  It is going to be a
  bit more nasty than usual as in touching things outside of
  arch/powerpc mostly due to the big iSeriesectomy :-) We finally got
  rid of the bugger (legacy iSeries support) which was a PITA to
  maintain and that nobody really used anymore.

  Here are some of the highlights:

   - Legacy iSeries is gone.  Thanks Stephen ! There's still some bits
     and pieces remaining if you do a grep -ir series arch/powerpc but
     they are harmless and will be removed in the next few weeks
     hopefully.

   - The 'fadump' functionality (Firmware Assisted Dump) replaces the
     previous (equivalent) "pHyp assisted dump"...  it's a rewrite of a
     mechanism to get the hypervisor to do crash dumps on pSeries, the
     new implementation hopefully being much more reliable.  Thanks
     Mahesh Salgaonkar.

   - The "EEH" code (pSeries PCI error handling & recovery) got a big
     spring cleaning, motivated by the need to be able to implement a
     new backend for it on top of some new different type of firwmare.

     The work isn't complete yet, but a good chunk of the cleanups is
     there.  Note that this adds a field to struct device_node which is
     not very nice and which Grant objects to.  I will have a patch soon
     that moves that to a powerpc private data structure (hopefully
     before rc1) and we'll improve things further later on (hopefully
     getting rid of the need for that pointer completely).  Thanks Gavin
     Shan.

   - I dug into our exception & interrupt handling code to improve the
     way we do lazy interrupt handling (and make it work properly with
     "edge" triggered interrupt sources), and while at it found & fixed
     a wagon of issues in those areas, including adding support for page
     fault retry & fatal signals on page faults.

   - Your usual random batch of small fixes & updates, including a bunch
     of new embedded boards, both Freescale and APM based ones, etc..."

I fixed up some conflicts with the generalized irq-domain changes from
Grant Likely, hopefully correctly.

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (141 commits)
  powerpc/ps3: Do not adjust the wrapper load address
  powerpc: Remove the rest of the legacy iSeries include files
  powerpc: Remove the remaining CONFIG_PPC_ISERIES pieces
  init: Remove CONFIG_PPC_ISERIES
  powerpc: Remove FW_FEATURE ISERIES from arch code
  tty/hvc_vio: FW_FEATURE_ISERIES is no longer selectable
  powerpc/spufs: Fix double unlocks
  powerpc/5200: convert mpc5200 to use of_platform_populate()
  powerpc/mpc5200: add options to mpc5200_defconfig
  powerpc/mpc52xx: add a4m072 board support
  powerpc/mpc5200: update mpc5200_defconfig to fit for charon board
  Documentation/powerpc/mpc52xx.txt: Checkpatch cleanup
  powerpc/44x: Add additional device support for APM821xx SoC and Bluestone board
  powerpc/44x: Add support PCI-E for APM821xx SoC and Bluestone board
  MAINTAINERS: Update PowerPC 4xx tree
  powerpc/44x: The bug fixed support for APM821xx SoC and Bluestone board
  powerpc: document the FSL MPIC message register binding
  powerpc: add support for MPIC message register API
  powerpc/fsl: Added aliased MSIIR register address to MSI node in dts
  powerpc/85xx: mpc8548cds - add 36-bit dts
  ...

331 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/powerpc/firmware-assisted-dump.txt [new file with mode: 0644]
Documentation/powerpc/mpc52xx.txt
Documentation/powerpc/phyp-assisted-dump.txt [deleted file]
MAINTAINERS
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
drivers/base/driver.c
drivers/block/viodasd.c [deleted file]
drivers/cdrom/viocd.c [deleted file]
drivers/char/viotape.c [deleted file]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-ge.c [new file with mode: 0644]
drivers/misc/carma/carma-fpga.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/fsl_ifc_nand.c [new file with mode: 0644]
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/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/watchdog/Kconfig
fs/proc/vmcore.c
include/linux/atomic.h
include/linux/device.h
include/linux/of.h
include/linux/pci.h
init/do_mounts_rd.c

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 2cf38bd841fd5776028803a11882036dccb3e38c..dc5744636a5792610f48e34812569acd25b3eda9 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 5d586e1ccaf504d6a6834b38605f864fd168eb23..5693877ab377d6007cdb9e7f4ae7705faec581d7 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
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 10dd4ab93b85ee1ce6e74a0dd88f32465bde48bc..0d540a31ea1ab32637e103b251860d0485e34a54 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 92f9924c4335dd9e758851e3a995062ac78e7861..58f60356f0714daf4efc0751f4068d47b1db3110 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 303703d716feaf21308b53e5eb016ddd6ee74ecf..d219ebecabf0b5139242f1b6fc870216ee4625d9 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 4ccb2a009f745f3477502964be609eeb14147cfa..72d55dbc6119d6b4370d6b79df8b223799934b70 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 b8b105c01c64662e8a2f839a9c199dcbe0901126..6524c6e2189651cb0c7b21f0b18076d1a5f07593 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 8844a17ce8ede20213d2c64d25d0d764587e834e..e8461cb18d0435e5716ae0ef098116d82ecb242f 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 74876f73740711e39a62b5f41cb4108a68834cb8..7bda373f10ef230a61744f029aad29af73f097a7 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 b37da56018b6340a6d514a85644d5131960de9ff..c8b2daa40ac876536ce67c9fe052898ffebd189b 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 9d8023a69d7d838340f490fe7934f3448799d82c..579d76cb8e329de15bf3c5efeb214dc4dc09f57b 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 289f1218d755ca56610fe1edecd049d5da9f0731..720422d83529092fd9237e8b4b1992522e9d6faa 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 a97d1263372ccbf9350f5db9ee29b9483886642a..0bde9ee8afafc5d2137ddc571e8bc1c9de9ea206 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 5de5fc351314a627605c0bd0389f05ae452e1714..68cc5e7f64777c6a1021494dc5826df4a658c83b 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 38ba54d1e32e1c426be065a5f3a648510dd28ca5..4252ef85fb7a9689902e03865e8cd17e0225a01b 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 ff9ed1d879297bfe0975cd7261abdc9eaab7a57f..06216b8c0af527ae15b6ea87ef40e748196b41e5 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 b06bb4cc1fe819254bbd7a23724871f8afa4e80b..941fa159cefba2d2229ebcb2ccdbaa62467452ec 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 332e9e75e6c2f706b370d9f7524594df25c5c387..884e01bcb2432e4af7f0ad57f80d182d505a76b0 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 234a399ddeb2cbb6e32c7395ecf340925d072f29..531eab82c6c93f78cacd23da466484613cde5e58 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 d41d08de7f7e3e1356d326731b4b3c15f47de673..af4ebc8009e3ed410caae2448c89b59558646b21 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 a63edd195ae5113e180f50961469f5369b16ef47..b3e56929eee289b195316e17707761314a10933e 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 914074b91a8561ecf89fce5fa3316d17c0f9cf47..64b6abea846453ed79f727df4bfca689670d87b9 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 a1979ae334a751d1b47e5d9c6478c835ad9b837a..3b0650a98478f6c8a830551a4bc5a19528d87fe5 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 4c4fdde1ec2a733a4a4bfe01d9afe63a6402c37e..96693b41f0f176591097d16436887d0779594faa 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 4b8ab438668aff9873df2570c7e7ceca55809fe4..6b3fab19da1ffd1e76263641cbc13d02d55c1a58 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 40c9137729aeae8f093c97dd46d2e9e5d92f565a..0da592d93ddd04efb3842674edce882bfaa0fcb2 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 5c8046065844419f17b067b42007ee6c63c6d161..fdedf7b1fe0f2e25d47729470e1665be9615a3d8 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 bf957a7fca2aed38932390a57466bd11a6233a7d..d4c9d5daab21fa8d30c05bd0c15a56bdf46a5813 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 b9bada6a87dc60a423e92f321e61f6f3e1d02227..08f42271f86a5aa92404b82cc77f4eb13fabc119 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 c0e450a551bf320fedf93fcde0ebdb40ba1ac9a0..81dd513d6308554fea3f891dcc129a70525bce69 100644 (file)
                                reg = <0x1>;
                                device_type = "ethernet-phy";
                        };
+                       tbi-phy@2 {
+                               device_type = "tbi-phy";
+                               reg = <0x2>;
+                       };
                };
 
                qeic: interrupt-controller@80 {
index c15881574fdc1909532063569c851f17215dcc64..19736222a0b92cccdb0a9d2277bad731a8f5a9f5 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 1462e4cf49d71a215e38b974d4e0e1907ded3b97..cc46dbd9746d7a1bac21ce42e80e1b3157a51081 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 8f4b929b1d1d8cdc24dc6aacca3e2b903280759e..f8a3b3413176260353619941e87cd8fe66be43b4 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 c3d4fac0532aea331aa701710f80818dec5acd45..14178944e2209ef5308791608fac988d977ea547 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 d4c4a7730285501317523ab39054825ff3d2df7a..49776143a1b84874b515ecd164a384aface0f122 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 eb8a6aa2bda5f019ae06311a9e753f12cf2891b0..153bc76bb48ea75cc93ca9d93d41207fe420a147 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 f090e6d2907eb13d71fd3d6a4c8742211a1b008d..6761c746048df389812888b8430aca4f442e191c 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 d41857a5152d978827766916066edf224078f024..da731c2fe984ae67b66e30bf3b7b81eb8f42391b 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 38303ec11bcd99e770dcddb119393920e7ecef6d..2149360a1e62382385c886500719b58dd4e6c0ac 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 98533973d20f527234ea8967333fb04b8204814d..af2e8e1edba61e70af84fa3d7271b776e7685ba8 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 2a1320fb27232457bf8afe7ccede0186774575bf..6640a35bebb7ac74d88d63f5c4420510088e088a 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 f37a2ab48881738fa7e6c9e4c92f1d5f3dd00e82..5fb0c8a948112478ed410271a626ca3c80de2388 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 abdcd317cda733c07d2485c9375ebba9cb993610..fb51bc90edd267bcd2270d347f6774b12d548716 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 5ab0b71531be8f0701dc5a17fe4f1a54b3a6d22f..9d92ba04b033891544f154e26e28f853ec42d64e 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 02e41b53488d8d8574f42c6a4e0ce1f99df9aaa8..14174e838ad9c443c5b68e71ebb1195a701d9c7b 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 ad55a1ccb9fb76fbe98c53005239df303efa5dc1..b9219e99bd2ae6cbc4c5882dff3dfd62759cbfe2 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 d57c08acedfc2e5f1167a1f3a861094662c486fb..63d5ca49cece245e79f83f3c08b150de18d508a3 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 a7e06e25c7083b6648109f66a4e04f551672cf86..adadb994361053ba22389e4c73aa64e42bc0f285 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 66ea9b8b95c58f44c2ca464758d754f5378ac2ca..d60f99814ffb70ea92c9151211004f4b2cec7802 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 cc3cb04539ac4972874000b01e95cd6f8e98ae6c..c68b012b7797b0144956c951cd90b9cab92713ab 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 8057f4f6980ffc55abfa0a20d366cf8e10a65b4b..548da3aa0a303a3f2065127d079b280c6264d14f 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 14db29b18d0ed9664629550c48cc76106b35fcc6..ad0b751b0d78e418e799b7cb959091d4a6f35df7 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 bebd12463ec9e1375548aca2fd96e01eb7fc3334..ce04530d20003a42e045a634790691c99d715d53 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 bb712c9488b3c74bcfb6f36c47322044e9c0992d..51010bfc792e9ea365f6d4f3b4fa34f089dd2e28 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 b0b06d85788db98d474320736cf2df638f7fa9c5..6f9b6e23dc5af74c8ee1423b052d2ada384c3d36 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 e0298d26ce5d9fba9ca7b772fcec6bf9fbbd671e..a76254af0aaa94024fcb999a923b04140ddd20d4 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 a5b7c56237f9fe298f0f22b36e84949b4b1a48e4..c65b9294376ee8e2e1745cf73b014dc1f49d372e 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 269c05a36d917529bc340f61cb0824e1276cd19b..daf813fea91fa6998322ff4d0fba63b2398f52e0 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 6d422979ebafde984906f20add7886fd9e1464ec..e660b37aa7d064d77c959c4ce4dd1a36a9316ab1 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 368f72f798087b331b31300c9c9f2aa5dec50588..50f73aa2ba219acbb132795af18cc7f447e019ff 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 7fdc2c0b7fa057bd1f9391e93d0332b9f8ccebb8..b1a215eabef6abc872ae94107a1be3af3c2bdad6 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 500fe1dc43e6de21023672b68ac477450a610663..8a97aa7289d36b155a1e01df4211a261a7a110e8 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 f9611bd69ed2a102b38e67da0451be7694c70a5b..7124fc06ad47d304303b93e725f0c4a1f822d0eb 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 c377457d1b898a13ce2ba24b6e0aab108069f91f..a02883d5af435f798bc0b174a6432134c084060c 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 964714940961a729c9b8d7404abb133dedb94c28..4a741c7efd02743a33d53bd6c56b24c8e4075596 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 7eb10fb96cd0e4be4d19b37aa5e7725e7cd331cf..2136f58a54e80a32fd014dd66b84196b9f0bc1df 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 ee728e433aa26fc245e25177561c56089453d766..f5808a35688ca4602a61978619d06c9d8a8d1d16 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 04caee7d9bc185a223841b4827da5576359f5be1..cc492e48ddfac1bf1db71b16b739799a7f929111 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 81db9e2a8a203e50b204bfec76cb2adef5f538f1..138ae183c44005bad8e2694aa7b21c85208e2284 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 2cc451aaaca757fa3d851c0e8b5edf8610a281d0..5b25c8060fd67a8ff1ec2ff290af5ec740b6376f 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 866462cbe2d832341d2cbf5b89d32be7986ec815..f8a7a1a1a9f4480ac1881f907da771a474606998 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 429983c06f9126e6991497a543d9c7c21912ff2e..7215cc2495df1d95a91af88471af120e98ae2656 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 15c5a4f6de0105b410de25643b22a7b9409bba22..2d0868a4e2f0d3d4b346721c1a25fad8ef717316 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 0654dba2c1f18a3582c7dc82854765d776c7dcf0..dc0488b6f6e15f57a4e06997c41e2fd985c1e929 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 872a6af83bad56c95cde844fc2044817e8fc8275..4989661b710b4a0643d39ab9b2c238c6cf01d786 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 06c7251c1bf7df7a617627e45f285ee9562a8f47..58bddee8e1e8eea9a5cd5b8da113e9b7c0117dd6 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 b68cb173ba2c6a500c37f369b9daadcf8c519d0c..b2a5860accfb9c3fa607e2cf4210802e574d6fd2 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 fc921bf62e159189eba0b2a5314a75022be9dd46..0e4175388f478af5456d7095a860a2d621e3ad3c 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 d5d78c4ceef6d4200e2d345c8d16fe25a96f6b7c..28e62598d0e81c10d18940b8461a969dd97ebde5 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 c97fc60c790cbcaf57c66dd550006b5b22658541..e8e821146f3813292390e803ca07fba062e2a1cb 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 16c002d6bdf11483a0de5ddd4132d96f24e1f3b0..ff007b59448db24523fc1590caa83057a6446dce 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 ba3195478600998a72bbdbabeaf7761963a435ed..2c71b0fc9f9101361475e8baaea3136a84753c45 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 fcdff198da4ba9f43fe0f58a84d2bd632136ff24..0cdc9a3928391264e66f7f772b7a276c3e25c69c 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 0cfcf98aafca25e3e9cb1c210ad4f149601a9bd9..359f078571c7e5c9da9a6b90e5a53e0feec78b06 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 bdfb3eee3e6f6d58daee601eaa6e3aca3851957c..a3d128e94cff4b9753810ebd6e09d9410cd9760a 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 479752901ec6764df5f57bca5ee3136244d600bb..d45ec58703cec58553d02de52baab00152fcad72 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 578f35f187236ced4b8e783cce9b897603725095..ac12bd80ad951e1be909e7c2dc92ac146bdb362b 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 b69463ec2010c7ca180918fd49d0f106b60eab87..ba16874fe294c003b6d28a65f25da53f8d23097a 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 e1612dfb4a930eca385a841bbbc967cb90c15b11..2049f2d00ffef60f0e7b1f9cfa5fc9cbd25a1758 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 41456ff55e14f6b1fb6868621e77650989f32d7b..0bb1f98613bab5041dcad6073eae70395db5970c 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 cce98d76e905ad2188ce0d27e985308abaa2a433..d0373bcb7c9dcebd42e0b8baddf48c881b375018 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 d817ab018486d71b8c06bb9b6275bd0f533d8c89..e40707032ac36cd1c71b7796558a9716bbfe6bc8 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 abe405dab34d88db0734db2f4cbab727ade30e1d..89e850af3dd6c0277c550afbe57cbf69e11a92d9 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 eca626ea3f2393dcaf0cd6bfb61f6262a4443e7e..e2d599048142e2d4d7084f803b2b5abd5fa70f43 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 6cd8f0196b6d4401af0f91e368f67caa53cad133..517bd86bc3f020537617710daeb0e9e34a07da5b 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 77bb77da05c1d5ad35ef17788f26cbe2878135a4..b0ebdeab9494386368fd4ce8b0f7ed39e9814977 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 ac6e437b10214d47b6d6525cc9d23b8b3e37dabe..7006b7f4267a7b7c3fa9337319c16f1556ceaac8 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 836a5a19eb2c3a3e45d5cab542fdb7138a8142bd..e061ef5dd4490dc0dfb20da69ab1551b69767e48 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 883e74c0d1b3b53b8a5cd1a003bc4ae30d0659f1..0c683d376b1cddddf6a9da9a07644f18d7acbb92 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 567dd7c3ac2ad9b2b5c9236804daf83064e967f0..2c42cd72d0f5b1a33eb501da54a8e5edbb08e63e 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 c091527efd89fa5a38688c055ba5ddcfee99e193..a750409ccc4e25b2743456bc3b492166b9f8c1c7 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 8b086299ba25cc1f1ff42f9e90464b212919f318..bca3fc427b45fffae821440d8021ac9beb4de7bd 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 710a54005dfb556521f387d2964cafeadfd968c0..65d1c08cf09ecdc72dd6d24affaab9130a28f3b2 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 336983da9e726c1e144b9a29be03934308800958..a7267167a55040c1e7b9acbdeb4d6fcc2764dfad 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 a6ebba56fdd4005a92e261a9d171423bb4325413..bb7cfecf2788ffcdd37542ec9333d69e08cbf427 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 2f0d1b032a892d82228b51c7d64c7df04fb7867d..19f2f9498b27f9ebc8f746c8e7d7fce42ddab728 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 66a6fd38e9cdb9df35d8dbb6206c581b7f5b550e..07ba45b0f07c8ed311313c14fdf4422613639e0e 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 2d282186cb45b43f55044819bba1b4a5279844b6..3e8c37a4e395cc730418eafc12bdd81cb5f0caad 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 5d9a59eaad931612e3f678cfdbd916626b4efb5d..8cdbd8634a58d4fa63df9623c2ec547927ffe404 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 42176bd0884ccdb66b43c2c8c6900ce257ff5dde..6dedc08e62c874f26d5e57917b79d9bc5f507dae 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 51f87956f8f87ebbc463085c2b44c55f048a166e..0907f92ce309258beb1cd964018b94a9146e2cec 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 e22276cb67a40a4c9290784cf2bf358b88e0646e..a538c80db2df068da5dac56aa5076f484db434d8 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 ef653dc95b6594a2f4883ab46fc4a0f07f4c4e3b..b9ee79ce2200998012e18cf95f462aebbb85e748 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 41e31642a86ad900853ed03dfdf3dc556db71a22..9106ebb118f52e516e1053b2d0b9fe88367a442c 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 d65e68f3cb25c16762347c7e24303caaa2647533..6f01624f317f6381f4431a2f4ef81d8c81d0e22c 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 fcf6bf2ceee9b1660c8e999de05bc6b8debc06f8..2e4e64abfab4ed751adb06dd2ffff0b476de35c9 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 3f6229b5dee027df0e8b33e7f42827f3dd77918a..583e67fee37ee1fd4daddc84ea3064fc4178ed6c 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 5b8cdbb82f80f486733149ddaca8d03012c28d06..a28a8629727eed875133f168a7951b9337e58802 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 8d2202763415b509cb6184463828de959919ac11..3ffb915446e39bdf74f716395a6a05f8e559c632 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 846b789fb1953000d15f90f1da723f0b0d81ff43..c0aa04068d6936bc195bfe271acf21758f494e0b 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 369fd5457a3f2edc13dba2072be8e8384f3e6489..d7e94f49532a156f78f3fc2da2d98b73e60c0554 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 d7946be298b6fc1f842eaff3e14b4ae502924f3c..f000d81c4e31214f5cf7dd3176419f847fdb0128 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 9cb2d4320dccb34ff4113c33986383786a2c65cf..2125d4ca068a983b0bd30b92e9daabb72b04ab82 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 07e3e6c47371f0759f2cb6dd4d640c262ac31155..df69e99e511c2d04232850900116a2be84503755 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 20f75d7819c6776b390a90d0d0689d3f8d9bd201..60120e55da41190d9a1d5a776a7d14e09019229e 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 cf266826682e72ea7ce9dd0c3e8bf5bdf8128f67..f58872688d8f99a01d59094eeec93d66501b8d1a 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 3bebb5173bfcb87f98022d675a911d7c33110975..d19f675cb369f886978e0763ff891aa7f1474f9d 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 40f03da616a9e8c38884f359f12a58c390f115ae..ab5f0bf19454ca04526517443615b2476812e38f 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 eefbb91e1d61cdb5883b5af8c3a5968c93d57de5..6e23e3e34bd94bf4bc501c6d6ec0ec2a142c3dd2 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 1d15a0cd2c82dd2110f27e835ede3cefd30f2bbb..f33662b46b8d31052028c4ff779b5a4d8fc064d1 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 ccf520e890bee2f209182cf6df3f0b240d0864f9..db214cd4c8220ebad46e845f47de857fc7088d47 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 538bc3f57e9d9cc3b5119d0c8a12fafe68763bb7..d8bd6563d9cac92a01d9bc7edc2236242a617787 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 b0984ada3f83c41db76a56f3adbbd7779af6d7c1..0fe88e39945ecd5e4b13dee9ec03e362e0ebdfe8 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 d951e7027bb65ef65e4b374ccc05a72866f75522..6b07398e4369f9ce7f1c690d3bdbc0168bfb350c 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 184a50784617fdf1b869138edb6cc72c745a407f..1677b8a22677ffe8e1d50a9497520c7babfb8823 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 940752e93051718b789772450949d0c25c67a80e..3c3bbcc275669b45a79c4d85cd4928a9b88b7285 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 18f635906b2762f8e0a9af23247bdf4c848458f9..b719192177560da2fcc5fb6f8cafebb0ae283729 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 e9e5234b4e76992ddca5121bf418583f406e5f35..27ca3a7b04abb1fafa8d3346bb0d0b3378b3e2c1 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 bf7c89fb75bbf92ebd4eb9efcd707f7fe5c315a1..d7504cefe016f57912d19244f883bdf426a3b11b 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 3a69f8b77de6f549729832fb6ed3703aa9cfc477..503c21596c6328035f3799f75adc7dcd8df434f1 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 8d6599d54ea6caadf8476cc42ba56734b1edfbcc..7a6279e38213e9c2444c4cb4ed67a118720390de 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 4b0d7b1aa0056bd45d5f80dfd95a150a4844f3d4..ede815d6489dbc8fbce9bea2b08fe05549737db7 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 60ce07e39100173ef750fe81a403bf7f0bb32c78..ed58b6cfd60cba66ab306876d350097dc5559c78 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 3ecee25bf3edcd760f03f9139ca10962533649cd..710db69bd52314ed8f7f2d9bea5ac01c3beb87a7 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 5090d608d9ee1cc47b556462550398f576fcbc19..4a13d2f4ac20181a021d4794ce5fb8f554fbcdc0 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 52bbfa031531583da870458a2c41207459cd36a1..22cc3571ae192ea714bdc719fc4e04641ef8d595 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 0cfb46d54b8c922db3b4136b1f7eb021213c48e7..a35ca44ade66a455c0cf5b13d0f1ccd204a3b671 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 2635a22bade22b0d3211c529623860992f5b2c76..879b4a448498807e08745b731b55ebbe1ab89e8b 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 62002a7edfedd8bdf77bb82060e96c943b17321e..fa3e294fd34305c17fb9932a45d5439c1e006042 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 4a3d90e0d426b96cd28359f63031dd407f40c2eb..1d75c92ea8fbf94c7773817de7d511e8d240069c 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;
 }
 
index 8591bb62d7fca91580ee30896ba22bd66d8a436d..5665dcc382c7350208e5c2b084a0e94761ce5051 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 f1f17bb2c33cf355b7eed3f6a35d497f99bc7731..c665d7de6c9985f5dcb7fe5ae83728369652bc8e 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 9cfcf20c05608009176ac419a614050cd5145198..ab51b21b4bd75bd4aea1ebef19f452cb8ab50a56 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 bcfad92c9cecbd43f0385303a593ff89fa563df4..455e7c08742290a6bfb175dc3f3d730829c5545b 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 f3350d786f5b7177120189bf75a58b28e6ede5b1..74ccce36baedc8039570c6153b3b73c5a607780a 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 afa6388349653ccf85eebbb6a4b391efc5d067a4..e0ed3c71d69b8d5896fcdef23d5bc84e6fb753d0 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 0bcbfe7b2c55ac53a9c638f1aab86757f4e85081..3b7545a51aa9af5fd4d5d450c5e2e694f8395e3e 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 98b7a7c1317600f33c75ed5969f5113b77231966..e777ad471a48797f2cabd24969afaaee09e1c1f5 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 54d227127c9f10839d79f639e6e8f98c7257fbdc..da18b26dcc6fdafb3136a8d8df030eff1c92f89b 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 92afc382a49e5dbcecbd3f1055715ce9542be906..66ad93de1d5571f80b5431dd72b69b88b304f6fc 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 f92b9ef7340e85129f4ec801128e307c627273b3..214478d781ae72a25fb83fb02eb5750a93f42eb2 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 467bd4ac682441b808c3123ada08ffbe2a4f91a9..db1ad1c8f68fd1ed18a91fbc542a55c9e31d60b1 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 f2556257bbdca1c983391902670c2355ca1b8744..aadbe4f6d5373d03bef6fd8de146a02c43a04ceb 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 236db46b407803786b0633e9fd589569ec7c8f6f..c222189f5bb230e1467103681ba0cb3923ebf275 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 c0b40af4ce4f130edbd094d48467f747a10d78cc..8011088392d3421cf560ae4a173fde92eb54f1b1 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 fc5ae767989e4b86cc44e2b2ad0088c70ce269fd..e5ae1c687c669e27e1f03c6007295e53e750eff6 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 1b6cb10589e01cd8ad44d91edb39e82794a84e11..baf92cd9dfab624c1fa37af234eb9da6f45bacf5 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 d2383cfb6dfd34f86b6f8e3d79437f06506c7273..4a475256585606889b791ce25a4f6683b21a315c 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 eb744ee234daebae5fe2a2d54fcf7fbacd41e4a4..243b3510d70f7ae2e9e3a801eefd2440dd9366db 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 7bc73af6c7b9e875f489563192866a2a8abbfea3..5f3ef876ded20e0f71da39c963bba0dd19ddb95d 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 38d24e7e7bb19830e6f9d3cc7b199c51a10cafe0..109fdb75578d780a6a1edf162e556be58570f085 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 55d4ec1bd1ac6234531127c867749aa5bba3ca68..fbb21fc3080b4e130142b03ff2519d79e7a5f545 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 085fd3f45ad2fd3e6beba86099d3d36cc2c88feb..a12e95af69331cfa7e54147405699cfb3adca738 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 f79f1278dfca84ad03ac28d1c23fe542da34d2a4..8f137af616afcbbe3f223d471f87c71c17ef3fae 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 7b4df37ac381edab99725c0ad9a4037d229d369f..a84fecf63c4d0841120b1d12c523e5567e5848da 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 5e37b4717864400fe6b9b650f1a49e6ec889f80b..1bd7ecb246207e8235d6d71dcb4cce3d2d418259 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 116415899176aa4d83fbcd4ca56a4ac5728f7719..37a69097e02251e9b8158ff7b9f3e2f7bb952adc 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 5f88797dce73cecc191312a81b27b7f97b67043e..cedabd0f4bfe81e362b8bd0bbc7d5238545dc3d7 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 0c01debe963b95ca1120839b91d8aedd61d53b2f..6e097de00e093741890b12c45cb13b16d99d1d20 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 a4c4f4a932d855e8cd00c46ee1c579b229b867c1..5b6f556094dd088271b569cd6c79f8c85fe2bf0d 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 15485789e9dbb0bb4d1ccd4461c0d067dc2e1046..14bd5221f28ad944c5faf01ecba83615a1e1a884 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 c83a512fa175c74b83b24eadb5ed9791b03351f1..9ac71ebd2c408b47869f5f152ff577e84c958064 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 0622aa91b18a3bd569558eb60efd619d334425b0..bbf342c883142515e300e6eb7e5f5a3af1cd8a2c 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 4f05f75423462f7be3b7774cc87ef98cf17023a6..56e8b3c3c89078a1821d2baaa562b926dd8dd692 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 cb95eea74d3d6f382e638f55f4865bb90a2ee0b3..68a9cbbab4504de8b7b5844047e89ce31a075c60 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 60e4f77ca66286499959cccfdd83b4e4a36ff8a8..3ec3896c83a659ac069a4d27a98f0bcdd193f78e 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");
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 d0c41188d4e536b4983857de9c834913f1355c13..0409cf35adda246f944c7173b219640aa23be3c6 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 fa10df604c017badef9d8052f69e78bf84f5a24c..9a8fb54ae462df9b48b40e4e12c6eb22dcf31e97 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 366bc156e34da003a57ea974cbb0b37fcd4d2596..8c279da0741026322b6ab71d712e438a7e077fe9 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 31b034b7eba3bd5e464c1ba3042a7da9625c2cad..3b1d6da874e03de79e39afcee576d859fac3caa9 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 618f4ba23699ecbd5115e17f720164fcdaa29c7a..19bc8cb1d1874bf3b64fbd6234258d5142171554 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 d3d18e89cb5761dbca06245ff92dd7978d5690f2..4e89103204dce7b4178e80fd2578b2b2d13f20d3 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 a423d96336258c964399869552635daddab3891c..ff5b5c5538eed62b3a43111318fe74d068f46b1a 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 3d391dc3f11fe7ce8272a85d92968a10cc329b26..e984951baeb6834b27d82b26f5afa6dbcc0bf471 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 02197a2b22b9e7fc52c2238f4b2a1f3b76743320..c503e1776014021573afcc8c531229c006286de1 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 4222035acfb71987a7f3f7c50db32cd5aae87262..48cb8d3d175878773b32c6d7cd3f0ef27fa077f0 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 89abf40bc73d3bd30c8d363e5224e3b2ef7a9927..4ca3723b0a3afb299a0eb679f14b1e6b42e12781 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 4c9b13e7748c4d4263cd08a804e19831ba90896a..72228276fe314b36a1344a1ffef36263a4379c4c 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 fc3c3ad6c0727918412f5f778ffb704d7f8d1ad0..3a0d53d6368f2f177afc3fc7528ec27cdbd56027 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 76e7764488e6b306fc5c7bc7be08e4063874b298..665beb68f67087a8dab9f73a8344b317964609c1 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 df9e8f0e327d3247e025794a8ce431f9015439d8..7e9e8f4d8f0ccba1582ab9413831d9d8269c45ee 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 b0f450a2bb7cc4bef696ab23591da2a75c0c1ffb..0d5071d29985b527eb4d2f6819b08646c82a2a30 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 42b77b5446d2b44d983d68c0929de5dabac6afa2..70cfcb2d63c49d5b5b72f6a5f42455060d89035d 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 7c46bc32fcbf78086b5fe6c1cfd9587e80ffd168..5ad17cccdd715cbd95ea98f7b279f9fd3d106ec3 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 f02d8b2f799d114c21455b9cdd5d4561fe69463b..d46a18ffbebbb6ca2cdd78344289627e99b76a78 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 b843fe79583b9b6cd4805ea87523f97ac1273928..27bf521bcebdf2c4cc0376b025af8e65083c45ae 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 887629e24c54a5065aa0ee9aca16bbe5d0becc66..01f1306aa26e2bfa0fd6fa273fc0754d117fa389 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++;