Merge tag 'powerpc-5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Oct 2020 19:21:15 +0000 (12:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Oct 2020 19:21:15 +0000 (12:21 -0700)
Pull powerpc updates from Michael Ellerman:

 - A series from Nick adding ARCH_WANT_IRQS_OFF_ACTIVATE_MM & selecting
   it for powerpc, as well as a related fix for sparc.

 - Remove support for PowerPC 601.

 - Some fixes for watchpoints & addition of a new ptrace flag for
   detecting ISA v3.1 (Power10) watchpoint features.

 - A fix for kernels using 4K pages and the hash MMU on bare metal
   Power9 systems with > 16TB of RAM, or RAM on the 2nd node.

 - A basic idle driver for shallow stop states on Power10.

 - Tweaks to our sched domains code to better inform the scheduler about
   the hardware topology on Power9/10, where two SMT4 cores can be
   presented by firmware as an SMT8 core.

 - A series doing further reworks & cleanups of our EEH code.

 - Addition of a filter for RTAS (firmware) calls done via sys_rtas(),
   to prevent root from overwriting kernel memory.

 - Other smaller features, fixes & cleanups.

Thanks to: Alexey Kardashevskiy, Andrew Donnellan, Aneesh Kumar K.V,
Athira Rajeev, Biwen Li, Cameron Berkenpas, Cédric Le Goater, Christophe
Leroy, Christoph Hellwig, Colin Ian King, Daniel Axtens, David Dai, Finn
Thain, Frederic Barrat, Gautham R. Shenoy, Greg Kurz, Gustavo Romero,
Ira Weiny, Jason Yan, Joel Stanley, Jordan Niethe, Kajol Jain, Konrad
Rzeszutek Wilk, Laurent Dufour, Leonardo Bras, Liu Shixin, Luca
Ceresoli, Madhavan Srinivasan, Mahesh Salgaonkar, Nathan Lynch, Nicholas
Mc Guire, Nicholas Piggin, Nick Desaulniers, Oliver O'Halloran, Pedro
Miraglia Franco de Carvalho, Pratik Rajesh Sampat, Qian Cai, Qinglang
Miao, Ravi Bangoria, Russell Currey, Satheesh Rajendran, Scott Cheloha,
Segher Boessenkool, Srikar Dronamraju, Stan Johnson, Stephen Kitt,
Stephen Rothwell, Thiago Jung Bauermann, Tyrel Datwyler, Vaibhav Jain,
Vaidyanathan Srinivasan, Vasant Hegde, Wang Wensheng, Wolfram Sang, Yang
Yingliang, zhengbin.

* tag 'powerpc-5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (228 commits)
  Revert "powerpc/pci: unmap legacy INTx interrupts when a PHB is removed"
  selftests/powerpc: Fix eeh-basic.sh exit codes
  cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier
  powerpc/time: Make get_tb() common to PPC32 and PPC64
  powerpc/time: Make get_tbl() common to PPC32 and PPC64
  powerpc/time: Remove get_tbu()
  powerpc/time: Avoid using get_tbl() and get_tbu() internally
  powerpc/time: Make mftb() common to PPC32 and PPC64
  powerpc/time: Rename mftbl() to mftb()
  powerpc/32s: Remove #ifdef CONFIG_PPC_BOOK3S_32 in head_book3s_32.S
  powerpc/32s: Rename head_32.S to head_book3s_32.S
  powerpc/32s: Setup the early hash table at all time.
  powerpc/time: Remove ifdef in get_dec() and set_dec()
  powerpc: Remove get_tb_or_rtc()
  powerpc: Remove __USE_RTC()
  powerpc: Tidy up a bit after removal of PowerPC 601.
  powerpc: Remove support for PowerPC 601
  powerpc: Remove PowerPC 601
  powerpc: Drop SYNC_601() ISYNC_601() and SYNC()
  powerpc: Remove CONFIG_PPC601_SYNC_FIX
  ...

224 files changed:
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7
Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_gpci
Documentation/powerpc/isa-versions.rst
Documentation/powerpc/ptrace.rst
arch/Kconfig
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/Makefile.postlink
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/fsl/t1024rdb.dts
arch/powerpc/boot/dts/fsl/t4240rdb.dts
arch/powerpc/boot/util.S
arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
arch/powerpc/configs/85xx/tqm8540_defconfig
arch/powerpc/configs/85xx/tqm8541_defconfig
arch/powerpc/configs/85xx/tqm8555_defconfig
arch/powerpc/configs/85xx/tqm8560_defconfig
arch/powerpc/include/asm/asm-prototypes.h
arch/powerpc/include/asm/book3s/64/hash-4k.h
arch/powerpc/include/asm/book3s/64/hash-64k.h
arch/powerpc/include/asm/book3s/64/mmu-hash.h
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/book3s/64/radix.h
arch/powerpc/include/asm/cacheflush.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/delay.h
arch/powerpc/include/asm/drmem.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/hw_breakpoint.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/icswx.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/nohash/32/hugetlb-8xx.h
arch/powerpc/include/asm/nohash/32/pgtable.h
arch/powerpc/include/asm/pnv-ocxl.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/svm.h
arch/powerpc/include/asm/synch.h
arch/powerpc/include/asm/time.h
arch/powerpc/include/asm/timex.h
arch/powerpc/include/asm/tlb.h
arch/powerpc/include/asm/topology.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/include/uapi/asm/ptrace.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/btext.c
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dt_cpu_ftrs.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/fadump.c
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/head_32.S [deleted file]
arch/powerpc/kernel/head_32.h
arch/powerpc/kernel/head_40x.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_book3s_32.S [new file with mode: 0644]
arch/powerpc/kernel/head_booke.h
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/hw_breakpoint_constraints.c [new file with mode: 0644]
arch/powerpc/kernel/idle.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/l2cr_6xx.S
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/ptrace/ptrace-noadv.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/security.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/tau_6xx.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vdso32/datapage.S
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/lib/code-patching.c
arch/powerpc/lib/sstep.c
arch/powerpc/mm/book3s32/hash_low.S
arch/powerpc/mm/book3s32/mmu.c
arch/powerpc/mm/book3s64/hash_native.c
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/mm/book3s64/internal.h
arch/powerpc/mm/book3s64/mmu_context.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/mm/book3s64/radix_tlb.c
arch/powerpc/mm/book3s64/slb.c
arch/powerpc/mm/drmem.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/kasan/kasan_init_32.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/nohash/8xx.c
arch/powerpc/mm/nohash/fsl_booke.c
arch/powerpc/mm/nohash/tlb.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/ptdump/8xx.c
arch/powerpc/mm/ptdump/bats.c
arch/powerpc/oprofile/cell/spu_task_sync.c
arch/powerpc/perf/hv-gpci-requests.h
arch/powerpc/perf/hv-gpci.c
arch/powerpc/perf/hv-gpci.h
arch/powerpc/perf/imc-pmu.c
arch/powerpc/perf/isa207-common.c
arch/powerpc/perf/isa207-common.h
arch/powerpc/perf/power10-pmu.c
arch/powerpc/perf/power5+-pmu.c
arch/powerpc/perf/power5-pmu.c
arch/powerpc/perf/power6-pmu.c
arch/powerpc/perf/power7-pmu.c
arch/powerpc/perf/ppc970-pmu.c
arch/powerpc/platforms/44x/machine_check.c
arch/powerpc/platforms/44x/ppc476.c
arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
arch/powerpc/platforms/embedded6xx/storcenter.c
arch/powerpc/platforms/powermac/pmac.h
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powermac/sleep.S
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/idle.c
arch/powerpc/platforms/powernv/ocxl.c
arch/powerpc/platforms/powernv/opal-core.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/opal-msglog.c
arch/powerpc/platforms/powernv/opal-prd.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/powernv.h
arch/powerpc/platforms/powernv/rng.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/powernv/vas-window.c
arch/powerpc/platforms/ps3/spu.c
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/lparcfg.c
arch/powerpc/platforms/pseries/papr_scm.c
arch/powerpc/platforms/pseries/rng.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/svm.c
arch/powerpc/sysdev/xics/icp-hv.c
arch/powerpc/sysdev/xive/common.c
arch/powerpc/tools/checkpatch.sh
arch/powerpc/tools/unrel_branch_check.sh
arch/powerpc/xmon/xmon.c
arch/sparc/kernel/smp_64.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpuidle/cpuidle-powernv.c
drivers/macintosh/smu.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_lm87_sensor.c
drivers/macintosh/windfarm_smu_sat.c
drivers/macintosh/windfarm_smu_sensors.c
drivers/misc/cxl/pci.c
drivers/misc/ocxl/Kconfig
drivers/misc/ocxl/afu_irq.c
drivers/misc/ocxl/link.c
drivers/scsi/cxlflash/ocxl_hw.c
drivers/scsi/cxlflash/ocxl_hw.h
fs/exec.c
include/linux/cpuhotplug.h
include/linux/topology.h
include/misc/ocxl.h
include/uapi/asm-generic/hugetlb_encode.h
include/uapi/linux/mman.h
tools/testing/selftests/powerpc/alignment/alignment_handler.c
tools/testing/selftests/powerpc/benchmarks/context_switch.c
tools/testing/selftests/powerpc/dscr/Makefile
tools/testing/selftests/powerpc/dscr/dscr_default_test.c
tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c
tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c
tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c
tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
tools/testing/selftests/powerpc/dscr/dscr_sysfs_thread_test.c
tools/testing/selftests/powerpc/dscr/dscr_user_test.c
tools/testing/selftests/powerpc/eeh/eeh-basic.sh
tools/testing/selftests/powerpc/include/utils.h
tools/testing/selftests/powerpc/mm/bad_accesses.c
tools/testing/selftests/powerpc/pmu/count_stcx_fail.c
tools/testing/selftests/powerpc/pmu/l3_bank_test.c
tools/testing/selftests/powerpc/pmu/per_event_excludes.c
tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
tools/testing/selftests/powerpc/security/rfi_flush.c
tools/testing/selftests/powerpc/security/spectre_v2.c
tools/testing/selftests/powerpc/stringloops/memcmp.c
tools/testing/selftests/powerpc/switch_endian/switch_endian_test.S
tools/testing/selftests/powerpc/syscalls/Makefile
tools/testing/selftests/powerpc/syscalls/rtas_filter.c [new file with mode: 0644]
tools/testing/selftests/powerpc/tm/tm-poison.c
tools/testing/selftests/powerpc/tm/tm-tmspr.c
tools/testing/selftests/powerpc/tm/tm-trap.c
tools/testing/selftests/powerpc/tm/tm-unavailable.c
tools/testing/selftests/powerpc/tm/tm.h
tools/testing/selftests/powerpc/utils.c

index e82fc37..2273627 100644 (file)
@@ -1,3 +1,28 @@
+What:           /sys/bus/event_source/devices/hv_24x7/format
+Date:           September 2020
+Contact:        Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
+Description:    Read-only. Attribute group to describe the magic bits
+                that go into perf_event_attr.config for a particular pmu.
+                (See ABI/testing/sysfs-bus-event_source-devices-format).
+
+                Each attribute under this group defines a bit range of the
+                perf_event_attr.config. All supported attributes are listed
+                below.
+
+                               chip = "config:16-31"
+                               core  = "config:16-31"
+                               domain = "config:0-3"
+                               lpar = "config:0-15"
+                               offset = "config:32-63"
+                               vcpu = "config:16-31"
+
+               For example,
+
+               PM_PB_CYC =  "domain=1,offset=0x80,chip=?,lpar=0x0"
+
+               In this event, '?' after chip specifies that
+               this value will be provided by user while running this event.
+
 What:          /sys/bus/event_source/devices/hv_24x7/interface/catalog
 Date:          February 2014
 Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
index 3ca4e55..6a023b4 100644 (file)
@@ -1,3 +1,34 @@
+What:           /sys/bus/event_source/devices/hv_gpci/format
+Date:           September 2020
+Contact:        Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
+Description:    Read-only. Attribute group to describe the magic bits
+                that go into perf_event_attr.config for a particular pmu.
+                (See ABI/testing/sysfs-bus-event_source-devices-format).
+
+                Each attribute under this group defines a bit range of the
+                perf_event_attr.config. All supported attributes are listed
+                below.
+
+                               counter_info_version  = "config:16-23"
+                               length  = "config:24-31"
+                               partition_id  = "config:32-63"
+                               request = "config:0-31"
+                               sibling_part_id = "config:32-63"
+                               hw_chip_id = "config:32-63"
+                               offset = "config:32-63"
+                               phys_processor_idx = "config:32-63"
+                               secondary_index = "config:0-15"
+                               starting_index = "config:32-63"
+
+               For example,
+
+               processor_core_utilization_instructions_completed = "request=0x94,
+                                       phys_processor_idx=?,counter_info_version=0x8,
+                                       length=8,offset=0x18"
+
+               In this event, '?' after phys_processor_idx specifies this value
+               this value will be provided by user while running this event.
+
 What:          /sys/bus/event_source/devices/hv_gpci/interface/collect_privileged
 Date:          February 2014
 Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
@@ -41,3 +72,10 @@ Contact:     Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
 Description:
                A number indicating the latest version of the gpci interface
                that the kernel is aware of.
+
+What:          /sys/devices/hv_gpci/cpumask
+Date:          October 2020
+Contact:       Linux on PowerPC Developer List <linuxppc-dev@lists.ozlabs.org>
+Description:   read only
+               This sysfs file exposes the cpumask which is designated to make
+               HCALLs to retrieve hv-gpci pmu event counter data.
index a363d8c..dfcb109 100644 (file)
@@ -7,6 +7,7 @@ Mapping of some CPU versions to relevant ISA versions.
 ========= ====================================================================
 CPU       Architecture version
 ========= ====================================================================
+Power10   Power ISA v3.1
 Power9    Power ISA v3.0B
 Power8    Power ISA v2.07
 Power7    Power ISA v2.06
@@ -32,6 +33,7 @@ Key Features
 ========== ==================
 CPU        VMX (aka. Altivec)
 ========== ==================
+Power10    Yes
 Power9     Yes
 Power8     Yes
 Power7     Yes
@@ -47,6 +49,7 @@ PPC970     Yes
 ========== ====
 CPU        VSX
 ========== ====
+Power10    Yes
 Power9     Yes
 Power8     Yes
 Power7     Yes
@@ -62,6 +65,7 @@ PPC970     No
 ========== ====================================
 CPU        Transactional Memory
 ========== ====================================
+Power10    No  (* see Power ISA v3.1, "Appendix A. Notes on the Removal of Transactional Memory from the Architecture")
 Power9     Yes (* see transactional_memory.txt)
 Power8     Yes
 Power7     No
index 864d4b6..77725d6 100644 (file)
@@ -46,6 +46,7 @@ features will have bits indicating whether there is support for::
   #define PPC_DEBUG_FEATURE_DATA_BP_RANGE              0x4
   #define PPC_DEBUG_FEATURE_DATA_BP_MASK               0x8
   #define PPC_DEBUG_FEATURE_DATA_BP_DAWR               0x10
+  #define PPC_DEBUG_FEATURE_DATA_BP_ARCH_31            0x20
 
 2. PTRACE_SETHWDEBUG
 
index 8519d9f..958be05 100644 (file)
@@ -420,6 +420,13 @@ config MMU_GATHER_NO_GATHER
        bool
        depends on MMU_GATHER_TABLE_FREE
 
+config ARCH_WANT_IRQS_OFF_ACTIVATE_MM
+       bool
+       help
+         Temporary select until all architectures can be converted to have
+         irqs disabled over activate_mm. Architectures that do IPI based TLB
+         shootdowns should enable this.
+
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
        bool
 
index 1f0bd7e..e9f13fe 100644 (file)
@@ -59,7 +59,10 @@ config HAVE_SETUP_PER_CPU_AREA
        def_bool PPC64
 
 config NEED_PER_CPU_EMBED_FIRST_CHUNK
-       def_bool PPC64
+       def_bool y if PPC64
+
+config NEED_PER_CPU_PAGE_FIRST_CHUNK
+       def_bool y if PPC64
 
 config NR_IRQS
        int "Number of virtual interrupt numbers"
@@ -148,6 +151,7 @@ config PPC
        select ARCH_USE_QUEUED_RWLOCKS          if PPC_QUEUED_SPINLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS        if PPC_QUEUED_SPINLOCKS
        select ARCH_WANT_IPC_PARSE_VERSION
+       select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
        select ARCH_WEAK_RELEASE_ACQUIRE
        select BINFMT_ELF
        select BUILDTIME_TABLE_SORT
@@ -964,7 +968,7 @@ config PPC_MEM_KEYS
 config PPC_SECURE_BOOT
        prompt "Enable secure boot support"
        bool
-       depends on PPC_POWERNV
+       depends on PPC_POWERNV || PPC_PSERIES
        depends on IMA_ARCH_POLICY
        imply IMA_SECURE_AND_OR_TRUSTED_BOOT
        help
@@ -984,6 +988,19 @@ config PPC_SECVAR_SYSFS
          read/write operations on these variables. Say Y if you have
          secure boot enabled and want to expose variables to userspace.
 
+config PPC_RTAS_FILTER
+       bool "Enable filtering of RTAS syscalls"
+       default y
+       depends on PPC_RTAS
+       help
+         The RTAS syscall API has security issues that could be used to
+         compromise system integrity. This option enforces restrictions on the
+         RTAS calls and arguments passed by userspace programs to mitigate
+         these issues.
+
+         Say Y unless you know what you are doing and the filter is causing
+         problems for you.
+
 endmenu
 
 config ISA_DMA_API
index 3e8da9c..c4f9dbd 100644 (file)
@@ -264,7 +264,8 @@ KBUILD_CFLAGS += $(cpu-as-y)
 KBUILD_AFLAGS += $(aflags-y)
 KBUILD_CFLAGS += $(cflags-y)
 
-head-y                         := arch/powerpc/kernel/head_$(BITS).o
+head-$(CONFIG_PPC64)           := arch/powerpc/kernel/head_64.o
+head-$(CONFIG_PPC_BOOK3S_32)   := arch/powerpc/kernel/head_book3s_32.o
 head-$(CONFIG_PPC_8xx)         := arch/powerpc/kernel/head_8xx.o
 head-$(CONFIG_40x)             := arch/powerpc/kernel/head_40x.o
 head-$(CONFIG_44x)             := arch/powerpc/kernel/head_44x.o
index 2268396..a6c77f4 100644 (file)
@@ -18,7 +18,7 @@ quiet_cmd_relocs_check = CHKREL  $@
 ifdef CONFIG_PPC_BOOK3S_64
       cmd_relocs_check =                                               \
        $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@" ; \
-       $(BASH) $(srctree)/arch/powerpc/tools/unrel_branch_check.sh "$(OBJDUMP)" "$@"
+       $(BASH) $(srctree)/arch/powerpc/tools/unrel_branch_check.sh "$(OBJDUMP)" "$(NM)" "$@"
 else
       cmd_relocs_check =                                               \
        $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@"
index b88fd27..f8ce6d2 100644 (file)
@@ -7,7 +7,7 @@
 # Based on coffboot by Paul Mackerras
 # Simplified for ppc64 by Todd Inglett
 #
-# NOTE:        this code is built for 32 bit in ELF32 format even though
+# NOTE:        this code may be built for 32 bit in ELF32 format even though
 #      it packages a 64 bit kernel.  We do this to simplify the
 #      bootloader and increase compatibility with OpenFirmware.
 #
index 73a6453..dbcd31c 100644 (file)
                        rtc@68 {
                                compatible = "dallas,ds1339";
                                reg = <0x68>;
-                               interrupts = <0x1 0x1 0 0>;
                        };
                };
 
index a56a705..145896f 100644 (file)
                        rtc@68 {
                                compatible = "dallas,ds1374";
                                reg = <0x68>;
-                               interrupts = <0x1 0x1 0 0>;
                        };
                };
 
index f11f058..d03cdb7 100644 (file)
@@ -18,7 +18,7 @@
 
        .text
 
-/* udelay (on non-601 processors) needs to know the period of the
+/* udelay needs to know the period of the
  * timebase in nanoseconds.  This used to be hardcoded to be 60ns
  * (period of 66MHz/4).  Now a variable is used that is initialized to
  * 60 for backward compatibility, but it can be overridden as necessary
@@ -37,19 +37,6 @@ timebase_period_ns:
  */
        .globl  udelay
 udelay:
-       mfspr   r4,SPRN_PVR
-       srwi    r4,r4,16
-       cmpwi   0,r4,1          /* 601 ? */
-       bne     .Ludelay_not_601
-00:    li      r0,86   /* Instructions / microsecond? */
-       mtctr   r0
-10:    addi    r0,r0,0 /* NOP */
-       bdnz    10b
-       subic.  r3,r3,1
-       bne     00b
-       blr
-
-.Ludelay_not_601:
        mulli   r4,r3,1000      /* nanoseconds */
        /*  Change r4 to be the number of ticks using:
         *      (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
index 0683d8c..cea72e8 100644 (file)
@@ -29,9 +29,9 @@ CONFIG_SYN_COOKIES=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_GIANFAR=y
 CONFIG_E1000=y
index 98982a0..bbf040a 100644 (file)
@@ -30,9 +30,9 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_GIANFAR=y
 CONFIG_E100=y
index a6e21db..523ad8d 100644 (file)
@@ -30,9 +30,9 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_GIANFAR=y
 CONFIG_E100=y
index ca1de39..0032ce1 100644 (file)
@@ -30,9 +30,9 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_GIANFAR=y
 CONFIG_E100=y
index ca3b8c8..a80b971 100644 (file)
@@ -30,9 +30,9 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_IDE=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_GIANFAR=y
 CONFIG_E100=y
index de14b1a..d0b832c 100644 (file)
@@ -67,6 +67,7 @@ void single_step_exception(struct pt_regs *regs);
 void program_check_exception(struct pt_regs *regs);
 void alignment_exception(struct pt_regs *regs);
 void StackOverflow(struct pt_regs *regs);
+void stack_overflow_exception(struct pt_regs *regs);
 void kernel_fp_unavailable_exception(struct pt_regs *regs);
 void altivec_unavailable_exception(struct pt_regs *regs);
 void vsx_unavailable_exception(struct pt_regs *regs);
@@ -144,7 +145,9 @@ void _kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
 void _kvmppc_save_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
 
 /* Patch sites */
-extern s32 patch__call_flush_branch_caches;
+extern s32 patch__call_flush_branch_caches1;
+extern s32 patch__call_flush_branch_caches2;
+extern s32 patch__call_flush_branch_caches3;
 extern s32 patch__flush_count_cache_return;
 extern s32 patch__flush_link_stack_return;
 extern s32 patch__call_kvm_flush_link_stack;
index 082b988..b6ac4f8 100644 (file)
  */
 #define MAX_EA_BITS_PER_CONTEXT                46
 
-#define REGION_SHIFT           (MAX_EA_BITS_PER_CONTEXT - 2)
 
 /*
- * Our page table limit us to 64TB. Hence for the kernel mapping,
- * each MAP area is limited to 16 TB.
- * The four map areas are:  linear mapping, vmap, IO and vmemmap
+ * Our page table limit us to 64TB. For 64TB physical memory, we only need 64GB
+ * of vmemmap space. To better support sparse memory layout, we use 61TB
+ * linear map range, 1TB of vmalloc, 1TB of I/O and 1TB of vmememmap.
  */
+#define REGION_SHIFT           (40)
 #define H_KERN_MAP_SIZE                (ASM_CONST(1) << REGION_SHIFT)
 
 /*
- * Define the address range of the kernel non-linear virtual area
- * 16TB
+ * Limits the linear mapping range
  */
-#define H_KERN_VIRT_START      ASM_CONST(0xc000100000000000)
+#define H_MAX_PHYSMEM_BITS     46
+
+/*
+ * Define the address range of the kernel non-linear virtual area (61TB)
+ */
+#define H_KERN_VIRT_START      ASM_CONST(0xc0003d0000000000)
 
 #ifndef __ASSEMBLY__
 #define H_PTE_TABLE_SIZE       (sizeof(pte_t) << H_PTE_INDEX_SIZE)
index f20de11..338e62f 100644 (file)
@@ -7,6 +7,19 @@
 #define H_PUD_INDEX_SIZE  10  // size: 8B << 10 = 8KB, maps 2^10 x 16GB = 16TB
 #define H_PGD_INDEX_SIZE   8  // size: 8B <<  8 = 2KB, maps 2^8  x 16TB =  4PB
 
+/*
+ * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS
+ * if we increase SECTIONS_WIDTH we will not store node details in page->flags and
+ * page_to_nid does a page->section->node lookup
+ * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce
+ * memory requirements with large number of sections.
+ * 51 bits is the max physical real address on POWER9
+ */
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME)
+#define H_MAX_PHYSMEM_BITS     51
+#else
+#define H_MAX_PHYSMEM_BITS     46
+#endif
 
 /*
  * Each context is 512TB size. SLB miss for first context/default context
index 93d18da..683a9c7 100644 (file)
@@ -577,8 +577,8 @@ extern void slb_set_size(u16 size);
  * For vmalloc and memmap, we use just one context with 512TB. With 64 byte
  * struct page size, we need ony 32 TB in memmap for 2PB (51 bits (MAX_PHYSMEM_BITS)).
  */
-#if (MAX_PHYSMEM_BITS > MAX_EA_BITS_PER_CONTEXT)
-#define MAX_KERNEL_CTX_CNT     (1UL << (MAX_PHYSMEM_BITS - MAX_EA_BITS_PER_CONTEXT))
+#if (H_MAX_PHYSMEM_BITS > MAX_EA_BITS_PER_CONTEXT)
+#define MAX_KERNEL_CTX_CNT     (1UL << (H_MAX_PHYSMEM_BITS - MAX_EA_BITS_PER_CONTEXT))
 #else
 #define MAX_KERNEL_CTX_CNT     1
 #endif
index b392384..e0b5294 100644 (file)
@@ -27,21 +27,6 @@ struct mmu_psize_def {
 extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
 #endif /* __ASSEMBLY__ */
 
-/*
- * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS
- * if we increase SECTIONS_WIDTH we will not store node details in page->flags and
- * page_to_nid does a page->section->node lookup
- * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce
- * memory requirements with large number of sections.
- * 51 bits is the max physical real address on POWER9
- */
-#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME) &&  \
-       defined(CONFIG_PPC_64K_PAGES)
-#define MAX_PHYSMEM_BITS 51
-#else
-#define MAX_PHYSMEM_BITS 46
-#endif
-
 /* 64-bit classic hash table MMU */
 #include <asm/book3s/64/mmu-hash.h>
 
@@ -85,7 +70,7 @@ extern unsigned int mmu_base_pid;
 /*
  * memory block size used with radix translation.
  */
-extern unsigned int __ro_after_init radix_mem_block_size;
+extern unsigned long __ro_after_init radix_mem_block_size;
 
 #define PRTB_SIZE_SHIFT        (mmu_pid_bits + 4)
 #define PRTB_ENTRIES   (1ul << mmu_pid_bits)
index f6d2c44..cd3feea 100644 (file)
@@ -294,6 +294,13 @@ extern unsigned long pci_io_base;
 #include <asm/book3s/64/hash.h>
 #include <asm/book3s/64/radix.h>
 
+#if H_MAX_PHYSMEM_BITS > R_MAX_PHYSMEM_BITS
+#define  MAX_PHYSMEM_BITS      H_MAX_PHYSMEM_BITS
+#else
+#define  MAX_PHYSMEM_BITS      R_MAX_PHYSMEM_BITS
+#endif
+
+
 #ifdef CONFIG_PPC_64K_PAGES
 #include <asm/book3s/64/pgtable-64k.h>
 #else
index 0cba794..c7813dc 100644 (file)
  * +------------------------------+  Kernel linear (0xc.....)
  */
 
+
+/*
+ * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS
+ * if we increase SECTIONS_WIDTH we will not store node details in page->flags and
+ * page_to_nid does a page->section->node lookup
+ * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce
+ * memory requirements with large number of sections.
+ * 51 bits is the max physical real address on POWER9
+ */
+
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME)
+#define R_MAX_PHYSMEM_BITS     51
+#else
+#define R_MAX_PHYSMEM_BITS     46
+#endif
+
 #define RADIX_KERN_VIRT_START  ASM_CONST(0xc008000000000000)
 /*
  * 49 =  MAX_EA_BITS_PER_CONTEXT (hash specific). To make sure we pick
index 54764c6..138e46d 100644 (file)
@@ -98,6 +98,16 @@ static inline void invalidate_dcache_range(unsigned long start,
        mb();   /* sync */
 }
 
+#ifdef CONFIG_4xx
+static inline void flush_instruction_cache(void)
+{
+       iccci((void *)KERNELBASE);
+       isync();
+}
+#else
+void flush_instruction_cache(void);
+#endif
+
 #include <asm-generic/cacheflush.h>
 
 #endif /* _ASM_POWERPC_CACHEFLUSH_H */
index 32a15dc..93bc70d 100644 (file)
@@ -9,11 +9,6 @@
 
 #ifndef __ASSEMBLY__
 
-/*
- * Added to include __machine_check_early_realmode_* functions
- */
-#include <asm/mce.h>
-
 /* This structure can grow, it's real size is used by head.S code
  * via the mkdefs mechanism.
  */
@@ -170,6 +165,7 @@ static inline void cpu_feature_keys_init(void) { }
 #else  /* CONFIG_PPC32 */
 /* Define these to 0 for the sake of tests in common code */
 #define CPU_FTR_PPC_LE                 (0)
+#define CPU_FTR_SPE                    (0)
 #endif
 
 /*
@@ -299,8 +295,6 @@ static inline void cpu_feature_keys_init(void) { }
 #define CPU_FTR_MAYBE_CAN_NAP  0
 #endif
 
-#define CPU_FTRS_PPC601        (CPU_FTR_COMMON | \
-       CPU_FTR_COHERENT_ICACHE)
 #define CPU_FTRS_603   (CPU_FTR_COMMON | CPU_FTR_MAYBE_CAN_DOZE | \
            CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE | CPU_FTR_NOEXECUTE)
 #define CPU_FTRS_604   (CPU_FTR_COMMON | CPU_FTR_PPC_LE)
@@ -516,10 +510,8 @@ static inline void cpu_feature_keys_init(void) { }
 #else
 enum {
        CPU_FTRS_POSSIBLE =
-#ifdef CONFIG_PPC_BOOK3S_601
-           CPU_FTRS_PPC601 |
-#elif defined(CONFIG_PPC_BOOK3S_32)
-           CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
+#ifdef CONFIG_PPC_BOOK3S_32
+           CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU |
            CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 |
            CPU_FTRS_750FX2 | CPU_FTRS_750FX | CPU_FTRS_750GX |
            CPU_FTRS_7400_NOTAU | CPU_FTRS_7400 | CPU_FTRS_7450_20 |
@@ -594,9 +586,7 @@ enum {
 #else
 enum {
        CPU_FTRS_ALWAYS =
-#ifdef CONFIG_PPC_BOOK3S_601
-           CPU_FTRS_PPC601 &
-#elif defined(CONFIG_PPC_BOOK3S_32)
+#ifdef CONFIG_PPC_BOOK3S_32
            CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU &
            CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 &
            CPU_FTRS_750FX2 & CPU_FTRS_750FX & CPU_FTRS_750GX &
index deb99fd..98c8bd1 100644 (file)
@@ -23,7 +23,6 @@
 extern int threads_per_core;
 extern int threads_per_subcore;
 extern int threads_shift;
-extern bool has_big_cores;
 extern cpumask_t threads_core_mask;
 #else
 #define threads_per_core       1
index 66963f7..51bb8c1 100644 (file)
@@ -54,7 +54,7 @@ extern void udelay(unsigned long usecs);
 ({                                                                             \
        typeof(condition) __ret;                                               \
        unsigned long __loops = tb_ticks_per_usec * timeout;                   \
-       unsigned long __start = get_tbl();                                     \
+       unsigned long __start = mftb();                                     \
                                                                                \
        if (delay) {                                                           \
                while (!(__ret = (condition)) &&                               \
index 17ccc64..bf2402f 100644 (file)
@@ -8,26 +8,39 @@
 #ifndef _ASM_POWERPC_LMB_H
 #define _ASM_POWERPC_LMB_H
 
+#include <linux/sched.h>
+
 struct drmem_lmb {
        u64     base_addr;
        u32     drc_index;
        u32     aa_index;
        u32     flags;
-#ifdef CONFIG_MEMORY_HOTPLUG
-       int     nid;
-#endif
 };
 
 struct drmem_lmb_info {
        struct drmem_lmb        *lmbs;
        int                     n_lmbs;
-       u32                     lmb_size;
+       u64                     lmb_size;
 };
 
 extern struct drmem_lmb_info *drmem_info;
 
+static inline struct drmem_lmb *drmem_lmb_next(struct drmem_lmb *lmb,
+                                              const struct drmem_lmb *start)
+{
+       /*
+        * DLPAR code paths can take several milliseconds per element
+        * when interacting with firmware. Ensure that we don't
+        * unfairly monopolize the CPU.
+        */
+       if (((++lmb - start) % 16) == 0)
+               cond_resched();
+
+       return lmb;
+}
+
 #define for_each_drmem_lmb_in_range(lmb, start, end)           \
-       for ((lmb) = (start); (lmb) < (end); (lmb)++)
+       for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start))
 
 #define for_each_drmem_lmb(lmb)                                        \
        for_each_drmem_lmb_in_range((lmb),                      \
@@ -67,7 +80,7 @@ struct of_drconf_cell_v2 {
 #define DRCONF_MEM_RESERVED    0x00000080
 #define DRCONF_MEM_HOTREMOVABLE        0x00000100
 
-static inline u32 drmem_lmb_size(void)
+static inline u64 drmem_lmb_size(void)
 {
        return drmem_info->lmb_size;
 }
@@ -105,22 +118,4 @@ static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb)
        lmb->aa_index = 0xffffffff;
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static inline void lmb_set_nid(struct drmem_lmb *lmb)
-{
-       lmb->nid = memory_add_physaddr_to_nid(lmb->base_addr);
-}
-static inline void lmb_clear_nid(struct drmem_lmb *lmb)
-{
-       lmb->nid = -1;
-}
-#else
-static inline void lmb_set_nid(struct drmem_lmb *lmb)
-{
-}
-static inline void lmb_clear_nid(struct drmem_lmb *lmb)
-{
-}
-#endif
-
 #endif /* _ASM_POWERPC_LMB_H */
index d5f369b..b1a5bba 100644 (file)
@@ -27,7 +27,6 @@ struct pci_dn;
 #define EEH_FORCE_DISABLED     0x02    /* EEH disabled                      */
 #define EEH_PROBE_MODE_DEV     0x04    /* From PCI device                   */
 #define EEH_PROBE_MODE_DEVTREE 0x08    /* From device tree                  */
-#define EEH_VALID_PE_ZERO      0x10    /* PE#0 is valid                     */
 #define EEH_ENABLE_IO_FOR_LOG  0x20    /* Enable IO for log                 */
 #define EEH_EARLY_DUMP_LOG     0x40    /* Dump log immediately              */
 
@@ -74,7 +73,6 @@ struct pci_dn;
 struct eeh_pe {
        int type;                       /* PE type: PHB/Bus/Device      */
        int state;                      /* PE EEH dependent mode        */
-       int config_addr;                /* Traditional PCI address      */
        int addr;                       /* PE configuration address     */
        struct pci_controller *phb;     /* Associated PHB               */
        struct pci_bus *bus;            /* Top PCI bus for bus PE       */
@@ -216,7 +214,6 @@ enum {
 
 struct eeh_ops {
        char *name;
-       int (*init)(void);
        struct eeh_dev *(*probe)(struct pci_dev *pdev);
        int (*set_option)(struct eeh_pe *pe, int option);
        int (*get_state)(struct eeh_pe *pe, int *delay);
@@ -281,8 +278,7 @@ int eeh_phb_pe_create(struct pci_controller *phb);
 int eeh_wait_state(struct eeh_pe *pe, int max_wait);
 struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
 struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root);
-struct eeh_pe *eeh_pe_get(struct pci_controller *phb,
-                         int pe_no, int config_addr);
+struct eeh_pe *eeh_pe_get(struct pci_controller *phb, int pe_no);
 int eeh_pe_tree_insert(struct eeh_dev *edev, struct eeh_pe *new_pe_parent);
 int eeh_pe_tree_remove(struct eeh_dev *edev);
 void eeh_pe_update_time_stamp(struct eeh_pe *pe);
@@ -295,8 +291,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe);
 struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
 
 void eeh_show_enabled(void);
-int __init eeh_ops_register(struct eeh_ops *ops);
-int __exit eeh_ops_unregister(const char *name);
+int __init eeh_init(struct eeh_ops *ops);
 int eeh_check_failure(const volatile void __iomem *token);
 int eeh_dev_check_failure(struct eeh_dev *edev);
 void eeh_addr_cache_init(void);
index fbb3770..c1fbccb 100644 (file)
 #define H_CPU_CHAR_THREAD_RECONFIG_CTRL        (1ull << 57) // IBM bit 6
 #define H_CPU_CHAR_COUNT_CACHE_DISABLED        (1ull << 56) // IBM bit 7
 #define H_CPU_CHAR_BCCTR_FLUSH_ASSIST  (1ull << 54) // IBM bit 9
+#define H_CPU_CHAR_BCCTR_LINK_FLUSH_ASSIST (1ull << 52) // IBM bit 11
 
 #define H_CPU_BEHAV_FAVOUR_SECURITY    (1ull << 63) // IBM bit 0
 #define H_CPU_BEHAV_L1D_FLUSH_PR       (1ull << 62) // IBM bit 1
 #define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR  (1ull << 61) // IBM bit 2
 #define H_CPU_BEHAV_FLUSH_COUNT_CACHE  (1ull << 58) // IBM bit 5
+#define H_CPU_BEHAV_FLUSH_LINK_STACK   (1ull << 57) // IBM bit 6
 
 /* Flag values used in H_REGISTER_PROC_TBL hcall */
 #define PROC_TABLE_OP_MASK     0x18
@@ -560,6 +562,42 @@ struct hv_guest_state {
 /* Latest version of hv_guest_state structure */
 #define HV_GUEST_STATE_VERSION 1
 
+/*
+ * From the document "H_GetPerformanceCounterInfo Interface" v1.07
+ *
+ * H_GET_PERF_COUNTER_INFO argument
+ */
+struct hv_get_perf_counter_info_params {
+       __be32 counter_request; /* I */
+       __be32 starting_index;  /* IO */
+       __be16 secondary_index; /* IO */
+       __be16 returned_values; /* O */
+       __be32 detail_rc; /* O, only needed when called via *_norets() */
+
+       /*
+        * O, size each of counter_value element in bytes, only set for version
+        * >= 0x3
+        */
+       __be16 cv_element_size;
+
+       /* I, 0 (zero) for versions < 0x3 */
+       __u8 counter_info_version_in;
+
+       /* O, 0 (zero) if version < 0x3. Must be set to 0 when making hcall */
+       __u8 counter_info_version_out;
+       __u8 reserved[0xC];
+       __u8 counter_value[];
+} __packed;
+
+#define HGPCI_REQ_BUFFER_SIZE  4096
+#define HGPCI_MAX_DATA_BYTES \
+       (HGPCI_REQ_BUFFER_SIZE - sizeof(struct hv_get_perf_counter_info_params))
+
+struct hv_gpci_request_buffer {
+       struct hv_get_perf_counter_info_params params;
+       uint8_t bytes[HGPCI_MAX_DATA_BYTES];
+} __packed;
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
index db206a7..abebfbe 100644 (file)
@@ -10,6 +10,7 @@
 #define _PPC_BOOK3S_64_HW_BREAKPOINT_H
 
 #include <asm/cpu_has_feature.h>
+#include <asm/inst.h>
 
 #ifdef __KERNEL__
 struct arch_hw_breakpoint {
@@ -17,6 +18,7 @@ struct arch_hw_breakpoint {
        u16             type;
        u16             len; /* length of the target data symbol */
        u16             hw_len; /* length programmed in hw */
+       u8              flags;
 };
 
 /* Note: Don't change the first 6 bits below as they are in the same order
@@ -36,12 +38,15 @@ struct arch_hw_breakpoint {
 #define HW_BRK_TYPE_PRIV_ALL   (HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \
                                 HW_BRK_TYPE_HYP)
 
+#define HW_BRK_FLAG_DISABLED   0x1
+
 /* Minimum granularity */
 #ifdef CONFIG_PPC_8xx
 #define HW_BREAKPOINT_SIZE  0x4
 #else
 #define HW_BREAKPOINT_SIZE  0x8
 #endif
+#define HW_BREAKPOINT_SIZE_QUADWORD    0x10
 
 #define DABR_MAX_LEN   8
 #define DAWR_MAX_LEN   512
@@ -51,6 +56,13 @@ static inline int nr_wp_slots(void)
        return cpu_has_feature(CPU_FTR_DAWR1) ? 2 : 1;
 }
 
+bool wp_check_constraints(struct pt_regs *regs, struct ppc_inst instr,
+                         unsigned long ea, int type, int size,
+                         struct arch_hw_breakpoint *info);
+
+void wp_get_instr_detail(struct pt_regs *regs, struct ppc_inst *instr,
+                        int *type, int *size, unsigned long *ea);
+
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 #include <linux/kdebug.h>
 #include <asm/reg.h>
index 35060be..0363734 100644 (file)
@@ -25,9 +25,8 @@
 #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 */
-#define PACA_IRQ_HMI           0x20
-#define PACA_IRQ_PMI           0x40
+#define PACA_IRQ_HMI           0x10
+#define PACA_IRQ_PMI           0x20
 
 /*
  * Some soft-masked interrupts must be hard masked until they are replayed
@@ -369,12 +368,6 @@ static inline void may_hard_irq_enable(void) { }
 
 #define ARCH_IRQ_INIT_FLAGS    IRQ_NOREQUEST
 
-/*
- * interrupt-retrigger: should we handle this via lost interrupts and IPIs
- * or should we not care like we do now ? --BenH.
- */
-struct irq_chip;
-
 #endif  /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HW_IRQ_H */
index b0c70a3..f6599cc 100644 (file)
@@ -156,8 +156,7 @@ struct coprocessor_request_block {
        u8 reserved[32];
 
        struct coprocessor_status_block csb;
-} __packed;
-
+} __aligned(128);
 
 /* RFC02167 Initiate Coprocessor Instructions document
  * Chapter 8.2.1.1.1 RS
@@ -188,6 +187,9 @@ static inline int icswx(__be32 ccw, struct coprocessor_request_block *crb)
        __be64 ccw_reg = ccw;
        u32 cr;
 
+       /* NB: the same structures are used by VAS-NX */
+       BUILD_BUG_ON(sizeof(*crb) != 128);
+
        __asm__ __volatile__(
        PPC_ICSWX(%1,0,%2) "\n"
        "mfcr %0\n"
index 814dfab..4f983ca 100644 (file)
@@ -35,7 +35,6 @@ static __inline__ int irq_canonicalize(int irq)
 
 extern int distribute_irqs;
 
-struct irqaction;
 struct pt_regs;
 
 #define __ARCH_HAS_DO_SOFTIRQ
index a90b892..9508107 100644 (file)
@@ -65,7 +65,6 @@ struct machdep_calls {
        void __noreturn (*restart)(char *cmd);
        void __noreturn (*halt)(void);
        void            (*panic)(char *str);
-       void            (*cpu_die)(void);
 
        long            (*time_init)(void); /* Optional, may be NULL */
 
@@ -222,8 +221,6 @@ struct machdep_calls {
 
 extern void e500_idle(void);
 extern void power4_idle(void);
-extern void power7_idle(void);
-extern void power9_idle(void);
 extern void ppc6xx_idle(void);
 extern void book3e_idle(void);
 
index 7f3658a..e02aa79 100644 (file)
@@ -244,7 +244,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  */
 static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
-       switch_mm(prev, next, current);
+       switch_mm_irqs_off(prev, next, current);
 }
 
 /* We don't currently use enter_lazy_tlb() for anything */
index e752a58..39be9ae 100644 (file)
@@ -65,4 +65,18 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
        pte_update(mm, addr, ptep, clr, set, 1);
 }
 
+#ifdef CONFIG_PPC_4K_PAGES
+static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+                                      struct page *page, int writable)
+{
+       size_t size = huge_page_size(hstate_vma(vma));
+
+       if (size == SZ_16K)
+               return __pte(pte_val(entry) & ~_PAGE_HUGE);
+       else
+               return entry;
+}
+#define arch_make_huge_pte arch_make_huge_pte
+#endif
+
 #endif /* _ASM_POWERPC_NOHASH_32_HUGETLB_8XX_H */
index b9e134d..ee2243b 100644 (file)
@@ -227,6 +227,19 @@ static inline void pmd_clear(pmd_t *pmdp)
  */
 #ifdef CONFIG_PPC_8xx
 static pmd_t *pmd_off(struct mm_struct *mm, unsigned long addr);
+static int hugepd_ok(hugepd_t hpd);
+
+static int number_of_cells_per_pte(pmd_t *pmd, pte_basic_t val, int huge)
+{
+       if (!huge)
+               return PAGE_SIZE / SZ_4K;
+       else if (hugepd_ok(*((hugepd_t *)pmd)))
+               return 1;
+       else if (IS_ENABLED(CONFIG_PPC_4K_PAGES) && !(val & _PAGE_HUGE))
+               return SZ_16K / SZ_4K;
+       else
+               return SZ_512K / SZ_4K;
+}
 
 static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, pte_t *p,
                                     unsigned long clr, unsigned long set, int huge)
@@ -237,12 +250,7 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
        int num, i;
        pmd_t *pmd = pmd_off(mm, addr);
 
-       if (!huge)
-               num = PAGE_SIZE / SZ_4K;
-       else if ((pmd_val(*pmd) & _PMD_PAGE_MASK) != _PMD_PAGE_8M)
-               num = SZ_512K / SZ_4K;
-       else
-               num = 1;
+       num = number_of_cells_per_pte(pmd, new, huge);
 
        for (i = 0; i < num; i++, entry++, new += SZ_4K)
                *entry = new;
index ee79d2c..d37eded 100644 (file)
@@ -28,7 +28,4 @@ int pnv_ocxl_spa_setup(struct pci_dev *dev, void *spa_mem, int PE_mask, void **p
 void pnv_ocxl_spa_release(void *platform_data);
 int pnv_ocxl_spa_remove_pe_from_cache(void *platform_data, int pe_handle);
 
-int pnv_ocxl_alloc_xive_irq(u32 *irq, u64 *trigger_addr);
-void pnv_ocxl_free_xive_irq(u32 irq);
-
 #endif /* _ASM_PNV_OCXL_H */
index b4cc660..511786f 100644 (file)
@@ -382,16 +382,6 @@ n:
 #endif
 
 /* various errata or part fixups */
-#ifdef CONFIG_PPC601_SYNC_FIX
-#define SYNC           sync; isync
-#define SYNC_601       sync
-#define ISYNC_601      isync
-#else
-#define        SYNC
-#define SYNC_601
-#define ISYNC_601
-#endif
-
 #if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define MFTB(dest)                     \
 90:    mfspr dest, SPRN_TBRL;          \
@@ -411,8 +401,7 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
 #define MFTBU(dest)                    mfspr dest, SPRN_TBRU
 #endif
 
-/* tlbsync is not implemented on 601 */
-#if !defined(CONFIG_SMP) || defined(CONFIG_PPC_BOOK3S_601)
+#ifndef CONFIG_SMP
 #define TLBSYNC
 #else
 #define TLBSYNC                tlbsync; sync
index ed0d633..365290b 100644 (file)
@@ -220,6 +220,7 @@ struct thread_struct {
        unsigned long   tm_tar;
        unsigned long   tm_ppr;
        unsigned long   tm_dscr;
+       unsigned long   tm_amr;
 
        /*
         * Checkpointed FP and VSX 0-31 register set.
@@ -432,16 +433,10 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
 extern int powersave_nap;      /* set if nap mode can be used in idle loop */
 
 extern void power7_idle_type(unsigned long type);
-extern void power9_idle_type(unsigned long stop_psscr_val,
+extern void arch300_idle_type(unsigned long stop_psscr_val,
                              unsigned long stop_psscr_mask);
 
-extern void flush_instruction_cache(void);
-extern void hard_reset_now(void);
-extern void poweroff_now(void);
 extern int fix_alignment(struct pt_regs *);
-extern void cvt_fd(float *from, double *to);
-extern void cvt_df(double *from, float *to);
-extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
 #ifdef CONFIG_PPC64
 /*
index 155a197..e2c778c 100644 (file)
@@ -243,11 +243,7 @@ static inline void set_trap_norestart(struct pt_regs *regs)
 }
 
 #define arch_has_single_step() (1)
-#ifndef CONFIG_PPC_BOOK3S_601
 #define arch_has_block_step()  (true)
-#else
-#define arch_has_block_step()  (false)
-#endif
 #define ARCH_HAS_USER_SINGLE_STEP_REPORT
 
 /*
index 88fb884..f877a57 100644 (file)
 #define SPRN_TSCR      0x399   /* Thread Switch Control Register */
 
 #define SPRN_DEC       0x016           /* Decrement Register */
+#define SPRN_PIT       0x3DB           /* Programmable Interval Timer (40x/BOOKE) */
+
 #define SPRN_DER       0x095           /* Debug Enable Register */
 #define DER_RSTE       0x40000000      /* Reset Interrupt */
 #define DER_CHSTPE     0x20000000      /* Check Stop */
 #define THRM1_TIN      (1 << 31)
 #define THRM1_TIV      (1 << 30)
 #define THRM1_THRES(x) ((x&0x7f)<<23)
-#define THRM3_SITV(x)  ((x&0x3fff)<<1)
+#define THRM3_SITV(x)  ((x & 0x1fff) << 1)
 #define THRM1_TID      (1<<2)
 #define THRM1_TIE      (1<<1)
 #define THRM1_V                (1<<0)
 #define PVR_POWER8NVL  0x004C
 #define PVR_POWER8     0x004D
 #define PVR_POWER9     0x004E
+#define PVR_POWER10    0x0080
 #define PVR_BE         0x0070
 #define PVR_PA6T       0x0090
 
@@ -1416,8 +1419,7 @@ static inline void msr_check_and_clear(unsigned long bits)
                __msr_check_and_clear(bits);
 }
 
-#ifdef __powerpc64__
-#if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
+#if defined(CONFIG_PPC_CELL) || defined(CONFIG_E500)
 #define mftb()         ({unsigned long rval;                           \
                        asm volatile(                                   \
                                "90:    mfspr %0, %2;\n"                \
@@ -1427,29 +1429,23 @@ static inline void msr_check_and_clear(unsigned long bits)
                        : "=r" (rval) \
                        : "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL) : "cr0"); \
                        rval;})
+#elif defined(CONFIG_PPC_8xx)
+#define mftb()         ({unsigned long rval;   \
+                       asm volatile("mftbl %0" : "=r" (rval)); rval;})
 #else
 #define mftb()         ({unsigned long rval;   \
                        asm volatile("mfspr %0, %1" : \
                                     "=r" (rval) : "i" (SPRN_TBRL)); rval;})
 #endif /* !CONFIG_PPC_CELL */
 
-#else /* __powerpc64__ */
-
 #if defined(CONFIG_PPC_8xx)
-#define mftbl()                ({unsigned long rval;   \
-                       asm volatile("mftbl %0" : "=r" (rval)); rval;})
 #define mftbu()                ({unsigned long rval;   \
                        asm volatile("mftbu %0" : "=r" (rval)); rval;})
 #else
-#define mftbl()                ({unsigned long rval;   \
-                       asm volatile("mfspr %0, %1" : "=r" (rval) : \
-                               "i" (SPRN_TBRL)); rval;})
 #define mftbu()                ({unsigned long rval;   \
                        asm volatile("mfspr %0, %1" : "=r" (rval) : \
                                "i" (SPRN_TBRU)); rval;})
 #endif
-#define mftb()         mftbl()
-#endif /* !__powerpc64__ */
 
 #define mttbl(v)       asm volatile("mttbl %0":: "r"(v))
 #define mttbu(v)       asm volatile("mttbu %0":: "r"(v))
index ff30f10..29a948e 100644 (file)
 #define SPRN_L1CSR1    0x3F3   /* L1 Cache Control and Status Register 1 */
 #define SPRN_MMUCSR0   0x3F4   /* MMU Control and Status Register 0 */
 #define SPRN_MMUCFG    0x3F7   /* MMU Configuration Register */
-#define SPRN_PIT       0x3DB   /* Programmable Interval Timer */
 #define SPRN_BUCSR     0x3F5   /* Branch Unit Control and Status */
 #define SPRN_L2CSR0    0x3F9   /* L2 Data Cache Control and Status Register 0 */
 #define SPRN_L2CSR1    0x3FA   /* L2 Data Cache Control and Status Register 1 */
index 49a25e2..b2035b2 100644 (file)
@@ -28,8 +28,8 @@
 extern int boot_cpuid;
 extern int spinning_secondaries;
 extern u32 *cpu_to_phys_id;
+extern bool coregroup_enabled;
 
-extern void cpu_die(void);
 extern int cpu_to_chip_id(int cpu);
 
 #ifdef CONFIG_SMP
@@ -50,6 +50,9 @@ struct smp_ops_t {
        int   (*cpu_disable)(void);
        void  (*cpu_die)(unsigned int nr);
        int   (*cpu_bootable)(unsigned int nr);
+#ifdef CONFIG_HOTPLUG_CPU
+       void  (*cpu_offline_self)(void);
+#endif
 };
 
 extern int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us);
@@ -118,11 +121,6 @@ static inline struct cpumask *cpu_sibling_mask(int cpu)
        return per_cpu(cpu_sibling_map, cpu);
 }
 
-static inline struct cpumask *cpu_core_mask(int cpu)
-{
-       return per_cpu(cpu_core_map, cpu);
-}
-
 static inline struct cpumask *cpu_l2_cache_mask(int cpu)
 {
        return per_cpu(cpu_l2_cache_map, cpu);
@@ -135,6 +133,19 @@ static inline struct cpumask *cpu_smallcore_mask(int cpu)
 
 extern int cpu_to_core_id(int cpu);
 
+extern bool has_big_cores;
+
+#define cpu_smt_mask cpu_smt_mask
+#ifdef CONFIG_SCHED_SMT
+static inline const struct cpumask *cpu_smt_mask(int cpu)
+{
+       if (has_big_cores)
+               return per_cpu(cpu_smallcore_map, cpu);
+
+       return per_cpu(cpu_sibling_map, cpu);
+}
+#endif /* CONFIG_SCHED_SMT */
+
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  *
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
@@ -243,7 +254,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
  * 64-bit but defining them all here doesn't harm
  */
 extern void generic_secondary_smp_init(void);
-extern void generic_secondary_thread_init(void);
 extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
index 85580b3..7546402 100644 (file)
@@ -15,6 +15,8 @@ static inline bool is_secure_guest(void)
        return mfmsr() & MSR_S;
 }
 
+void __init svm_swiotlb_init(void);
+
 void dtl_cache_ctor(void *addr);
 #define get_dtl_cache_ctor()   (is_secure_guest() ? dtl_cache_ctor : NULL)
 
@@ -25,6 +27,8 @@ static inline bool is_secure_guest(void)
        return false;
 }
 
+static inline void svm_swiotlb_init(void) {}
+
 #define get_dtl_cache_ctor() NULL
 
 #endif /* CONFIG_PPC_SVM */
index aca70fb..1d67bc8 100644 (file)
@@ -3,8 +3,9 @@
 #define _ASM_POWERPC_SYNCH_H 
 #ifdef __KERNEL__
 
+#include <asm/cputable.h>
 #include <asm/feature-fixups.h>
-#include <asm/asm-const.h>
+#include <asm/ppc-opcode.h>
 
 #ifndef __ASSEMBLY__
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
@@ -20,6 +21,22 @@ static inline void isync(void)
 {
        __asm__ __volatile__ ("isync" : : : "memory");
 }
+
+static inline void ppc_after_tlbiel_barrier(void)
+{
+       asm volatile("ptesync": : :"memory");
+       /*
+        * POWER9, POWER10 need a cp_abort after tlbiel to ensure the copy is
+        * invalidated correctly. If this is not done, the paste can take data
+        * from the physical address that was translated at copy time.
+        *
+        * POWER9 in practice does not need this, because address spaces with
+        * accelerators mapped will use tlbie (which does invalidate the copy)
+        * to invalidate translations. It's not possible to limit POWER10 this
+        * way due to local copy-paste.
+        */
+       asm volatile(ASM_FTR_IFSET(PPC_CP_ABORT, "", %0) : : "i" (CPU_FTR_ARCH_31) : "memory");
+}
 #endif /* __ASSEMBLY__ */
 
 #if defined(__powerpc64__)
index cb32672..2f566c1 100644 (file)
@@ -38,44 +38,10 @@ struct div_result {
        u64 result_low;
 };
 
-/* Accessor functions for the timebase (RTC on 601) registers. */
-#define __USE_RTC()    (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-
-#ifdef CONFIG_PPC64
-
 /* For compatibility, get_tbl() is defined as get_tb() on ppc64 */
-#define get_tbl                get_tb
-
-#else
-
 static inline unsigned long get_tbl(void)
 {
-       return mftbl();
-}
-
-static inline unsigned int get_tbu(void)
-{
-       return mftbu();
-}
-#endif /* !CONFIG_PPC64 */
-
-static inline unsigned int get_rtcl(void)
-{
-       unsigned int rtcl;
-
-       asm volatile("mfrtcl %0" : "=r" (rtcl));
-       return rtcl;
-}
-
-static inline u64 get_rtc(void)
-{
-       unsigned int hi, lo, hi2;
-
-       do {
-               asm volatile("mfrtcu %0; mfrtcl %1; mfrtcu %2"
-                            : "=r" (hi), "=r" (lo), "=r" (hi2));
-       } while (hi2 != hi);
-       return (u64)hi * 1000000000 + lo;
+       return mftb();
 }
 
 static inline u64 get_vtb(void)
@@ -87,30 +53,21 @@ static inline u64 get_vtb(void)
        return 0;
 }
 
-#ifdef CONFIG_PPC64
-static inline u64 get_tb(void)
-{
-       return mftb();
-}
-#else /* CONFIG_PPC64 */
 static inline u64 get_tb(void)
 {
        unsigned int tbhi, tblo, tbhi2;
 
+       if (IS_ENABLED(CONFIG_PPC64))
+               return mftb();
+
        do {
-               tbhi = get_tbu();
-               tblo = get_tbl();
-               tbhi2 = get_tbu();
+               tbhi = mftbu();
+               tblo = mftb();
+               tbhi2 = mftbu();
        } while (tbhi != tbhi2);
 
        return ((u64)tbhi << 32) | tblo;
 }
-#endif /* !CONFIG_PPC64 */
-
-static inline u64 get_tb_or_rtc(void)
-{
-       return __USE_RTC() ? get_rtc() : get_tb();
-}
 
 static inline void set_tb(unsigned int upper, unsigned int lower)
 {
@@ -127,11 +84,10 @@ static inline void set_tb(unsigned int upper, unsigned int lower)
  */
 static inline u64 get_dec(void)
 {
-#if defined(CONFIG_40x)
-       return (mfspr(SPRN_PIT));
-#else
-       return (mfspr(SPRN_DEC));
-#endif
+       if (IS_ENABLED(CONFIG_40x))
+               return mfspr(SPRN_PIT);
+
+       return mfspr(SPRN_DEC);
 }
 
 /*
@@ -141,23 +97,17 @@ static inline u64 get_dec(void)
  */
 static inline void set_dec(u64 val)
 {
-#if defined(CONFIG_40x)
-       mtspr(SPRN_PIT, (u32) val);
-#else
-#ifndef CONFIG_BOOKE
-       --val;
-#endif
-       mtspr(SPRN_DEC, val);
-#endif /* not 40x */
+       if (IS_ENABLED(CONFIG_40x))
+               mtspr(SPRN_PIT, (u32)val);
+       else if (IS_ENABLED(CONFIG_BOOKE))
+               mtspr(SPRN_DEC, val);
+       else
+               mtspr(SPRN_DEC, val - 1);
 }
 
 static inline unsigned long tb_ticks_since(unsigned long tstamp)
 {
-       if (__USE_RTC()) {
-               int delta = get_rtcl() - (unsigned int) tstamp;
-               return delta < 0 ? delta + 1000000000 : delta;
-       }
-       return get_tbl() - tstamp;
+       return mftb() - tstamp;
 }
 
 #define mulhwu(x,y) \
index 6047402..9598887 100644 (file)
@@ -17,9 +17,6 @@ typedef unsigned long cycles_t;
 
 static inline cycles_t get_cycles(void)
 {
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-               return 0;
-
        return mftb();
 }
 
index fbc6f30..d97f061 100644 (file)
@@ -66,19 +66,6 @@ static inline int mm_is_thread_local(struct mm_struct *mm)
                return false;
        return cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm));
 }
-static inline void mm_reset_thread_local(struct mm_struct *mm)
-{
-       WARN_ON(atomic_read(&mm->context.copros) > 0);
-       /*
-        * It's possible for mm_access to take a reference on mm_users to
-        * access the remote mm from another thread, but it's not allowed
-        * to set mm_cpumask, so mm_users may be > 1 here.
-        */
-       WARN_ON(current->mm != mm);
-       atomic_set(&mm->context.active_cpus, 1);
-       cpumask_clear(mm_cpumask(mm));
-       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-}
 #else /* CONFIG_PPC_BOOK3S_64 */
 static inline int mm_is_thread_local(struct mm_struct *mm)
 {
index f0b6300..8728590 100644 (file)
@@ -86,14 +86,27 @@ static inline int cpu_distance(__be32 *cpu1_assoc, __be32 *cpu2_assoc)
 
 #endif /* CONFIG_NUMA */
 
+struct drmem_lmb;
+int of_drconf_to_nid_single(struct drmem_lmb *lmb);
+
 #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
 extern int find_and_online_cpu_nid(int cpu);
+extern int cpu_to_coregroup_id(int cpu);
 #else
 static inline int find_and_online_cpu_nid(int cpu)
 {
        return 0;
 }
 
+static inline int cpu_to_coregroup_id(int cpu)
+{
+#ifdef CONFIG_SMP
+       return cpu_to_core_id(cpu);
+#else
+       return 0;
+#endif
+}
+
 #endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */
 
 #include <asm-generic/topology.h>
@@ -104,15 +117,10 @@ static inline int find_and_online_cpu_nid(int cpu)
 #ifdef CONFIG_PPC64
 #include <asm/smp.h>
 
-#ifdef CONFIG_PPC_SPLPAR
-int get_physical_package_id(int cpu);
-#define topology_physical_package_id(cpu)      (get_physical_package_id(cpu))
-#else
 #define topology_physical_package_id(cpu)      (cpu_to_chip_id(cpu))
-#endif
 
 #define topology_sibling_cpumask(cpu)  (per_cpu(cpu_sibling_map, cpu))
-#define topology_core_cpumask(cpu)     (per_cpu(cpu_core_map, cpu))
+#define topology_core_cpumask(cpu)     (cpu_cpu_mask(cpu))
 #define topology_core_id(cpu)          (cpu_to_core_id(cpu))
 
 #endif
index 20a3537..604d705 100644 (file)
@@ -151,52 +151,16 @@ static inline int __access_ok(unsigned long addr, unsigned long size,
 
 extern long __put_user_bad(void);
 
-/*
- * We don't tell gcc that we are accessing memory, but this is OK
- * because we do not write to any memory gcc knows about, so there
- * are no aliasing issues.
- */
-#define __put_user_asm(x, addr, err, op)                       \
-       __asm__ __volatile__(                                   \
-               "1:     " op " %1,0(%2) # put_user\n"           \
-               "2:\n"                                          \
-               ".section .fixup,\"ax\"\n"                      \
-               "3:     li %0,%3\n"                             \
-               "       b 2b\n"                                 \
-               ".previous\n"                                   \
-               EX_TABLE(1b, 3b)                                \
-               : "=r" (err)                                    \
-               : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err))
-
-#ifdef __powerpc64__
-#define __put_user_asm2(x, ptr, retval)                                \
-         __put_user_asm(x, ptr, retval, "std")
-#else /* __powerpc64__ */
-#define __put_user_asm2(x, addr, err)                          \
-       __asm__ __volatile__(                                   \
-               "1:     stw %1,0(%2)\n"                         \
-               "2:     stw %1+1,4(%2)\n"                       \
-               "3:\n"                                          \
-               ".section .fixup,\"ax\"\n"                      \
-               "4:     li %0,%3\n"                             \
-               "       b 3b\n"                                 \
-               ".previous\n"                                   \
-               EX_TABLE(1b, 4b)                                \
-               EX_TABLE(2b, 4b)                                \
-               : "=r" (err)                                    \
-               : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err))
-#endif /* __powerpc64__ */
-
 #define __put_user_size_allowed(x, ptr, size, retval)          \
 do {                                                           \
+       __label__ __pu_failed;                                  \
+                                                               \
        retval = 0;                                             \
-       switch (size) {                                         \
-         case 1: __put_user_asm(x, ptr, retval, "stb"); break; \
-         case 2: __put_user_asm(x, ptr, retval, "sth"); break; \
-         case 4: __put_user_asm(x, ptr, retval, "stw"); break; \
-         case 8: __put_user_asm2(x, ptr, retval); break;       \
-         default: __put_user_bad();                            \
-       }                                                       \
+       __put_user_size_goto(x, ptr, size, __pu_failed);        \
+       break;                                                  \
+                                                               \
+__pu_failed:                                                   \
+       retval = -EFAULT;                                       \
 } while (0)
 
 #define __put_user_size(x, ptr, size, retval)                  \
@@ -249,12 +213,17 @@ do {                                                              \
 })
 
 
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
 #define __put_user_asm_goto(x, addr, label, op)                        \
        asm volatile goto(                                      \
                "1:     " op "%U1%X1 %0,%1      # put_user\n"   \
                EX_TABLE(1b, %l2)                               \
                :                                               \
-               : "r" (x), "m" (*addr)                          \
+               : "r" (x), "m<>" (*addr)                                \
                :                                               \
                : label)
 
@@ -316,7 +285,7 @@ extern long __get_user_bad(void);
 
 #define __get_user_asm(x, addr, err, op)               \
        __asm__ __volatile__(                           \
-               "1:     "op" %1,0(%2)   # get_user\n"   \
+               "1:     "op"%U2%X2 %1, %2       # get_user\n"   \
                "2:\n"                                  \
                ".section .fixup,\"ax\"\n"              \
                "3:     li %0,%3\n"                     \
@@ -325,7 +294,7 @@ extern long __get_user_bad(void);
                ".previous\n"                           \
                EX_TABLE(1b, 3b)                        \
                : "=r" (err), "=r" (x)                  \
-               : "b" (addr), "i" (-EFAULT), "0" (err))
+               : "m<>" (*addr), "i" (-EFAULT), "0" (err))
 
 #ifdef __powerpc64__
 #define __get_user_asm2(x, addr, err)                  \
@@ -333,8 +302,8 @@ extern long __get_user_bad(void);
 #else /* __powerpc64__ */
 #define __get_user_asm2(x, addr, err)                  \
        __asm__ __volatile__(                           \
-               "1:     lwz %1,0(%2)\n"                 \
-               "2:     lwz %1+1,4(%2)\n"               \
+               "1:     lwz%X2 %1, %2\n"                        \
+               "2:     lwz%X2 %L1, %L2\n"              \
                "3:\n"                                  \
                ".section .fixup,\"ax\"\n"              \
                "4:     li %0,%3\n"                     \
@@ -345,7 +314,7 @@ extern long __get_user_bad(void);
                EX_TABLE(1b, 4b)                        \
                EX_TABLE(2b, 4b)                        \
                : "=r" (err), "=&r" (x)                 \
-               : "b" (addr), "i" (-EFAULT), "0" (err))
+               : "m" (*addr), "i" (-EFAULT), "0" (err))
 #endif /* __powerpc64__ */
 
 #define __get_user_size_allowed(x, ptr, size, retval)          \
@@ -355,10 +324,10 @@ do {                                                              \
        if (size > sizeof(x))                                   \
                (x) = __get_user_bad();                         \
        switch (size) {                                         \
-       case 1: __get_user_asm(x, ptr, retval, "lbz"); break;   \
-       case 2: __get_user_asm(x, ptr, retval, "lhz"); break;   \
-       case 4: __get_user_asm(x, ptr, retval, "lwz"); break;   \
-       case 8: __get_user_asm2(x, ptr, retval);  break;        \
+       case 1: __get_user_asm(x, (u8 __user *)ptr, retval, "lbz"); break;      \
+       case 2: __get_user_asm(x, (u16 __user *)ptr, retval, "lhz"); break;     \
+       case 4: __get_user_asm(x, (u32 __user *)ptr, retval, "lwz"); break;     \
+       case 8: __get_user_asm2(x, (u64 __user *)ptr, retval);  break;  \
        default: (x) = __get_user_bad();                        \
        }                                                       \
 } while (0)
index f5f1ccc..7004cfe 100644 (file)
@@ -222,6 +222,7 @@ struct ppc_debug_info {
 #define PPC_DEBUG_FEATURE_DATA_BP_RANGE                0x0000000000000004
 #define PPC_DEBUG_FEATURE_DATA_BP_MASK         0x0000000000000008
 #define PPC_DEBUG_FEATURE_DATA_BP_DAWR         0x0000000000000010
+#define PPC_DEBUG_FEATURE_DATA_BP_ARCH_31      0x0000000000000020
 
 #ifndef __ASSEMBLY__
 
index cbf41fb..bf0bf1b 100644 (file)
@@ -45,7 +45,8 @@ obj-y                         := cputable.o syscalls.o \
                                   signal.o sysfs.o cacheinfo.o time.o \
                                   prom.o traps.o setup-common.o \
                                   udbg.o misc.o io.o misc_$(BITS).o \
-                                  of_platform.o prom_parse.o firmware.o
+                                  of_platform.o prom_parse.o firmware.o \
+                                  hw_breakpoint_constraints.o
 obj-y                          += ptrace/
 obj-$(CONFIG_PPC64)            += setup_64.o \
                                   paca.o nvram_64.o note.o syscall_64.o
@@ -94,7 +95,8 @@ obj-$(CONFIG_PPC_FSL_BOOK3E)  += cpu_setup_fsl_booke.o
 obj-$(CONFIG_PPC_DOORBELL)     += dbell.o
 obj-$(CONFIG_JUMP_LABEL)       += jump_label.o
 
-extra-y                                := head_$(BITS).o
+extra-$(CONFIG_PPC64)          := head_64.o
+extra-$(CONFIG_PPC_BOOK3S_32)  := head_book3s_32.o
 extra-$(CONFIG_40x)            := head_40x.o
 extra-$(CONFIG_44x)            := head_44x.o
 extra-$(CONFIG_FSL_BOOKE)      := head_fsl_booke.o
index 8711c21..c2722ff 100644 (file)
@@ -176,6 +176,7 @@ int main(void)
        OFFSET(THREAD_TM_TAR, thread_struct, tm_tar);
        OFFSET(THREAD_TM_PPR, thread_struct, tm_ppr);
        OFFSET(THREAD_TM_DSCR, thread_struct, tm_dscr);
+       OFFSET(THREAD_TM_AMR, thread_struct, tm_amr);
        OFFSET(PT_CKPT_REGS, thread_struct, ckpt_regs);
        OFFSET(THREAD_CKVRSTATE, thread_struct, ckvr_state.vr);
        OFFSET(THREAD_CKVRSAVE, thread_struct, ckvrsave);
index 02300ed..c22a8e0 100644 (file)
@@ -95,19 +95,10 @@ void __init btext_prepare_BAT(void)
                boot_text_mapped = 0;
                return;
        }
-       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
-               /* 603, 604, G3, G4, ... */
-               lowbits = addr & ~0xFF000000UL;
-               addr &= 0xFF000000UL;
-               disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
-               disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); 
-       } else {
-               /* 601 */
-               lowbits = addr & ~0xFF800000UL;
-               addr &= 0xFF800000UL;
-               disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
-               disp_BAT[1] = addr | BL_8M | 0x40;
-       }
+       lowbits = addr & ~0xFF000000UL;
+       addr &= 0xFF000000UL;
+       disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
+       disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
        logicalDisplayBase = (void *) (vaddr + lowbits);
 }
 #endif
index 2aa89c6..492c0b3 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/oprofile_impl.h>
 #include <asm/cputable.h>
 #include <asm/prom.h>          /* for PTRRELOC on ARCH=ppc */
+#include <asm/mce.h>
 #include <asm/mmu.h>
 #include <asm/setup.h>
 
@@ -608,21 +609,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
 #ifdef CONFIG_PPC32
-#ifdef CONFIG_PPC_BOOK3S_601
-       {       /* 601 */
-               .pvr_mask               = 0xffff0000,
-               .pvr_value              = 0x00010000,
-               .cpu_name               = "601",
-               .cpu_features           = CPU_FTRS_PPC601,
-               .cpu_user_features      = COMMON_USER | PPC_FEATURE_601_INSTR |
-                       PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB,
-               .mmu_features           = MMU_FTR_HPTE_TABLE,
-               .icache_bsize           = 32,
-               .dcache_bsize           = 32,
-               .machine_check          = machine_check_generic,
-               .platform               = "ppc601",
-       },
-#endif /* CONFIG_PPC_BOOK3S_601 */
 #ifdef CONFIG_PPC_BOOK3S_6xx
        {       /* 603 */
                .pvr_mask               = 0xffff0000,
index f204ad7..1098863 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/cputable.h>
 #include <asm/dt_cpu_ftrs.h>
+#include <asm/mce.h>
 #include <asm/mmu.h>
 #include <asm/oprofile_impl.h>
 #include <asm/prom.h>
index 9468238..0e160df 100644 (file)
@@ -466,7 +466,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
                return 0;
        }
 
-       if (!pe->addr && !pe->config_addr) {
+       if (!pe->addr) {
                eeh_stats.no_cfg_addr++;
                return 0;
        }
@@ -929,56 +929,6 @@ void eeh_save_bars(struct eeh_dev *edev)
                edev->config_space[1] |= PCI_COMMAND_MASTER;
 }
 
-/**
- * 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_warn("%s: Invalid EEH ops name for %p\n",
-                       __func__, ops);
-               return -EINVAL;
-       }
-
-       if (eeh_ops && eeh_ops != ops) {
-               pr_warn("%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_warn("%s: Invalid EEH ops name\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       if (eeh_ops && !strcmp(eeh_ops->name, name)) {
-               eeh_ops = NULL;
-               return 0;
-       }
-
-       return -EEXIST;
-}
-
 static int eeh_reboot_notifier(struct notifier_block *nb,
                               unsigned long action, void *unused)
 {
@@ -990,54 +940,6 @@ static struct notifier_block eeh_reboot_nb = {
        .notifier_call = eeh_reboot_notifier,
 };
 
-/**
- * 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
- * check.  If a user turns off EEH for a particular adapter they are really
- * telling Linux to ignore errors.  Some hardware (e.g. POWER5) won't
- * grant access to a slot if EEH isn't enabled, and so we always enable
- * EEH for all slots/all devices.
- *
- * The eeh-force-off option disables EEH checking globally, for all slots.
- * Even if force-off is set, the EEH hardware is still enabled, so that
- * newer systems can boot.
- */
-static int eeh_init(void)
-{
-       struct pci_controller *hose, *tmp;
-       int ret = 0;
-
-       /* Register reboot notifier */
-       ret = register_reboot_notifier(&eeh_reboot_nb);
-       if (ret) {
-               pr_warn("%s: Failed to register notifier (%d)\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       /* call platform initialization function */
-       if (!eeh_ops) {
-               pr_warn("%s: Platform EEH operation not found\n",
-                       __func__);
-               return -EEXIST;
-       } else if ((ret = eeh_ops->init()))
-               return ret;
-
-       /* Initialize PHB PEs */
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
-               eeh_phb_pe_create(hose);
-
-       eeh_addr_cache_init();
-
-       /* Initialize EEH event */
-       return eeh_event_init();
-}
-
-core_initcall_sync(eeh_init);
-
 static int eeh_device_notifier(struct notifier_block *nb,
                               unsigned long action, void *data)
 {
@@ -1062,12 +964,47 @@ static struct notifier_block eeh_device_nb = {
        .notifier_call = eeh_device_notifier,
 };
 
-static __init int eeh_set_bus_notifier(void)
+/**
+ * eeh_init - System wide EEH initialization
+ *
+ * It's the platform's job to call this from an arch_initcall().
+ */
+int eeh_init(struct eeh_ops *ops)
 {
-       bus_register_notifier(&pci_bus_type, &eeh_device_nb);
-       return 0;
+       struct pci_controller *hose, *tmp;
+       int ret = 0;
+
+       /* the platform should only initialise EEH once */
+       if (WARN_ON(eeh_ops))
+               return -EEXIST;
+       if (WARN_ON(!ops))
+               return -ENOENT;
+       eeh_ops = ops;
+
+       /* Register reboot notifier */
+       ret = register_reboot_notifier(&eeh_reboot_nb);
+       if (ret) {
+               pr_warn("%s: Failed to register reboot notifier (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = bus_register_notifier(&pci_bus_type, &eeh_device_nb);
+       if (ret) {
+               pr_warn("%s: Failed to register bus notifier (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       /* Initialize PHB PEs */
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+               eeh_phb_pe_create(hose);
+
+       eeh_addr_cache_init();
+
+       /* Initialize EEH event */
+       return eeh_event_init();
 }
-arch_initcall(eeh_set_bus_notifier);
 
 /**
  * eeh_probe_device() - Perform EEH initialization for the indicated pci device
@@ -1720,7 +1657,7 @@ static ssize_t eeh_force_recover_write(struct file *filp,
                return -ENODEV;
 
        /* Retrieve PE */
-       pe = eeh_pe_get(hose, pe_no, 0);
+       pe = eeh_pe_get(hose, pe_no);
        if (!pe)
                return -ENODEV;
 
index d2aaaa7..845e024 100644 (file)
@@ -251,43 +251,21 @@ void eeh_pe_dev_traverse(struct eeh_pe *root,
 
 /**
  * __eeh_pe_get - Check the PE address
- * @data: EEH PE
- * @flag: EEH device
  *
  * For one particular PE, it can be identified by PE address
  * or tranditional BDF address. BDF address is composed of
  * Bus/Device/Function number. The extra data referred by flag
  * indicates which type of address should be used.
  */
-struct eeh_pe_get_flag {
-       int pe_no;
-       int config_addr;
-};
-
 static void *__eeh_pe_get(struct eeh_pe *pe, void *flag)
 {
-       struct eeh_pe_get_flag *tmp = (struct eeh_pe_get_flag *) flag;
+       int *target_pe = flag;
 
-       /* Unexpected PHB PE */
+       /* PHB PEs are special and should be ignored */
        if (pe->type & EEH_PE_PHB)
                return NULL;
 
-       /*
-        * We prefer PE address. For most cases, we should
-        * have non-zero PE address
-        */
-       if (eeh_has_flag(EEH_VALID_PE_ZERO)) {
-               if (tmp->pe_no == pe->addr)
-                       return pe;
-       } else {
-               if (tmp->pe_no &&
-                   (tmp->pe_no == pe->addr))
-                       return pe;
-       }
-
-       /* Try BDF address */
-       if (tmp->config_addr &&
-          (tmp->config_addr == pe->config_addr))
+       if (*target_pe == pe->addr)
                return pe;
 
        return NULL;
@@ -297,7 +275,6 @@ static void *__eeh_pe_get(struct eeh_pe *pe, void *flag)
  * eeh_pe_get - Search PE based on the given address
  * @phb: PCI controller
  * @pe_no: PE number
- * @config_addr: Config address
  *
  * Search the corresponding PE based on the specified address which
  * is included in the eeh device. The function is used to check if
@@ -306,16 +283,11 @@ static void *__eeh_pe_get(struct eeh_pe *pe, void *flag)
  * which is composed of PCI bus/device/function number, or unified
  * PE address.
  */
-struct eeh_pe *eeh_pe_get(struct pci_controller *phb,
-               int pe_no, int config_addr)
+struct eeh_pe *eeh_pe_get(struct pci_controller *phb, int pe_no)
 {
        struct eeh_pe *root = eeh_phb_pe_get(phb);
-       struct eeh_pe_get_flag tmp = { pe_no, config_addr };
-       struct eeh_pe *pe;
 
-       pe = eeh_pe_traverse(root, __eeh_pe_get, &tmp);
-
-       return pe;
+       return eeh_pe_traverse(root, __eeh_pe_get, &pe_no);
 }
 
 /**
@@ -336,19 +308,13 @@ int eeh_pe_tree_insert(struct eeh_dev *edev, struct eeh_pe *new_pe_parent)
        struct pci_controller *hose = edev->controller;
        struct eeh_pe *pe, *parent;
 
-       /* Check if the PE number is valid */
-       if (!eeh_has_flag(EEH_VALID_PE_ZERO) && !edev->pe_config_addr) {
-               eeh_edev_err(edev, "PE#0 is invalid for this PHB!\n");
-               return -EINVAL;
-       }
-
        /*
         * Search the PE has been existing or not according
         * to the PE address. If that has been existing, the
         * PE should be composed of PCI bus and its subordinate
         * components.
         */
-       pe = eeh_pe_get(hose, edev->pe_config_addr, edev->bdfn);
+       pe = eeh_pe_get(hose, edev->pe_config_addr);
        if (pe) {
                if (pe->type & EEH_PE_INVALID) {
                        list_add_tail(&edev->entry, &pe->edevs);
@@ -388,8 +354,8 @@ int eeh_pe_tree_insert(struct eeh_dev *edev, struct eeh_pe *new_pe_parent)
                pr_err("%s: out of memory!\n", __func__);
                return -ENOMEM;
        }
-       pe->addr        = edev->pe_config_addr;
-       pe->config_addr = edev->bdfn;
+
+       pe->addr = edev->pe_config_addr;
 
        /*
         * Put the new EEH PE into hierarchy tree. If the parent
index f4d0af8..8cdc8bc 100644 (file)
@@ -234,7 +234,6 @@ transfer_to_handler_cont:
        mtspr   SPRN_SRR0,r11
        mtspr   SPRN_SRR1,r10
        mtlr    r9
-       SYNC
        RFI                             /* jump to handler, enable MMU */
 
 #if defined (CONFIG_PPC_BOOK3S_32) || defined(CONFIG_E500)
@@ -264,7 +263,6 @@ _ASM_NOKPROBE_SYMBOL(transfer_to_handler_cont)
        LOAD_REG_IMMEDIATE(r0, MSR_KERNEL)
        mtspr   SPRN_SRR0,r12
        mtspr   SPRN_SRR1,r0
-       SYNC
        RFI
 
 reenable_mmu:
@@ -323,7 +321,6 @@ stack_ovf:
 #endif
        mtspr   SPRN_SRR0,r9
        mtspr   SPRN_SRR1,r10
-       SYNC
        RFI
 _ASM_NOKPROBE_SYMBOL(stack_ovf)
 #endif
@@ -411,7 +408,6 @@ ret_from_syscall:
        /* disable interrupts so current_thread_info()->flags can't change */
        LOAD_REG_IMMEDIATE(r10,MSR_KERNEL)      /* doesn't include MSR_EE */
        /* Note: We don't bother telling lockdep about it */
-       SYNC
        mtmsr   r10
        lwz     r9,TI_FLAGS(r2)
        li      r8,-MAX_ERRNO
@@ -474,7 +470,6 @@ syscall_exit_finish:
 #endif
        mtspr   SPRN_SRR0,r7
        mtspr   SPRN_SRR1,r8
-       SYNC
        RFI
 _ASM_NOKPROBE_SYMBOL(syscall_exit_finish)
 #ifdef CONFIG_44x
@@ -567,7 +562,6 @@ syscall_exit_work:
         * lockdep as we are supposed to have IRQs on at this point
         */
        ori     r10,r10,MSR_EE
-       SYNC
        mtmsr   r10
 
        /* Save NVGPRS if they're not saved already */
@@ -606,7 +600,6 @@ ret_from_kernel_syscall:
 #endif
        mtspr   SPRN_SRR0, r9
        mtspr   SPRN_SRR1, r10
-       SYNC
        RFI
 _ASM_NOKPROBE_SYMBOL(ret_from_kernel_syscall)
 
@@ -810,7 +803,6 @@ fast_exception_return:
        REST_GPR(9, r11)
        REST_GPR(12, r11)
        lwz     r11,GPR11(r11)
-       SYNC
        RFI
 _ASM_NOKPROBE_SYMBOL(fast_exception_return)
 
@@ -819,19 +811,11 @@ _ASM_NOKPROBE_SYMBOL(fast_exception_return)
 1:     lis     r3,exc_exit_restart_end@ha
        addi    r3,r3,exc_exit_restart_end@l
        cmplw   r12,r3
-#ifdef CONFIG_PPC_BOOK3S_601
-       bge     2b
-#else
        bge     3f
-#endif
        lis     r4,exc_exit_restart@ha
        addi    r4,r4,exc_exit_restart@l
        cmplw   r12,r4
-#ifdef CONFIG_PPC_BOOK3S_601
-       blt     2b
-#else
        blt     3f
-#endif
        lis     r3,fee_restarts@ha
        tophys(r3,r3)
        lwz     r5,fee_restarts@l(r3)
@@ -848,7 +832,6 @@ fee_restarts:
 
 /* aargh, a nonrecoverable interrupt, panic */
 /* aargh, we don't know which trap this is */
-/* but the 601 doesn't implement the RI bit, so assume it's OK */
 3:
        li      r10,-1
        stw     r10,_TRAP(r11)
@@ -872,7 +855,6 @@ ret_from_except:
         * from the interrupt. */
        /* Note: We don't bother telling lockdep about it */
        LOAD_REG_IMMEDIATE(r10,MSR_KERNEL)
-       SYNC                    /* Some chip revs have problems here... */
        mtmsr   r10             /* disable interrupts */
 
        lwz     r3,_MSR(r1)     /* Returning to user mode? */
@@ -1035,7 +1017,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
         * exc_exit_restart below.  -- paulus
         */
        LOAD_REG_IMMEDIATE(r10,MSR_KERNEL & ~MSR_RI)
-       SYNC
        mtmsr   r10             /* clear the RI bit */
        .globl exc_exit_restart
 exc_exit_restart:
@@ -1046,7 +1027,6 @@ exc_exit_restart:
        lwz     r1,GPR1(r1)
        .globl exc_exit_restart_end
 exc_exit_restart_end:
-       SYNC
        RFI
 _ASM_NOKPROBE_SYMBOL(exc_exit_restart)
 _ASM_NOKPROBE_SYMBOL(exc_exit_restart_end)
@@ -1274,7 +1254,6 @@ do_resched:                       /* r10 contains MSR_KERNEL here */
        mfmsr   r10
 #endif
        ori     r10,r10,MSR_EE
-       SYNC
        mtmsr   r10             /* hard-enable interrupts */
        bl      schedule
 recheck:
@@ -1283,7 +1262,6 @@ recheck:
         * TI_FLAGS aren't advertised.
         */
        LOAD_REG_IMMEDIATE(r10,MSR_KERNEL)
-       SYNC
        mtmsr   r10             /* disable interrupts */
        lwz     r9,TI_FLAGS(r2)
        andi.   r0,r9,_TIF_NEED_RESCHED
@@ -1292,7 +1270,6 @@ recheck:
        beq     restore_user
 do_user_signal:                        /* r10 contains MSR_KERNEL here */
        ori     r10,r10,MSR_EE
-       SYNC
        mtmsr   r10             /* hard-enable interrupts */
        /* save r13-r31 in the exception frame, if not already done */
        lwz     r3,_TRAP(r1)
@@ -1316,19 +1293,11 @@ nonrecoverable:
        lis     r10,exc_exit_restart_end@ha
        addi    r10,r10,exc_exit_restart_end@l
        cmplw   r12,r10
-#ifdef CONFIG_PPC_BOOK3S_601
-       bgelr
-#else
        bge     3f
-#endif
        lis     r11,exc_exit_restart@ha
        addi    r11,r11,exc_exit_restart@l
        cmplw   r12,r11
-#ifdef CONFIG_PPC_BOOK3S_601
-       bltlr
-#else
        blt     3f
-#endif
        lis     r10,ee_restarts@ha
        lwz     r12,ee_restarts@l(r10)
        addi    r12,r12,1
@@ -1336,7 +1305,6 @@ nonrecoverable:
        mr      r12,r11         /* restart at exc_exit_restart */
        blr
 3:     /* OK, we can't recover, kill this process */
-       /* but the 601 doesn't implement the RI bit, so assume it's OK */
        lwz     r3,_TRAP(r1)
        andi.   r0,r3,1
        beq     5f
@@ -1382,8 +1350,7 @@ _GLOBAL(enter_rtas)
        mfmsr   r9
        stw     r9,8(r1)
        LOAD_REG_IMMEDIATE(r0,MSR_KERNEL)
-       SYNC                    /* disable interrupts so SRR0/1 */
-       mtmsr   r0              /* don't get trashed */
+       mtmsr   r0      /* disable interrupts so SRR0/1 don't get trashed */
        li      r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
        mtlr    r6
        stw     r7, THREAD + RTAS_SP(r2)
index 733e40e..2f38461 100644 (file)
@@ -430,7 +430,11 @@ _ASM_NOKPROBE_SYMBOL(save_nvgprs);
 
 #define FLUSH_COUNT_CACHE      \
 1:     nop;                    \
-       patch_site 1b, patch__call_flush_branch_caches
+       patch_site 1b, patch__call_flush_branch_caches1; \
+1:     nop;                    \
+       patch_site 1b, patch__call_flush_branch_caches2; \
+1:     nop;                    \
+       patch_site 1b, patch__call_flush_branch_caches3
 
 .macro nops number
        .rept \number
@@ -512,7 +516,7 @@ _GLOBAL(_switch)
 
        kuap_check_amr r9, r10
 
-       FLUSH_COUNT_CACHE
+       FLUSH_COUNT_CACHE       /* Clobbers r9, ctr */
 
        /*
         * On SMP kernels, care must be taken because a task may be
index d9ed794..f579ce4 100644 (file)
@@ -988,7 +988,6 @@ kernel_dbg_exc:
 .endm
 
 masked_interrupt_book3e_0x500:
-       // XXX When adding support for EPR, use PACA_IRQ_EE_EDGE
        masked_interrupt_book3e PACA_IRQ_EE 1
 
 masked_interrupt_book3e_0x900:
@@ -1303,16 +1302,6 @@ fast_exception_return:
        addi    r3,r1,STACK_FRAME_OVERHEAD;
        bl      do_IRQ
        b       ret_from_except
-1:     cmpwi   cr0,r3,0xf00
-       bne     1f
-       addi    r3,r1,STACK_FRAME_OVERHEAD;
-       bl      performance_monitor_exception
-       b       ret_from_except
-1:     cmpwi   cr0,r3,0xe60
-       bne     1f
-       addi    r3,r1,STACK_FRAME_OVERHEAD;
-       bl      handle_hmi_exception
-       b       ret_from_except
 1:     cmpwi   cr0,r3,0x900
        bne     1f
        addi    r3,r1,STACK_FRAME_OVERHEAD;
index 5cdf416..8482739 100644 (file)
@@ -754,10 +754,8 @@ u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
 
 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. */
index 4ae39db..3ff9a8f 100644 (file)
@@ -87,7 +87,6 @@ BEGIN_FTR_SECTION
        oris    r5,r5,MSR_VSX@h
 END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
-       SYNC
        MTMSRD(r5)                      /* enable use of fpu now */
        isync
        /* enable use of FP after return */
@@ -134,18 +133,3 @@ _GLOBAL(save_fpu)
        mffs    fr0
        stfd    fr0,FPSTATE_FPSCR(r6)
        blr
-
-/*
- * These are used in the alignment trap handler when emulating
- * single-precision loads and stores.
- */
-
-_GLOBAL(cvt_fd)
-       lfs     0,0(r3)
-       stfd    0,0(r4)
-       blr
-
-_GLOBAL(cvt_df)
-       lfd     0,0(r3)
-       stfs    0,0(r4)
-       blr
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
deleted file mode 100644 (file)
index f3ab94d..0000000
+++ /dev/null
@@ -1,1422 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *  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.
- *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC platform, including trap and interrupt dispatch.
- *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
- */
-
-#include <linux/init.h>
-#include <linux/pgtable.h>
-#include <asm/reg.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/cputable.h>
-#include <asm/cache.h>
-#include <asm/thread_info.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/ptrace.h>
-#include <asm/bug.h>
-#include <asm/kvm_book3s_asm.h>
-#include <asm/export.h>
-#include <asm/feature-fixups.h>
-
-#include "head_32.h"
-
-/* 601 only have IBAT */
-#ifdef CONFIG_PPC_BOOK3S_601
-#define LOAD_BAT(n, reg, RA, RB)       \
-       li      RA,0;                   \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       lwz     RA,(n*16)+0(reg);       \
-       lwz     RB,(n*16)+4(reg);       \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       mtspr   SPRN_IBAT##n##L,RB
-#else
-#define LOAD_BAT(n, reg, RA, RB)       \
-       /* see the comment for clear_bats() -- Cort */ \
-       li      RA,0;                   \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       mtspr   SPRN_DBAT##n##U,RA;     \
-       lwz     RA,(n*16)+0(reg);       \
-       lwz     RB,(n*16)+4(reg);       \
-       mtspr   SPRN_IBAT##n##U,RA;     \
-       mtspr   SPRN_IBAT##n##L,RB;     \
-       lwz     RA,(n*16)+8(reg);       \
-       lwz     RB,(n*16)+12(reg);      \
-       mtspr   SPRN_DBAT##n##U,RA;     \
-       mtspr   SPRN_DBAT##n##L,RB
-#endif
-
-       __HEAD
-       .stabs  "arch/powerpc/kernel/",N_SO,0,0,0f
-       .stabs  "head_32.S",N_SO,0,0,0f
-0:
-_ENTRY(_stext);
-
-/*
- * _start is defined this way because the XCOFF loader in the OpenFirmware
- * on the powermac expects the entry point to be a procedure descriptor.
- */
-_ENTRY(_start);
-       /*
-        * These are here for legacy reasons, the kernel used to
-        * need to look like a coff function entry for the pmac
-        * but we're always started by some kind of bootloader now.
-        *  -- Cort
-        */
-       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
-       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
-       nop
-
-/* PMAC
- * Enter here with the kernel text, data and bss loaded starting at
- * 0, running with virtual == physical mapping.
- * r5 points to the prom entry point (the client interface handler
- * address).  Address translation is turned on, with the prom
- * managing the hash table.  Interrupts are disabled.  The stack
- * pointer (r1) points to just below the end of the half-meg region
- * from 0x380000 - 0x400000, which is mapped in already.
- *
- * If we are booted from MacOS via BootX, we enter with the kernel
- * image loaded somewhere, and the following values in registers:
- *  r3: 'BooX' (0x426f6f58)
- *  r4: virtual address of boot_infos_t
- *  r5: 0
- *
- * PREP
- * This is jumped to on prep systems right after the kernel is relocated
- * to its proper place in memory by the boot loader.  The expected layout
- * of the regs is:
- *   r3: ptr to residual data
- *   r4: initrd_start or if no initrd then 0
- *   r5: initrd_end - unused if r4 is 0
- *   r6: Start of command line string
- *   r7: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort
- */
-
-       .globl  __start
-__start:
-/*
- * We have to do any OF calls before we map ourselves to KERNELBASE,
- * because OF may have I/O devices mapped into that area
- * (particularly on CHRP).
- */
-       cmpwi   0,r5,0
-       beq     1f
-
-#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
-       /* find out where we are now */
-       bcl     20,31,$+4
-0:     mflr    r8                      /* r8 = runtime addr here */
-       addis   r8,r8,(_stext - 0b)@ha
-       addi    r8,r8,(_stext - 0b)@l   /* current runtime base addr */
-       bl      prom_init
-#endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */
-
-       /* We never return. We also hit that trap if trying to boot
-        * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
-       trap
-
-/*
- * Check for BootX signature when supporting PowerMac and branch to
- * appropriate trampoline if it's present
- */
-#ifdef CONFIG_PPC_PMAC
-1:     lis     r31,0x426f
-       ori     r31,r31,0x6f58
-       cmpw    0,r3,r31
-       bne     1f
-       bl      bootx_init
-       trap
-#endif /* CONFIG_PPC_PMAC */
-
-1:     mr      r31,r3                  /* save device tree ptr */
-       li      r24,0                   /* cpu # */
-
-/*
- * early_init() does the early machine identification and does
- * the necessary low-level setup and clears the BSS
- *  -- Cort <cort@fsmlabs.com>
- */
-       bl      early_init
-
-/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
- * the physical address we are running at, returned by early_init()
- */
-       bl      mmu_off
-__after_mmu_off:
-       bl      clear_bats
-       bl      flush_tlbs
-
-       bl      initial_bats
-       bl      load_segment_registers
-#ifdef CONFIG_KASAN
-       bl      early_hash_table
-#endif
-#if defined(CONFIG_BOOTX_TEXT)
-       bl      setup_disp_bat
-#endif
-#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
-       bl      setup_cpm_bat
-#endif
-#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
-       bl      setup_usbgecko_bat
-#endif
-
-/*
- * Call setup_cpu for CPU 0 and initialize 6xx Idle
- */
-       bl      reloc_offset
-       li      r24,0                   /* cpu# */
-       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
-#ifdef CONFIG_PPC_BOOK3S_32
-       bl      reloc_offset
-       bl      init_idle_6xx
-#endif /* CONFIG_PPC_BOOK3S_32 */
-
-
-/*
- * We need to run with _start at physical address 0.
- * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
- * the exception vectors at 0 (and therefore this copy
- * overwrites OF's exception vectors with our own).
- * The MMU is off at this point.
- */
-       bl      reloc_offset
-       mr      r26,r3
-       addis   r4,r3,KERNELBASE@h      /* current address of _start */
-       lis     r5,PHYSICAL_START@h
-       cmplw   0,r4,r5                 /* already running at PHYSICAL_START? */
-       bne     relocate_kernel
-/*
- * we now have the 1st 16M of ram mapped with the bats.
- * prep needs the mmu to be turned on here, but pmac already has it on.
- * this shouldn't bother the pmac since it just gets turned on again
- * as we jump to our code at KERNELBASE. -- Cort
- * Actually no, pmac doesn't have it on any more. BootX enters with MMU
- * off, and in other cases, we now turn it off before changing BATs above.
- */
-turn_on_mmu:
-       mfmsr   r0
-       ori     r0,r0,MSR_DR|MSR_IR|MSR_RI
-       mtspr   SPRN_SRR1,r0
-       lis     r0,start_here@h
-       ori     r0,r0,start_here@l
-       mtspr   SPRN_SRR0,r0
-       SYNC
-       RFI                             /* enables MMU */
-
-/*
- * We need __secondary_hold as a place to hold the other cpus on
- * an SMP machine, even when we are running a UP kernel.
- */
-       . = 0xc0                        /* for prep bootloader */
-       li      r3,1                    /* MTX only has 1 cpu */
-       .globl  __secondary_hold
-__secondary_hold:
-       /* tell the master we're here */
-       stw     r3,__secondary_hold_acknowledge@l(0)
-#ifdef CONFIG_SMP
-100:   lwz     r4,0(0)
-       /* wait until we're told to start */
-       cmpw    0,r4,r3
-       bne     100b
-       /* our cpu # was at addr 0 - go */
-       mr      r24,r3                  /* cpu # */
-       b       __secondary_start
-#else
-       b       .
-#endif /* CONFIG_SMP */
-
-       .globl  __secondary_hold_spinloop
-__secondary_hold_spinloop:
-       .long   0
-       .globl  __secondary_hold_acknowledge
-__secondary_hold_acknowledge:
-       .long   -1
-
-/* System reset */
-/* core99 pmac starts the seconary here by changing the vector, and
-   putting it back to what it was (unknown_exception) when done.  */
-       EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
-
-/* Machine check */
-/*
- * On CHRP, this is complicated by the fact that we could get a
- * machine check inside RTAS, and we have no guarantee that certain
- * critical registers will have the values we expect.  The set of
- * registers that might have bad values includes all the GPRs
- * and all the BATs.  We indicate that we are in RTAS by putting
- * a non-zero value, the address of the exception frame to use,
- * in thread.rtas_sp.  The machine check handler checks thread.rtas_sp
- * and uses its value if it is non-zero.
- * (Other exception handlers assume that r1 is a valid kernel stack
- * pointer when we take an exception from supervisor mode.)
- *     -- paulus.
- */
-       . = 0x200
-       DO_KVM  0x200
-MachineCheck:
-       EXCEPTION_PROLOG_0
-#ifdef CONFIG_VMAP_STACK
-       li      r11, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */
-       mtmsr   r11
-       isync
-#endif
-#ifdef CONFIG_PPC_CHRP
-       mfspr   r11, SPRN_SPRG_THREAD
-       tovirt_vmstack r11, r11
-       lwz     r11, RTAS_SP(r11)
-       cmpwi   cr1, r11, 0
-       bne     cr1, 7f
-#endif /* CONFIG_PPC_CHRP */
-       EXCEPTION_PROLOG_1 for_rtas=1
-7:     EXCEPTION_PROLOG_2
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-#ifdef CONFIG_PPC_CHRP
-#ifdef CONFIG_VMAP_STACK
-       mfspr   r4, SPRN_SPRG_THREAD
-       tovirt(r4, r4)
-       lwz     r4, RTAS_SP(r4)
-       cmpwi   cr1, r4, 0
-#endif
-       beq     cr1, machine_check_tramp
-       twi     31, 0, 0
-#else
-       b       machine_check_tramp
-#endif
-
-/* Data access exception. */
-       . = 0x300
-       DO_KVM  0x300
-DataAccess:
-#ifdef CONFIG_VMAP_STACK
-       mtspr   SPRN_SPRG_SCRATCH0,r10
-       mfspr   r10, SPRN_SPRG_THREAD
-BEGIN_MMU_FTR_SECTION
-       stw     r11, THR11(r10)
-       mfspr   r10, SPRN_DSISR
-       mfcr    r11
-#ifdef CONFIG_PPC_KUAP
-       andis.  r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH | DSISR_PROTFAULT)@h
-#else
-       andis.  r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
-#endif
-       mfspr   r10, SPRN_SPRG_THREAD
-       beq     hash_page_dsi
-.Lhash_page_dsi_cont:
-       mtcr    r11
-       lwz     r11, THR11(r10)
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
-       mtspr   SPRN_SPRG_SCRATCH1,r11
-       mfspr   r11, SPRN_DAR
-       stw     r11, DAR(r10)
-       mfspr   r11, SPRN_DSISR
-       stw     r11, DSISR(r10)
-       mfspr   r11, SPRN_SRR0
-       stw     r11, SRR0(r10)
-       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
-       stw     r11, SRR1(r10)
-       mfcr    r10
-       andi.   r11, r11, MSR_PR
-
-       EXCEPTION_PROLOG_1
-       b       handle_page_fault_tramp_1
-#else  /* CONFIG_VMAP_STACK */
-       EXCEPTION_PROLOG handle_dar_dsisr=1
-       get_and_save_dar_dsisr_on_stack r4, r5, r11
-BEGIN_MMU_FTR_SECTION
-#ifdef CONFIG_PPC_KUAP
-       andis.  r0, r5, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH | DSISR_PROTFAULT)@h
-#else
-       andis.  r0, r5, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
-#endif
-       bne     handle_page_fault_tramp_2       /* if not, try to put a PTE */
-       rlwinm  r3, r5, 32 - 15, 21, 21         /* DSISR_STORE -> _PAGE_RW */
-       bl      hash_page
-       b       handle_page_fault_tramp_1
-FTR_SECTION_ELSE
-       b       handle_page_fault_tramp_2
-ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
-#endif /* CONFIG_VMAP_STACK */
-
-/* Instruction access exception. */
-       . = 0x400
-       DO_KVM  0x400
-InstructionAccess:
-#ifdef CONFIG_VMAP_STACK
-       mtspr   SPRN_SPRG_SCRATCH0,r10
-       mtspr   SPRN_SPRG_SCRATCH1,r11
-       mfspr   r10, SPRN_SPRG_THREAD
-       mfspr   r11, SPRN_SRR0
-       stw     r11, SRR0(r10)
-       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
-       stw     r11, SRR1(r10)
-       mfcr    r10
-BEGIN_MMU_FTR_SECTION
-       andis.  r11, r11, SRR1_ISI_NOPT@h       /* no pte found? */
-       bne     hash_page_isi
-.Lhash_page_isi_cont:
-       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
-       andi.   r11, r11, MSR_PR
-
-       EXCEPTION_PROLOG_1
-       EXCEPTION_PROLOG_2
-#else  /* CONFIG_VMAP_STACK */
-       EXCEPTION_PROLOG
-       andis.  r0,r9,SRR1_ISI_NOPT@h   /* no pte found? */
-       beq     1f                      /* if so, try to put a PTE */
-       li      r3,0                    /* into the hash table */
-       mr      r4,r12                  /* SRR0 is fault address */
-BEGIN_MMU_FTR_SECTION
-       bl      hash_page
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
-#endif /* CONFIG_VMAP_STACK */
-1:     mr      r4,r12
-       andis.  r5,r9,DSISR_SRR1_MATCH_32S@h /* Filter relevant SRR1 bits */
-       stw     r4, _DAR(r11)
-       EXC_XFER_LITE(0x400, handle_page_fault)
-
-/* External interrupt */
-       EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
-
-/* Alignment exception */
-       . = 0x600
-       DO_KVM  0x600
-Alignment:
-       EXCEPTION_PROLOG handle_dar_dsisr=1
-       save_dar_dsisr_on_stack r4, r5, r11
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       b       alignment_exception_tramp
-
-/* Program check exception */
-       EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
-
-/* Floating-point unavailable */
-       . = 0x800
-       DO_KVM  0x800
-FPUnavailable:
-BEGIN_FTR_SECTION
-/*
- * Certain Freescale cores don't have a FPU and treat fp instructions
- * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
- */
-       b       ProgramCheck
-END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
-       EXCEPTION_PROLOG
-       beq     1f
-       bl      load_up_fpu             /* if from user, just load it up */
-       b       fast_exception_return
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_LITE(0x800, kernel_fp_unavailable_exception)
-
-/* Decrementer */
-       EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
-
-       EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_STD)
-
-/* System call */
-       . = 0xc00
-       DO_KVM  0xc00
-SystemCall:
-       SYSCALL_ENTRY   0xc00
-
-/* Single step - not used on 601 */
-       EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)
-       EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_STD)
-
-/*
- * The Altivec unavailable trap is at 0x0f20.  Foo.
- * We effectively remap it to 0x3000.
- * We include an altivec unavailable exception vector even if
- * not configured for Altivec, so that you can't panic a
- * non-altivec kernel running on a machine with altivec just
- * by executing an altivec instruction.
- */
-       . = 0xf00
-       DO_KVM  0xf00
-       b       PerformanceMonitor
-
-       . = 0xf20
-       DO_KVM  0xf20
-       b       AltiVecUnavailable
-
-/*
- * Handle TLB miss for instruction on 603/603e.
- * Note: we get an alternate set of r0 - r3 to use automatically.
- */
-       . = 0x1000
-InstructionTLBMiss:
-/*
- * r0: scratch
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_IMISS
-#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
-       lis     r1, TASK_SIZE@h         /* check if kernel address */
-       cmplw   0,r1,r3
-#endif
-       mfspr   r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-       li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
-#else
-       li      r1,_PAGE_PRESENT | _PAGE_EXEC
-#endif
-#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
-       bgt-    112f
-       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
-       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
-#endif
-112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    InstructionAddressInvalid       /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r0,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r0                /* check access & ~permission */
-       bne-    InstructionAddressInvalid /* return if access not permitted */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwimi  r0,r0,32-2,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r1, r1, 0xe06           /* clear out reserved bits */
-       andc    r1, r0, r1              /* PP = user? 1 : 0 */
-BEGIN_FTR_SECTION
-       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
-END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
-       mtspr   SPRN_RPA,r1
-       tlbli   r3
-       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r3
-       rfi
-InstructionAddressInvalid:
-       mfspr   r3,SPRN_SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-
-       addis   r1,r1,0x2000
-       mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       or      r2,r2,r1
-       mtspr   SPRN_SRR1,r2
-       mfspr   r1,SPRN_IMISS   /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       rlwimi  r2,r2,1,30,30   /* change 1 -> 3 */
-       xor     r1,r1,r2
-       mtspr   SPRN_DAR,r1     /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       mtmsr   r0
-       b       InstructionAccess
-
-/*
- * Handle TLB miss for DATA Load operation on 603/603e
- */
-       . = 0x1100
-DataLoadTLBMiss:
-/*
- * r0: scratch
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_DMISS
-       lis     r1, TASK_SIZE@h         /* check if kernel address */
-       cmplw   0,r1,r3
-       mfspr   r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-       li      r1, _PAGE_PRESENT | _PAGE_ACCESSED
-#else
-       li      r1, _PAGE_PRESENT
-#endif
-       bgt-    112f
-       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
-       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
-112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    DataAddressInvalid      /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r0,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r0                /* check access & ~permission */
-       bne-    DataAddressInvalid      /* return if access not permitted */
-       /*
-        * NOTE! We are assuming this is not an SMP system, otherwise
-        * we would need to update the pte atomically with lwarx/stwcx.
-        */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwinm  r1,r0,32-9,30,30        /* _PAGE_RW -> PP msb */
-       rlwimi  r0,r0,32-1,30,30        /* _PAGE_USER -> PP msb */
-       rlwimi  r0,r0,32-1,31,31        /* _PAGE_USER -> PP lsb */
-       ori     r1,r1,0xe04             /* clear out reserved bits */
-       andc    r1,r0,r1                /* PP = user? rw? 1: 3: 0 */
-BEGIN_FTR_SECTION
-       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
-END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
-       mtspr   SPRN_RPA,r1
-       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r2
-BEGIN_MMU_FTR_SECTION
-       li      r0,1
-       mfspr   r1,SPRN_SPRG_603_LRU
-       rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
-       slw     r0,r0,r2
-       xor     r1,r0,r1
-       srw     r0,r1,r2
-       mtspr   SPRN_SPRG_603_LRU,r1
-       mfspr   r2,SPRN_SRR1
-       rlwimi  r2,r0,31-14,14,14
-       mtspr   SPRN_SRR1,r2
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
-       tlbld   r3
-       rfi
-DataAddressInvalid:
-       mfspr   r3,SPRN_SRR1
-       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
-       addis   r1,r1,0x2000
-       mtspr   SPRN_DSISR,r1
-       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
-       mtspr   SPRN_SRR1,r2
-       mfspr   r1,SPRN_DMISS   /* Get failing address */
-       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
-       beq     20f             /* Jump if big endian */
-       xori    r1,r1,3
-20:    mtspr   SPRN_DAR,r1     /* Set fault address */
-       mfmsr   r0              /* Restore "normal" registers */
-       xoris   r0,r0,MSR_TGPR>>16
-       mtcrf   0x80,r3         /* Restore CR0 */
-       mtmsr   r0
-       b       DataAccess
-
-/*
- * Handle TLB miss for DATA Store on 603/603e
- */
-       . = 0x1200
-DataStoreTLBMiss:
-/*
- * r0: scratch
- * r1: linux style pte ( later becomes ppc hardware pte )
- * r2: ptr to linux-style pte
- * r3: scratch
- */
-       /* Get PTE (linux-style) and check access */
-       mfspr   r3,SPRN_DMISS
-       lis     r1, TASK_SIZE@h         /* check if kernel address */
-       cmplw   0,r1,r3
-       mfspr   r2, SPRN_SPRG_PGDIR
-#ifdef CONFIG_SWAP
-       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
-#else
-       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT
-#endif
-       bgt-    112f
-       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
-       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
-112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
-       lwz     r2,0(r2)                /* get pmd entry */
-       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
-       beq-    DataAddressInvalid      /* return if no mapping */
-       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
-       lwz     r0,0(r2)                /* get linux-style pte */
-       andc.   r1,r1,r0                /* check access & ~permission */
-       bne-    DataAddressInvalid      /* return if access not permitted */
-       /*
-        * NOTE! We are assuming this is not an SMP system, otherwise
-        * we would need to update the pte atomically with lwarx/stwcx.
-        */
-       /* Convert linux-style PTE to low word of PPC-style PTE */
-       rlwimi  r0,r0,32-2,31,31        /* _PAGE_USER -> PP lsb */
-       li      r1,0xe06                /* clear out reserved bits & PP msb */
-       andc    r1,r0,r1                /* PP = user? 1: 0 */
-BEGIN_FTR_SECTION
-       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
-END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
-       mtspr   SPRN_RPA,r1
-       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
-       mtcrf   0x80,r2
-BEGIN_MMU_FTR_SECTION
-       li      r0,1
-       mfspr   r1,SPRN_SPRG_603_LRU
-       rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
-       slw     r0,r0,r2
-       xor     r1,r0,r1
-       srw     r0,r1,r2
-       mtspr   SPRN_SPRG_603_LRU,r1
-       mfspr   r2,SPRN_SRR1
-       rlwimi  r2,r0,31-14,14,14
-       mtspr   SPRN_SRR1,r2
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
-       tlbld   r3
-       rfi
-
-#ifndef CONFIG_ALTIVEC
-#define altivec_assist_exception       unknown_exception
-#endif
-
-#ifndef CONFIG_TAU_INT
-#define TAUException   unknown_exception
-#endif
-
-       EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_STD)
-       EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_STD)
-       EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_STD)
-       EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
-       EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_STD)
-       EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_STD)
-       EXCEPTION(0x2f00, Trap_2f, unknown_exception, EXC_XFER_STD)
-
-       . = 0x3000
-
-machine_check_tramp:
-       EXC_XFER_STD(0x200, machine_check_exception)
-
-alignment_exception_tramp:
-       EXC_XFER_STD(0x600, alignment_exception)
-
-handle_page_fault_tramp_1:
-#ifdef CONFIG_VMAP_STACK
-       EXCEPTION_PROLOG_2 handle_dar_dsisr=1
-#endif
-       lwz     r4, _DAR(r11)
-       lwz     r5, _DSISR(r11)
-       /* fall through */
-handle_page_fault_tramp_2:
-       EXC_XFER_LITE(0x300, handle_page_fault)
-
-#ifdef CONFIG_VMAP_STACK
-.macro save_regs_thread                thread
-       stw     r0, THR0(\thread)
-       stw     r3, THR3(\thread)
-       stw     r4, THR4(\thread)
-       stw     r5, THR5(\thread)
-       stw     r6, THR6(\thread)
-       stw     r8, THR8(\thread)
-       stw     r9, THR9(\thread)
-       mflr    r0
-       stw     r0, THLR(\thread)
-       mfctr   r0
-       stw     r0, THCTR(\thread)
-.endm
-
-.macro restore_regs_thread     thread
-       lwz     r0, THLR(\thread)
-       mtlr    r0
-       lwz     r0, THCTR(\thread)
-       mtctr   r0
-       lwz     r0, THR0(\thread)
-       lwz     r3, THR3(\thread)
-       lwz     r4, THR4(\thread)
-       lwz     r5, THR5(\thread)
-       lwz     r6, THR6(\thread)
-       lwz     r8, THR8(\thread)
-       lwz     r9, THR9(\thread)
-.endm
-
-hash_page_dsi:
-       save_regs_thread        r10
-       mfdsisr r3
-       mfdar   r4
-       mfsrr0  r5
-       mfsrr1  r9
-       rlwinm  r3, r3, 32 - 15, _PAGE_RW       /* DSISR_STORE -> _PAGE_RW */
-       bl      hash_page
-       mfspr   r10, SPRN_SPRG_THREAD
-       restore_regs_thread r10
-       b       .Lhash_page_dsi_cont
-
-hash_page_isi:
-       mr      r11, r10
-       mfspr   r10, SPRN_SPRG_THREAD
-       save_regs_thread        r10
-       li      r3, 0
-       lwz     r4, SRR0(r10)
-       lwz     r9, SRR1(r10)
-       bl      hash_page
-       mfspr   r10, SPRN_SPRG_THREAD
-       restore_regs_thread r10
-       mr      r10, r11
-       b       .Lhash_page_isi_cont
-
-       .globl fast_hash_page_return
-fast_hash_page_return:
-       andis.  r10, r9, SRR1_ISI_NOPT@h        /* Set on ISI, cleared on DSI */
-       mfspr   r10, SPRN_SPRG_THREAD
-       restore_regs_thread r10
-       bne     1f
-
-       /* DSI */
-       mtcr    r11
-       lwz     r11, THR11(r10)
-       mfspr   r10, SPRN_SPRG_SCRATCH0
-       SYNC
-       RFI
-
-1:     /* ISI */
-       mtcr    r11
-       mfspr   r11, SPRN_SPRG_SCRATCH1
-       mfspr   r10, SPRN_SPRG_SCRATCH0
-       SYNC
-       RFI
-
-stack_overflow:
-       vmap_stack_overflow_exception
-#endif
-
-AltiVecUnavailable:
-       EXCEPTION_PROLOG
-#ifdef CONFIG_ALTIVEC
-       beq     1f
-       bl      load_up_altivec         /* if from user, just load it up */
-       b       fast_exception_return
-#endif /* CONFIG_ALTIVEC */
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_LITE(0xf20, altivec_unavailable_exception)
-
-PerformanceMonitor:
-       EXCEPTION_PROLOG
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       EXC_XFER_STD(0xf00, performance_monitor_exception)
-
-
-/*
- * This code is jumped to from the startup code to copy
- * the kernel image to physical address PHYSICAL_START.
- */
-relocate_kernel:
-       addis   r9,r26,klimit@ha        /* fetch klimit */
-       lwz     r25,klimit@l(r9)
-       addis   r25,r25,-KERNELBASE@h
-       lis     r3,PHYSICAL_START@h     /* Destination base address */
-       li      r6,0                    /* Destination offset */
-       li      r5,0x4000               /* # bytes of memory to copy */
-       bl      copy_and_flush          /* copy the first 0x4000 bytes */
-       addi    r0,r3,4f@l              /* jump to the address of 4f */
-       mtctr   r0                      /* in copy and do the rest. */
-       bctr                            /* jump to the copy */
-4:     mr      r5,r25
-       bl      copy_and_flush          /* copy the rest */
-       b       turn_on_mmu
-
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- */
-_ENTRY(copy_and_flush)
-       addi    r5,r5,-4
-       addi    r6,r6,-4
-4:     li      r0,L1_CACHE_BYTES/4
-       mtctr   r0
-3:     addi    r6,r6,4                 /* copy a cache line */
-       lwzx    r0,r6,r4
-       stwx    r0,r6,r3
-       bdnz    3b
-       dcbst   r6,r3                   /* write it to memory */
-       sync
-       icbi    r6,r3                   /* flush the icache line */
-       cmplw   0,r6,r5
-       blt     4b
-       sync                            /* additional sync needed on g4 */
-       isync
-       addi    r5,r5,4
-       addi    r6,r6,4
-       blr
-
-#ifdef CONFIG_SMP
-       .globl __secondary_start_mpc86xx
-__secondary_start_mpc86xx:
-       mfspr   r3, SPRN_PIR
-       stw     r3, __secondary_hold_acknowledge@l(0)
-       mr      r24, r3                 /* cpu # */
-       b       __secondary_start
-
-       .globl  __secondary_start_pmac_0
-__secondary_start_pmac_0:
-       /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
-       li      r24,0
-       b       1f
-       li      r24,1
-       b       1f
-       li      r24,2
-       b       1f
-       li      r24,3
-1:
-       /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
-          set to map the 0xf0000000 - 0xffffffff region */
-       mfmsr   r0
-       rlwinm  r0,r0,0,28,26           /* clear DR (0x10) */
-       SYNC
-       mtmsr   r0
-       isync
-
-       .globl  __secondary_start
-__secondary_start:
-       /* Copy some CPU settings from CPU 0 */
-       bl      __restore_cpu_setup
-
-       lis     r3,-KERNELBASE@h
-       mr      r4,r24
-       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
-#ifdef CONFIG_PPC_BOOK3S_32
-       lis     r3,-KERNELBASE@h
-       bl      init_idle_6xx
-#endif /* CONFIG_PPC_BOOK3S_32 */
-
-       /* get current's stack and current */
-       lis     r2,secondary_current@ha
-       tophys(r2,r2)
-       lwz     r2,secondary_current@l(r2)
-       tophys(r1,r2)
-       lwz     r1,TASK_STACK(r1)
-
-       /* stack */
-       addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
-       li      r0,0
-       tophys(r3,r1)
-       stw     r0,0(r3)
-
-       /* load up the MMU */
-       bl      load_segment_registers
-       bl      load_up_mmu
-
-       /* ptr to phys current thread */
-       tophys(r4,r2)
-       addi    r4,r4,THREAD    /* phys address of our thread_struct */
-       mtspr   SPRN_SPRG_THREAD,r4
-       lis     r4, (swapper_pg_dir - PAGE_OFFSET)@h
-       ori     r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
-       mtspr   SPRN_SPRG_PGDIR, r4
-
-       /* enable MMU and jump to start_secondary */
-       li      r4,MSR_KERNEL
-       lis     r3,start_secondary@h
-       ori     r3,r3,start_secondary@l
-       mtspr   SPRN_SRR0,r3
-       mtspr   SPRN_SRR1,r4
-       SYNC
-       RFI
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_KVM_BOOK3S_HANDLER
-#include "../kvm/book3s_rmhandlers.S"
-#endif
-
-/*
- * Those generic dummy functions are kept for CPUs not
- * included in CONFIG_PPC_BOOK3S_32
- */
-#if !defined(CONFIG_PPC_BOOK3S_32)
-_ENTRY(__save_cpu_setup)
-       blr
-_ENTRY(__restore_cpu_setup)
-       blr
-#endif /* !defined(CONFIG_PPC_BOOK3S_32) */
-
-/*
- * Load stuff into the MMU.  Intended to be called with
- * IR=0 and DR=0.
- */
-#ifdef CONFIG_KASAN
-early_hash_table:
-       sync                    /* Force all PTE updates to finish */
-       isync
-       tlbia                   /* Clear all TLB entries */
-       sync                    /* wait for tlbia/tlbie to finish */
-       TLBSYNC                 /* ... on all CPUs */
-       /* Load the SDR1 register (hash table base & size) */
-       lis     r6, early_hash - PAGE_OFFSET@h
-       ori     r6, r6, 3       /* 256kB table */
-       mtspr   SPRN_SDR1, r6
-       blr
-#endif
-
-load_up_mmu:
-       sync                    /* Force all PTE updates to finish */
-       isync
-       tlbia                   /* Clear all TLB entries */
-       sync                    /* wait for tlbia/tlbie to finish */
-       TLBSYNC                 /* ... on all CPUs */
-       /* Load the SDR1 register (hash table base & size) */
-       lis     r6,_SDR1@ha
-       tophys(r6,r6)
-       lwz     r6,_SDR1@l(r6)
-       mtspr   SPRN_SDR1,r6
-
-/* Load the BAT registers with the values set up by MMU_init.
-   MMU_init takes care of whether we're on a 601 or not. */
-       lis     r3,BATS@ha
-       addi    r3,r3,BATS@l
-       tophys(r3,r3)
-       LOAD_BAT(0,r3,r4,r5)
-       LOAD_BAT(1,r3,r4,r5)
-       LOAD_BAT(2,r3,r4,r5)
-       LOAD_BAT(3,r3,r4,r5)
-BEGIN_MMU_FTR_SECTION
-       LOAD_BAT(4,r3,r4,r5)
-       LOAD_BAT(5,r3,r4,r5)
-       LOAD_BAT(6,r3,r4,r5)
-       LOAD_BAT(7,r3,r4,r5)
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
-       blr
-
-load_segment_registers:
-       li      r0, NUM_USER_SEGMENTS /* load up user segment register values */
-       mtctr   r0              /* for context 0 */
-       li      r3, 0           /* Kp = 0, Ks = 0, VSID = 0 */
-#ifdef CONFIG_PPC_KUEP
-       oris    r3, r3, SR_NX@h /* Set Nx */
-#endif
-#ifdef CONFIG_PPC_KUAP
-       oris    r3, r3, SR_KS@h /* Set Ks */
-#endif
-       li      r4, 0
-3:     mtsrin  r3, r4
-       addi    r3, r3, 0x111   /* increment VSID */
-       addis   r4, r4, 0x1000  /* address of next segment */
-       bdnz    3b
-       li      r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
-       mtctr   r0                      /* for context 0 */
-       rlwinm  r3, r3, 0, ~SR_NX       /* Nx = 0 */
-       rlwinm  r3, r3, 0, ~SR_KS       /* Ks = 0 */
-       oris    r3, r3, SR_KP@h         /* Kp = 1 */
-3:     mtsrin  r3, r4
-       addi    r3, r3, 0x111   /* increment VSID */
-       addis   r4, r4, 0x1000  /* address of next segment */
-       bdnz    3b
-       blr
-
-/*
- * This is where the main kernel code starts.
- */
-start_here:
-       /* ptr to current */
-       lis     r2,init_task@h
-       ori     r2,r2,init_task@l
-       /* Set up for using our exception vectors */
-       /* ptr to phys current thread */
-       tophys(r4,r2)
-       addi    r4,r4,THREAD    /* init task's THREAD */
-       mtspr   SPRN_SPRG_THREAD,r4
-       lis     r4, (swapper_pg_dir - PAGE_OFFSET)@h
-       ori     r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
-       mtspr   SPRN_SPRG_PGDIR, r4
-
-       /* stack */
-       lis     r1,init_thread_union@ha
-       addi    r1,r1,init_thread_union@l
-       li      r0,0
-       stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
-/*
- * Do early platform-specific initialization,
- * and set up the MMU.
- */
-#ifdef CONFIG_KASAN
-       bl      kasan_early_init
-#endif
-       li      r3,0
-       mr      r4,r31
-       bl      machine_init
-       bl      __save_cpu_setup
-       bl      MMU_init
-#ifdef CONFIG_KASAN
-BEGIN_MMU_FTR_SECTION
-       bl      MMU_init_hw_patch
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
-#endif
-
-/*
- * Go back to running unmapped so we can load up new values
- * for SDR1 (hash table pointer) and the segment registers
- * and change to using our exception vectors.
- */
-       lis     r4,2f@h
-       ori     r4,r4,2f@l
-       tophys(r4,r4)
-       li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
-
-       .align  4
-       mtspr   SPRN_SRR0,r4
-       mtspr   SPRN_SRR1,r3
-       SYNC
-       RFI
-/* Load up the kernel context */
-2:     bl      load_up_mmu
-
-#ifdef CONFIG_BDI_SWITCH
-       /* Add helper information for the Abatron bdiGDB debugger.
-        * We do this here because we know the mmu is disabled, and
-        * will be enabled for real in just a few instructions.
-        */
-       lis     r5, abatron_pteptrs@h
-       ori     r5, r5, abatron_pteptrs@l
-       stw     r5, 0xf0(r0)    /* This much match your Abatron config */
-       lis     r6, swapper_pg_dir@h
-       ori     r6, r6, swapper_pg_dir@l
-       tophys(r5, r5)
-       stw     r6, 0(r5)
-#endif /* CONFIG_BDI_SWITCH */
-
-/* Now turn on the MMU for real! */
-       li      r4,MSR_KERNEL
-       lis     r3,start_kernel@h
-       ori     r3,r3,start_kernel@l
-       mtspr   SPRN_SRR0,r3
-       mtspr   SPRN_SRR1,r4
-       SYNC
-       RFI
-
-/*
- * void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);
- *
- * Set up the segment registers for a new context.
- */
-_ENTRY(switch_mmu_context)
-       lwz     r3,MMCONTEXTID(r4)
-       cmpwi   cr0,r3,0
-       blt-    4f
-       mulli   r3,r3,897       /* multiply context by skew factor */
-       rlwinm  r3,r3,4,8,27    /* VSID = (context & 0xfffff) << 4 */
-#ifdef CONFIG_PPC_KUEP
-       oris    r3, r3, SR_NX@h /* Set Nx */
-#endif
-#ifdef CONFIG_PPC_KUAP
-       oris    r3, r3, SR_KS@h /* Set Ks */
-#endif
-       li      r0,NUM_USER_SEGMENTS
-       mtctr   r0
-
-       lwz     r4, MM_PGD(r4)
-#ifdef CONFIG_BDI_SWITCH
-       /* Context switch the PTE pointer for the Abatron BDI2000.
-        * The PGDIR is passed as second argument.
-        */
-       lis     r5, abatron_pteptrs@ha
-       stw     r4, abatron_pteptrs@l + 0x4(r5)
-#endif
-       tophys(r4, r4)
-       mtspr   SPRN_SPRG_PGDIR, r4
-       li      r4,0
-       isync
-3:
-       mtsrin  r3,r4
-       addi    r3,r3,0x111     /* next VSID */
-       rlwinm  r3,r3,0,8,3     /* clear out any overflow from VSID field */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
-       sync
-       isync
-       blr
-4:     trap
-       EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,0
-       blr
-EXPORT_SYMBOL(switch_mmu_context)
-
-/*
- * An undocumented "feature" of 604e requires that the v bit
- * be cleared before changing BAT values.
- *
- * Also, newer IBM firmware does not clear bat3 and 4 so
- * this makes sure it's done.
- *  -- Cort
- */
-clear_bats:
-       li      r10,0
-
-#ifndef CONFIG_PPC_BOOK3S_601
-       mtspr   SPRN_DBAT0U,r10
-       mtspr   SPRN_DBAT0L,r10
-       mtspr   SPRN_DBAT1U,r10
-       mtspr   SPRN_DBAT1L,r10
-       mtspr   SPRN_DBAT2U,r10
-       mtspr   SPRN_DBAT2L,r10
-       mtspr   SPRN_DBAT3U,r10
-       mtspr   SPRN_DBAT3L,r10
-#endif
-       mtspr   SPRN_IBAT0U,r10
-       mtspr   SPRN_IBAT0L,r10
-       mtspr   SPRN_IBAT1U,r10
-       mtspr   SPRN_IBAT1L,r10
-       mtspr   SPRN_IBAT2U,r10
-       mtspr   SPRN_IBAT2L,r10
-       mtspr   SPRN_IBAT3U,r10
-       mtspr   SPRN_IBAT3L,r10
-BEGIN_MMU_FTR_SECTION
-       /* Here's a tweak: at this point, CPU setup have
-        * not been called yet, so HIGH_BAT_EN may not be
-        * set in HID0 for the 745x processors. However, it
-        * seems that doesn't affect our ability to actually
-        * write to these SPRs.
-        */
-       mtspr   SPRN_DBAT4U,r10
-       mtspr   SPRN_DBAT4L,r10
-       mtspr   SPRN_DBAT5U,r10
-       mtspr   SPRN_DBAT5L,r10
-       mtspr   SPRN_DBAT6U,r10
-       mtspr   SPRN_DBAT6L,r10
-       mtspr   SPRN_DBAT7U,r10
-       mtspr   SPRN_DBAT7L,r10
-       mtspr   SPRN_IBAT4U,r10
-       mtspr   SPRN_IBAT4L,r10
-       mtspr   SPRN_IBAT5U,r10
-       mtspr   SPRN_IBAT5L,r10
-       mtspr   SPRN_IBAT6U,r10
-       mtspr   SPRN_IBAT6L,r10
-       mtspr   SPRN_IBAT7U,r10
-       mtspr   SPRN_IBAT7L,r10
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
-       blr
-
-_ENTRY(update_bats)
-       lis     r4, 1f@h
-       ori     r4, r4, 1f@l
-       tophys(r4, r4)
-       mfmsr   r6
-       mflr    r7
-       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)
-       rlwinm  r0, r6, 0, ~MSR_RI
-       rlwinm  r0, r0, 0, ~MSR_EE
-       mtmsr   r0
-
-       .align  4
-       mtspr   SPRN_SRR0, r4
-       mtspr   SPRN_SRR1, r3
-       SYNC
-       RFI
-1:     bl      clear_bats
-       lis     r3, BATS@ha
-       addi    r3, r3, BATS@l
-       tophys(r3, r3)
-       LOAD_BAT(0, r3, r4, r5)
-       LOAD_BAT(1, r3, r4, r5)
-       LOAD_BAT(2, r3, r4, r5)
-       LOAD_BAT(3, r3, r4, r5)
-BEGIN_MMU_FTR_SECTION
-       LOAD_BAT(4, r3, r4, r5)
-       LOAD_BAT(5, r3, r4, r5)
-       LOAD_BAT(6, r3, r4, r5)
-       LOAD_BAT(7, r3, r4, r5)
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
-       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR | MSR_RI)
-       mtmsr   r3
-       mtspr   SPRN_SRR0, r7
-       mtspr   SPRN_SRR1, r6
-       SYNC
-       RFI
-
-flush_tlbs:
-       lis     r10, 0x40
-1:     addic.  r10, r10, -0x1000
-       tlbie   r10
-       bgt     1b
-       sync
-       blr
-
-mmu_off:
-       addi    r4, r3, __after_mmu_off - _start
-       mfmsr   r3
-       andi.   r0,r3,MSR_DR|MSR_IR             /* MMU enabled? */
-       beqlr
-       andc    r3,r3,r0
-
-       .align  4
-       mtspr   SPRN_SRR0,r4
-       mtspr   SPRN_SRR1,r3
-       sync
-       RFI
-
-/*
- * On 601, we use 3 BATs to map up to 24M of RAM at _PAGE_OFFSET
- * (we keep one for debugging) and on others, we use one 256M BAT.
- */
-initial_bats:
-       lis     r11,PAGE_OFFSET@h
-#ifdef CONFIG_PPC_BOOK3S_601
-       ori     r11,r11,4               /* set up BAT registers for 601 */
-       li      r8,0x7f                 /* valid, block length = 8MB */
-       mtspr   SPRN_IBAT0U,r11         /* N.B. 601 has valid bit in */
-       mtspr   SPRN_IBAT0L,r8          /* lower BAT register */
-       addis   r11,r11,0x800000@h
-       addis   r8,r8,0x800000@h
-       mtspr   SPRN_IBAT1U,r11
-       mtspr   SPRN_IBAT1L,r8
-       addis   r11,r11,0x800000@h
-       addis   r8,r8,0x800000@h
-       mtspr   SPRN_IBAT2U,r11
-       mtspr   SPRN_IBAT2L,r8
-#else
-       tophys(r8,r11)
-#ifdef CONFIG_SMP
-       ori     r8,r8,0x12              /* R/W access, M=1 */
-#else
-       ori     r8,r8,2                 /* R/W access */
-#endif /* CONFIG_SMP */
-       ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
-
-       mtspr   SPRN_DBAT0L,r8          /* N.B. 6xx (not 601) have valid */
-       mtspr   SPRN_DBAT0U,r11         /* bit in upper BAT register */
-       mtspr   SPRN_IBAT0L,r8
-       mtspr   SPRN_IBAT0U,r11
-#endif
-       isync
-       blr
-
-#ifdef CONFIG_BOOTX_TEXT
-setup_disp_bat:
-       /*
-        * setup the display bat prepared for us in prom.c
-        */
-       mflr    r8
-       bl      reloc_offset
-       mtlr    r8
-       addis   r8,r3,disp_BAT@ha
-       addi    r8,r8,disp_BAT@l
-       cmpwi   cr0,r8,0
-       beqlr
-       lwz     r11,0(r8)
-       lwz     r8,4(r8)
-#ifndef CONFIG_PPC_BOOK3S_601
-       mtspr   SPRN_DBAT3L,r8
-       mtspr   SPRN_DBAT3U,r11
-#else
-       mtspr   SPRN_IBAT3L,r8
-       mtspr   SPRN_IBAT3U,r11
-#endif
-       blr
-#endif /* CONFIG_BOOTX_TEXT */
-
-#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
-setup_cpm_bat:
-       lis     r8, 0xf000
-       ori     r8, r8, 0x002a
-       mtspr   SPRN_DBAT1L, r8
-
-       lis     r11, 0xf000
-       ori     r11, r11, (BL_1M << 2) | 2
-       mtspr   SPRN_DBAT1U, r11
-
-       blr
-#endif
-
-#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
-setup_usbgecko_bat:
-       /* prepare a BAT for early io */
-#if defined(CONFIG_GAMECUBE)
-       lis     r8, 0x0c00
-#elif defined(CONFIG_WII)
-       lis     r8, 0x0d00
-#else
-#error Invalid platform for USB Gecko based early debugging.
-#endif
-       /*
-        * The virtual address used must match the virtual address
-        * associated to the fixmap entry FIX_EARLY_DEBUG_BASE.
-        */
-       lis     r11, 0xfffe     /* top 128K */
-       ori     r8, r8, 0x002a  /* uncached, guarded ,rw */
-       ori     r11, r11, 0x2   /* 128K, Vs=1, Vp=0 */
-       mtspr   SPRN_DBAT1L, r8
-       mtspr   SPRN_DBAT1U, r11
-       blr
-#endif
-
-#ifdef CONFIG_8260
-/* Jump into the system reset for the rom.
- * We first disable the MMU, and then jump to the ROM reset address.
- *
- * r3 is the board info structure, r4 is the location for starting.
- * I use this for building a small kernel that can load other kernels,
- * rather than trying to write or rely on a rom monitor that can tftp load.
- */
-       .globl  m8260_gorom
-m8260_gorom:
-       mfmsr   r0
-       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
-       sync
-       mtmsr   r0
-       sync
-       mfspr   r11, SPRN_HID0
-       lis     r10, 0
-       ori     r10,r10,HID0_ICE|HID0_DCE
-       andc    r11, r11, r10
-       mtspr   SPRN_HID0, r11
-       isync
-       li      r5, MSR_ME|MSR_RI
-       lis     r6,2f@h
-       addis   r6,r6,-KERNELBASE@h
-       ori     r6,r6,2f@l
-       mtspr   SPRN_SRR0,r6
-       mtspr   SPRN_SRR1,r5
-       isync
-       sync
-       rfi
-2:
-       mtlr    r4
-       blr
-#endif
-
-
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
-       .data
-       .globl  sdata
-sdata:
-       .globl  empty_zero_page
-empty_zero_page:
-       .space  4096
-EXPORT_SYMBOL(empty_zero_page)
-
-       .globl  swapper_pg_dir
-swapper_pg_dir:
-       .space  PGD_TABLE_SIZE
-
-/* Room for two PTE pointers, usually the kernel and current user pointers
- * to their respective root page table.
- */
-abatron_pteptrs:
-       .space  8
index 9abec6c..7c76776 100644 (file)
 
 .macro EXCEPTION_PROLOG_1 for_rtas=0
 #ifdef CONFIG_VMAP_STACK
-       .ifeq   \for_rtas
-       li      r11, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */
-       mtmsr   r11
-       isync
-       .endif
-       subi    r11, r1, INT_FRAME_SIZE         /* use r1 if kernel */
+       mr      r11, r1
+       subi    r1, r1, INT_FRAME_SIZE          /* use r1 if kernel */
+       beq     1f
+       mfspr   r1,SPRN_SPRG_THREAD
+       lwz     r1,TASK_STACK-THREAD(r1)
+       addi    r1, r1, THREAD_SIZE - INT_FRAME_SIZE
 #else
-       tophys(r11,r1)                  /* use tophys(r1) if kernel */
-       subi    r11, r11, INT_FRAME_SIZE        /* alloc exc. frame */
-#endif
+       subi    r11, r1, INT_FRAME_SIZE         /* use r1 if kernel */
        beq     1f
        mfspr   r11,SPRN_SPRG_THREAD
-       tovirt_vmstack r11, r11
        lwz     r11,TASK_STACK-THREAD(r11)
        addi    r11, r11, THREAD_SIZE - INT_FRAME_SIZE
-       tophys_novmstack r11, r11
+#endif
 1:
+       tophys_novmstack r11, r11
 #ifdef CONFIG_VMAP_STACK
-       mtcrf   0x7f, r11
+       mtcrf   0x7f, r1
        bt      32 - THREAD_ALIGN_SHIFT, stack_overflow
 #endif
 .endm
 
 .macro EXCEPTION_PROLOG_2 handle_dar_dsisr=0
-#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
-BEGIN_MMU_FTR_SECTION
+#ifdef CONFIG_VMAP_STACK
        mtcr    r10
-FTR_SECTION_ELSE
-       stw     r10, _CCR(r11)
-ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
+       li      r10, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */
+       mtmsr   r10
+       isync
 #else
        stw     r10,_CCR(r11)           /* save registers */
 #endif
        mfspr   r10, SPRN_SPRG_SCRATCH0
+#ifdef CONFIG_VMAP_STACK
+       stw     r11,GPR1(r1)
+       stw     r11,0(r1)
+       mr      r11, r1
+#else
+       stw     r1,GPR1(r11)
+       stw     r1,0(r11)
+       tovirt(r1, r11)         /* set new kernel sp */
+#endif
        stw     r12,GPR12(r11)
        stw     r9,GPR9(r11)
        stw     r10,GPR10(r11)
-#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
-BEGIN_MMU_FTR_SECTION
+#ifdef CONFIG_VMAP_STACK
        mfcr    r10
        stw     r10, _CCR(r11)
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
 #endif
        mfspr   r12,SPRN_SPRG_SCRATCH1
        stw     r12,GPR11(r11)
@@ -97,19 +101,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
        stw     r10, _DSISR(r11)
        .endif
        lwz     r9, SRR1(r12)
-#if defined(CONFIG_VMAP_STACK) && defined(CONFIG_PPC_BOOK3S)
-BEGIN_MMU_FTR_SECTION
        andi.   r10, r9, MSR_PR
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
-#endif
        lwz     r12, SRR0(r12)
 #else
        mfspr   r12,SPRN_SRR0
        mfspr   r9,SPRN_SRR1
 #endif
-       stw     r1,GPR1(r11)
-       stw     r1,0(r11)
-       tovirt_novmstack r1, r11        /* set new kernel sp */
 #ifdef CONFIG_40x
        rlwinm  r9,r9,0,14,12           /* clear MSR_WE (necessary?) */
 #else
@@ -225,7 +222,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
 #endif
        mtspr   SPRN_SRR1,r10
        mtspr   SPRN_SRR0,r11
-       SYNC
        RFI                             /* jump to handler, enable MMU */
 99:    b       ret_from_kernel_syscall
 .endm
@@ -327,20 +323,19 @@ label:
 .macro vmap_stack_overflow_exception
 #ifdef CONFIG_VMAP_STACK
 #ifdef CONFIG_SMP
-       mfspr   r11, SPRN_SPRG_THREAD
-       tovirt(r11, r11)
-       lwz     r11, TASK_CPU - THREAD(r11)
-       slwi    r11, r11, 3
-       addis   r11, r11, emergency_ctx@ha
+       mfspr   r1, SPRN_SPRG_THREAD
+       lwz     r1, TASK_CPU - THREAD(r1)
+       slwi    r1, r1, 3
+       addis   r1, r1, emergency_ctx@ha
 #else
-       lis     r11, emergency_ctx@ha
+       lis     r1, emergency_ctx@ha
 #endif
-       lwz     r11, emergency_ctx@l(r11)
-       cmpwi   cr1, r11, 0
+       lwz     r1, emergency_ctx@l(r1)
+       cmpwi   cr1, r1, 0
        bne     cr1, 1f
-       lis     r11, init_thread_union@ha
-       addi    r11, r11, init_thread_union@l
-1:     addi    r11, r11, THREAD_SIZE - INT_FRAME_SIZE
+       lis     r1, init_thread_union@ha
+       addi    r1, r1, init_thread_union@l
+1:     addi    r1, r1, THREAD_SIZE - INT_FRAME_SIZE
        EXCEPTION_PROLOG_2
        SAVE_NVGPRS(r11)
        addi    r3, r1, STACK_FRAME_OVERHEAD
index 5b282d9..44c9018 100644 (file)
@@ -72,7 +72,6 @@ turn_on_mmu:
        lis     r0,start_here@h
        ori     r0,r0,start_here@l
        mtspr   SPRN_SRR0,r0
-       SYNC
        rfi                             /* enables MMU */
        b       .                       /* prevent prefetch past rfi */
 
index 0e05a9a..1510b2a 100644 (file)
@@ -300,9 +300,6 @@ _GLOBAL(fsl_secondary_thread_init)
        rlwimi  r3, r3, 30, 2, 30
        mtspr   SPRN_PIR, r3
 1:
-#endif
-
-_GLOBAL(generic_secondary_thread_init)
        mr      r24,r3
 
        /* turn on 64-bit mode */
@@ -312,13 +309,13 @@ _GLOBAL(generic_secondary_thread_init)
        bl      relative_toc
        tovirt(r2,r2)
 
-#ifdef CONFIG_PPC_BOOK3E
        /* Book3E initialization */
        mr      r3,r24
        bl      book3e_secondary_thread_init
-#endif
        b       generic_secondary_common_init
 
+#endif /* CONFIG_PPC_BOOK3E */
+
 /*
  * On pSeries and most other platforms, secondary processors spin
  * in the following code.
diff --git a/arch/powerpc/kernel/head_book3s_32.S b/arch/powerpc/kernel/head_book3s_32.S
new file mode 100644 (file)
index 0000000..5eb9eed
--- /dev/null
@@ -0,0 +1,1351 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  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.
+ *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC platform, including trap and interrupt dispatch.
+ *  (The PPC 8xx embedded CPUs use head_8xx.S instead.)
+ */
+
+#include <linux/init.h>
+#include <linux/pgtable.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/ptrace.h>
+#include <asm/bug.h>
+#include <asm/kvm_book3s_asm.h>
+#include <asm/export.h>
+#include <asm/feature-fixups.h>
+
+#include "head_32.h"
+
+#define LOAD_BAT(n, reg, RA, RB)       \
+       /* see the comment for clear_bats() -- Cort */ \
+       li      RA,0;                   \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       lwz     RA,(n*16)+0(reg);       \
+       lwz     RB,(n*16)+4(reg);       \
+       mtspr   SPRN_IBAT##n##U,RA;     \
+       mtspr   SPRN_IBAT##n##L,RB;     \
+       lwz     RA,(n*16)+8(reg);       \
+       lwz     RB,(n*16)+12(reg);      \
+       mtspr   SPRN_DBAT##n##U,RA;     \
+       mtspr   SPRN_DBAT##n##L,RB
+
+       __HEAD
+       .stabs  "arch/powerpc/kernel/",N_SO,0,0,0f
+       .stabs  "head_book3s_32.S",N_SO,0,0,0f
+0:
+_ENTRY(_stext);
+
+/*
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
+ */
+_ENTRY(_start);
+       /*
+        * These are here for legacy reasons, the kernel used to
+        * need to look like a coff function entry for the pmac
+        * but we're always started by some kind of bootloader now.
+        *  -- Cort
+        */
+       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
+       nop     /* used by __secondary_hold on prep (mtx) and chrp smp */
+       nop
+
+/* PMAC
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address).  Address translation is turned on, with the prom
+ * managing the hash table.  Interrupts are disabled.  The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
+ *
+ * If we are booted from MacOS via BootX, we enter with the kernel
+ * image loaded somewhere, and the following values in registers:
+ *  r3: 'BooX' (0x426f6f58)
+ *  r4: virtual address of boot_infos_t
+ *  r5: 0
+ *
+ * PREP
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader.  The expected layout
+ * of the regs is:
+ *   r3: ptr to residual data
+ *   r4: initrd_start or if no initrd then 0
+ *   r5: initrd_end - unused if r4 is 0
+ *   r6: Start of command line string
+ *   r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
+ */
+
+       .globl  __start
+__start:
+/*
+ * We have to do any OF calls before we map ourselves to KERNELBASE,
+ * because OF may have I/O devices mapped into that area
+ * (particularly on CHRP).
+ */
+       cmpwi   0,r5,0
+       beq     1f
+
+#ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
+       /* find out where we are now */
+       bcl     20,31,$+4
+0:     mflr    r8                      /* r8 = runtime addr here */
+       addis   r8,r8,(_stext - 0b)@ha
+       addi    r8,r8,(_stext - 0b)@l   /* current runtime base addr */
+       bl      prom_init
+#endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */
+
+       /* We never return. We also hit that trap if trying to boot
+        * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */
+       trap
+
+/*
+ * Check for BootX signature when supporting PowerMac and branch to
+ * appropriate trampoline if it's present
+ */
+#ifdef CONFIG_PPC_PMAC
+1:     lis     r31,0x426f
+       ori     r31,r31,0x6f58
+       cmpw    0,r3,r31
+       bne     1f
+       bl      bootx_init
+       trap
+#endif /* CONFIG_PPC_PMAC */
+
+1:     mr      r31,r3                  /* save device tree ptr */
+       li      r24,0                   /* cpu # */
+
+/*
+ * early_init() does the early machine identification and does
+ * the necessary low-level setup and clears the BSS
+ *  -- Cort <cort@fsmlabs.com>
+ */
+       bl      early_init
+
+/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
+ * the physical address we are running at, returned by early_init()
+ */
+       bl      mmu_off
+__after_mmu_off:
+       bl      clear_bats
+       bl      flush_tlbs
+
+       bl      initial_bats
+       bl      load_segment_registers
+BEGIN_MMU_FTR_SECTION
+       bl      early_hash_table
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
+#if defined(CONFIG_BOOTX_TEXT)
+       bl      setup_disp_bat
+#endif
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+       bl      setup_cpm_bat
+#endif
+#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
+       bl      setup_usbgecko_bat
+#endif
+
+/*
+ * Call setup_cpu for CPU 0 and initialize 6xx Idle
+ */
+       bl      reloc_offset
+       li      r24,0                   /* cpu# */
+       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
+       bl      reloc_offset
+       bl      init_idle_6xx
+
+
+/*
+ * We need to run with _start at physical address 0.
+ * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
+ * the exception vectors at 0 (and therefore this copy
+ * overwrites OF's exception vectors with our own).
+ * The MMU is off at this point.
+ */
+       bl      reloc_offset
+       mr      r26,r3
+       addis   r4,r3,KERNELBASE@h      /* current address of _start */
+       lis     r5,PHYSICAL_START@h
+       cmplw   0,r4,r5                 /* already running at PHYSICAL_START? */
+       bne     relocate_kernel
+/*
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
+ * Actually no, pmac doesn't have it on any more. BootX enters with MMU
+ * off, and in other cases, we now turn it off before changing BATs above.
+ */
+turn_on_mmu:
+       mfmsr   r0
+       ori     r0,r0,MSR_DR|MSR_IR|MSR_RI
+       mtspr   SPRN_SRR1,r0
+       lis     r0,start_here@h
+       ori     r0,r0,start_here@l
+       mtspr   SPRN_SRR0,r0
+       RFI                             /* enables MMU */
+
+/*
+ * We need __secondary_hold as a place to hold the other cpus on
+ * an SMP machine, even when we are running a UP kernel.
+ */
+       . = 0xc0                        /* for prep bootloader */
+       li      r3,1                    /* MTX only has 1 cpu */
+       .globl  __secondary_hold
+__secondary_hold:
+       /* tell the master we're here */
+       stw     r3,__secondary_hold_acknowledge@l(0)
+#ifdef CONFIG_SMP
+100:   lwz     r4,0(0)
+       /* wait until we're told to start */
+       cmpw    0,r4,r3
+       bne     100b
+       /* our cpu # was at addr 0 - go */
+       mr      r24,r3                  /* cpu # */
+       b       __secondary_start
+#else
+       b       .
+#endif /* CONFIG_SMP */
+
+       .globl  __secondary_hold_spinloop
+__secondary_hold_spinloop:
+       .long   0
+       .globl  __secondary_hold_acknowledge
+__secondary_hold_acknowledge:
+       .long   -1
+
+/* System reset */
+/* core99 pmac starts the seconary here by changing the vector, and
+   putting it back to what it was (unknown_exception) when done.  */
+       EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
+
+/* Machine check */
+/*
+ * On CHRP, this is complicated by the fact that we could get a
+ * machine check inside RTAS, and we have no guarantee that certain
+ * critical registers will have the values we expect.  The set of
+ * registers that might have bad values includes all the GPRs
+ * and all the BATs.  We indicate that we are in RTAS by putting
+ * a non-zero value, the address of the exception frame to use,
+ * in thread.rtas_sp.  The machine check handler checks thread.rtas_sp
+ * and uses its value if it is non-zero.
+ * (Other exception handlers assume that r1 is a valid kernel stack
+ * pointer when we take an exception from supervisor mode.)
+ *     -- paulus.
+ */
+       . = 0x200
+       DO_KVM  0x200
+MachineCheck:
+       EXCEPTION_PROLOG_0
+#ifdef CONFIG_PPC_CHRP
+       mfspr   r11, SPRN_SPRG_THREAD
+       lwz     r11, RTAS_SP(r11)
+       cmpwi   cr1, r11, 0
+       bne     cr1, 7f
+#endif /* CONFIG_PPC_CHRP */
+       EXCEPTION_PROLOG_1 for_rtas=1
+7:     EXCEPTION_PROLOG_2
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+#ifdef CONFIG_PPC_CHRP
+#ifdef CONFIG_VMAP_STACK
+       mfspr   r4, SPRN_SPRG_THREAD
+       tovirt(r4, r4)
+       lwz     r4, RTAS_SP(r4)
+       cmpwi   cr1, r4, 0
+#endif
+       beq     cr1, machine_check_tramp
+       twi     31, 0, 0
+#else
+       b       machine_check_tramp
+#endif
+
+/* Data access exception. */
+       . = 0x300
+       DO_KVM  0x300
+DataAccess:
+#ifdef CONFIG_VMAP_STACK
+       mtspr   SPRN_SPRG_SCRATCH0,r10
+       mfspr   r10, SPRN_SPRG_THREAD
+BEGIN_MMU_FTR_SECTION
+       stw     r11, THR11(r10)
+       mfspr   r10, SPRN_DSISR
+       mfcr    r11
+#ifdef CONFIG_PPC_KUAP
+       andis.  r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH | DSISR_PROTFAULT)@h
+#else
+       andis.  r10, r10, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
+#endif
+       mfspr   r10, SPRN_SPRG_THREAD
+       beq     hash_page_dsi
+.Lhash_page_dsi_cont:
+       mtcr    r11
+       lwz     r11, THR11(r10)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
+       mtspr   SPRN_SPRG_SCRATCH1,r11
+       mfspr   r11, SPRN_DAR
+       stw     r11, DAR(r10)
+       mfspr   r11, SPRN_DSISR
+       stw     r11, DSISR(r10)
+       mfspr   r11, SPRN_SRR0
+       stw     r11, SRR0(r10)
+       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
+       stw     r11, SRR1(r10)
+       mfcr    r10
+       andi.   r11, r11, MSR_PR
+
+       EXCEPTION_PROLOG_1
+       b       handle_page_fault_tramp_1
+#else  /* CONFIG_VMAP_STACK */
+       EXCEPTION_PROLOG handle_dar_dsisr=1
+       get_and_save_dar_dsisr_on_stack r4, r5, r11
+BEGIN_MMU_FTR_SECTION
+#ifdef CONFIG_PPC_KUAP
+       andis.  r0, r5, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH | DSISR_PROTFAULT)@h
+#else
+       andis.  r0, r5, (DSISR_BAD_FAULT_32S | DSISR_DABRMATCH)@h
+#endif
+       bne     handle_page_fault_tramp_2       /* if not, try to put a PTE */
+       rlwinm  r3, r5, 32 - 15, 21, 21         /* DSISR_STORE -> _PAGE_RW */
+       bl      hash_page
+       b       handle_page_fault_tramp_1
+FTR_SECTION_ELSE
+       b       handle_page_fault_tramp_2
+ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_HPTE_TABLE)
+#endif /* CONFIG_VMAP_STACK */
+
+/* Instruction access exception. */
+       . = 0x400
+       DO_KVM  0x400
+InstructionAccess:
+#ifdef CONFIG_VMAP_STACK
+       mtspr   SPRN_SPRG_SCRATCH0,r10
+       mtspr   SPRN_SPRG_SCRATCH1,r11
+       mfspr   r10, SPRN_SPRG_THREAD
+       mfspr   r11, SPRN_SRR0
+       stw     r11, SRR0(r10)
+       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
+       stw     r11, SRR1(r10)
+       mfcr    r10
+BEGIN_MMU_FTR_SECTION
+       andis.  r11, r11, SRR1_ISI_NOPT@h       /* no pte found? */
+       bne     hash_page_isi
+.Lhash_page_isi_cont:
+       mfspr   r11, SPRN_SRR1          /* check whether user or kernel */
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
+       andi.   r11, r11, MSR_PR
+
+       EXCEPTION_PROLOG_1
+       EXCEPTION_PROLOG_2
+#else  /* CONFIG_VMAP_STACK */
+       EXCEPTION_PROLOG
+       andis.  r0,r9,SRR1_ISI_NOPT@h   /* no pte found? */
+       beq     1f                      /* if so, try to put a PTE */
+       li      r3,0                    /* into the hash table */
+       mr      r4,r12                  /* SRR0 is fault address */
+BEGIN_MMU_FTR_SECTION
+       bl      hash_page
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_HPTE_TABLE)
+#endif /* CONFIG_VMAP_STACK */
+1:     mr      r4,r12
+       andis.  r5,r9,DSISR_SRR1_MATCH_32S@h /* Filter relevant SRR1 bits */
+       stw     r4, _DAR(r11)
+       EXC_XFER_LITE(0x400, handle_page_fault)
+
+/* External interrupt */
+       EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
+
+/* Alignment exception */
+       . = 0x600
+       DO_KVM  0x600
+Alignment:
+       EXCEPTION_PROLOG handle_dar_dsisr=1
+       save_dar_dsisr_on_stack r4, r5, r11
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       b       alignment_exception_tramp
+
+/* Program check exception */
+       EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
+
+/* Floating-point unavailable */
+       . = 0x800
+       DO_KVM  0x800
+FPUnavailable:
+BEGIN_FTR_SECTION
+/*
+ * Certain Freescale cores don't have a FPU and treat fp instructions
+ * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
+ */
+       b       ProgramCheck
+END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
+       EXCEPTION_PROLOG
+       beq     1f
+       bl      load_up_fpu             /* if from user, just load it up */
+       b       fast_exception_return
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_LITE(0x800, kernel_fp_unavailable_exception)
+
+/* Decrementer */
+       EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
+
+       EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_STD)
+
+/* System call */
+       . = 0xc00
+       DO_KVM  0xc00
+SystemCall:
+       SYSCALL_ENTRY   0xc00
+
+       EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD)
+       EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_STD)
+
+/*
+ * The Altivec unavailable trap is at 0x0f20.  Foo.
+ * We effectively remap it to 0x3000.
+ * We include an altivec unavailable exception vector even if
+ * not configured for Altivec, so that you can't panic a
+ * non-altivec kernel running on a machine with altivec just
+ * by executing an altivec instruction.
+ */
+       . = 0xf00
+       DO_KVM  0xf00
+       b       PerformanceMonitor
+
+       . = 0xf20
+       DO_KVM  0xf20
+       b       AltiVecUnavailable
+
+/*
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
+ */
+       . = 0x1000
+InstructionTLBMiss:
+/*
+ * r0: scratch
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_IMISS
+#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
+       lis     r1, TASK_SIZE@h         /* check if kernel address */
+       cmplw   0,r1,r3
+#endif
+       mfspr   r2, SPRN_SPRG_PGDIR
+#ifdef CONFIG_SWAP
+       li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
+#else
+       li      r1,_PAGE_PRESENT | _PAGE_EXEC
+#endif
+#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC)
+       bgt-    112f
+       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
+#endif
+112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    InstructionAddressInvalid       /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
+       bne-    InstructionAddressInvalid /* return if access not permitted */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwimi  r0,r0,32-2,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r1, r1, 0xe06           /* clear out reserved bits */
+       andc    r1, r0, r1              /* PP = user? 1 : 0 */
+BEGIN_FTR_SECTION
+       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
+       mtspr   SPRN_RPA,r1
+       tlbli   r3
+       mfspr   r3,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r3
+       rfi
+InstructionAddressInvalid:
+       mfspr   r3,SPRN_SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+
+       addis   r1,r1,0x2000
+       mtspr   SPRN_DSISR,r1   /* (shouldn't be needed) */
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       or      r2,r2,r1
+       mtspr   SPRN_SRR1,r2
+       mfspr   r1,SPRN_IMISS   /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       rlwimi  r2,r2,1,30,30   /* change 1 -> 3 */
+       xor     r1,r1,r2
+       mtspr   SPRN_DAR,r1     /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       mtmsr   r0
+       b       InstructionAccess
+
+/*
+ * Handle TLB miss for DATA Load operation on 603/603e
+ */
+       . = 0x1100
+DataLoadTLBMiss:
+/*
+ * r0: scratch
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_DMISS
+       lis     r1, TASK_SIZE@h         /* check if kernel address */
+       cmplw   0,r1,r3
+       mfspr   r2, SPRN_SPRG_PGDIR
+#ifdef CONFIG_SWAP
+       li      r1, _PAGE_PRESENT | _PAGE_ACCESSED
+#else
+       li      r1, _PAGE_PRESENT
+#endif
+       bgt-    112f
+       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
+112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    DataAddressInvalid      /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
+       bne-    DataAddressInvalid      /* return if access not permitted */
+       /*
+        * NOTE! We are assuming this is not an SMP system, otherwise
+        * we would need to update the pte atomically with lwarx/stwcx.
+        */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwinm  r1,r0,32-9,30,30        /* _PAGE_RW -> PP msb */
+       rlwimi  r0,r0,32-1,30,30        /* _PAGE_USER -> PP msb */
+       rlwimi  r0,r0,32-1,31,31        /* _PAGE_USER -> PP lsb */
+       ori     r1,r1,0xe04             /* clear out reserved bits */
+       andc    r1,r0,r1                /* PP = user? rw? 1: 3: 0 */
+BEGIN_FTR_SECTION
+       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
+       mtspr   SPRN_RPA,r1
+       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r2
+BEGIN_MMU_FTR_SECTION
+       li      r0,1
+       mfspr   r1,SPRN_SPRG_603_LRU
+       rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
+       slw     r0,r0,r2
+       xor     r1,r0,r1
+       srw     r0,r1,r2
+       mtspr   SPRN_SPRG_603_LRU,r1
+       mfspr   r2,SPRN_SRR1
+       rlwimi  r2,r0,31-14,14,14
+       mtspr   SPRN_SRR1,r2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
+       tlbld   r3
+       rfi
+DataAddressInvalid:
+       mfspr   r3,SPRN_SRR1
+       rlwinm  r1,r3,9,6,6     /* Get load/store bit */
+       addis   r1,r1,0x2000
+       mtspr   SPRN_DSISR,r1
+       andi.   r2,r3,0xFFFF    /* Clear upper bits of SRR1 */
+       mtspr   SPRN_SRR1,r2
+       mfspr   r1,SPRN_DMISS   /* Get failing address */
+       rlwinm. r2,r2,0,31,31   /* Check for little endian access */
+       beq     20f             /* Jump if big endian */
+       xori    r1,r1,3
+20:    mtspr   SPRN_DAR,r1     /* Set fault address */
+       mfmsr   r0              /* Restore "normal" registers */
+       xoris   r0,r0,MSR_TGPR>>16
+       mtcrf   0x80,r3         /* Restore CR0 */
+       mtmsr   r0
+       b       DataAccess
+
+/*
+ * Handle TLB miss for DATA Store on 603/603e
+ */
+       . = 0x1200
+DataStoreTLBMiss:
+/*
+ * r0: scratch
+ * r1: linux style pte ( later becomes ppc hardware pte )
+ * r2: ptr to linux-style pte
+ * r3: scratch
+ */
+       /* Get PTE (linux-style) and check access */
+       mfspr   r3,SPRN_DMISS
+       lis     r1, TASK_SIZE@h         /* check if kernel address */
+       cmplw   0,r1,r3
+       mfspr   r2, SPRN_SPRG_PGDIR
+#ifdef CONFIG_SWAP
+       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
+#else
+       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT
+#endif
+       bgt-    112f
+       lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
+112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
+       lwz     r2,0(r2)                /* get pmd entry */
+       rlwinm. r2,r2,0,0,19            /* extract address of pte page */
+       beq-    DataAddressInvalid      /* return if no mapping */
+       rlwimi  r2,r3,22,20,29          /* insert next 10 bits of address */
+       lwz     r0,0(r2)                /* get linux-style pte */
+       andc.   r1,r1,r0                /* check access & ~permission */
+       bne-    DataAddressInvalid      /* return if access not permitted */
+       /*
+        * NOTE! We are assuming this is not an SMP system, otherwise
+        * we would need to update the pte atomically with lwarx/stwcx.
+        */
+       /* Convert linux-style PTE to low word of PPC-style PTE */
+       rlwimi  r0,r0,32-2,31,31        /* _PAGE_USER -> PP lsb */
+       li      r1,0xe06                /* clear out reserved bits & PP msb */
+       andc    r1,r0,r1                /* PP = user? 1: 0 */
+BEGIN_FTR_SECTION
+       rlwinm  r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
+       mtspr   SPRN_RPA,r1
+       mfspr   r2,SPRN_SRR1            /* Need to restore CR0 */
+       mtcrf   0x80,r2
+BEGIN_MMU_FTR_SECTION
+       li      r0,1
+       mfspr   r1,SPRN_SPRG_603_LRU
+       rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
+       slw     r0,r0,r2
+       xor     r1,r0,r1
+       srw     r0,r1,r2
+       mtspr   SPRN_SPRG_603_LRU,r1
+       mfspr   r2,SPRN_SRR1
+       rlwimi  r2,r0,31-14,14,14
+       mtspr   SPRN_SRR1,r2
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
+       tlbld   r3
+       rfi
+
+#ifndef CONFIG_ALTIVEC
+#define altivec_assist_exception       unknown_exception
+#endif
+
+#ifndef CONFIG_TAU_INT
+#define TAUException   unknown_exception
+#endif
+
+       EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_STD)
+       EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_STD)
+       EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_STD)
+       EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
+       EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_STD)
+       EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_STD)
+       EXCEPTION(0x2f00, Trap_2f, unknown_exception, EXC_XFER_STD)
+
+       . = 0x3000
+
+machine_check_tramp:
+       EXC_XFER_STD(0x200, machine_check_exception)
+
+alignment_exception_tramp:
+       EXC_XFER_STD(0x600, alignment_exception)
+
+handle_page_fault_tramp_1:
+#ifdef CONFIG_VMAP_STACK
+       EXCEPTION_PROLOG_2 handle_dar_dsisr=1
+#endif
+       lwz     r4, _DAR(r11)
+       lwz     r5, _DSISR(r11)
+       /* fall through */
+handle_page_fault_tramp_2:
+       EXC_XFER_LITE(0x300, handle_page_fault)
+
+#ifdef CONFIG_VMAP_STACK
+.macro save_regs_thread                thread
+       stw     r0, THR0(\thread)
+       stw     r3, THR3(\thread)
+       stw     r4, THR4(\thread)
+       stw     r5, THR5(\thread)
+       stw     r6, THR6(\thread)
+       stw     r8, THR8(\thread)
+       stw     r9, THR9(\thread)
+       mflr    r0
+       stw     r0, THLR(\thread)
+       mfctr   r0
+       stw     r0, THCTR(\thread)
+.endm
+
+.macro restore_regs_thread     thread
+       lwz     r0, THLR(\thread)
+       mtlr    r0
+       lwz     r0, THCTR(\thread)
+       mtctr   r0
+       lwz     r0, THR0(\thread)
+       lwz     r3, THR3(\thread)
+       lwz     r4, THR4(\thread)
+       lwz     r5, THR5(\thread)
+       lwz     r6, THR6(\thread)
+       lwz     r8, THR8(\thread)
+       lwz     r9, THR9(\thread)
+.endm
+
+hash_page_dsi:
+       save_regs_thread        r10
+       mfdsisr r3
+       mfdar   r4
+       mfsrr0  r5
+       mfsrr1  r9
+       rlwinm  r3, r3, 32 - 15, _PAGE_RW       /* DSISR_STORE -> _PAGE_RW */
+       bl      hash_page
+       mfspr   r10, SPRN_SPRG_THREAD
+       restore_regs_thread r10
+       b       .Lhash_page_dsi_cont
+
+hash_page_isi:
+       mr      r11, r10
+       mfspr   r10, SPRN_SPRG_THREAD
+       save_regs_thread        r10
+       li      r3, 0
+       lwz     r4, SRR0(r10)
+       lwz     r9, SRR1(r10)
+       bl      hash_page
+       mfspr   r10, SPRN_SPRG_THREAD
+       restore_regs_thread r10
+       mr      r10, r11
+       b       .Lhash_page_isi_cont
+
+       .globl fast_hash_page_return
+fast_hash_page_return:
+       andis.  r10, r9, SRR1_ISI_NOPT@h        /* Set on ISI, cleared on DSI */
+       mfspr   r10, SPRN_SPRG_THREAD
+       restore_regs_thread r10
+       bne     1f
+
+       /* DSI */
+       mtcr    r11
+       lwz     r11, THR11(r10)
+       mfspr   r10, SPRN_SPRG_SCRATCH0
+       RFI
+
+1:     /* ISI */
+       mtcr    r11
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
+       RFI
+
+stack_overflow:
+       vmap_stack_overflow_exception
+#endif
+
+AltiVecUnavailable:
+       EXCEPTION_PROLOG
+#ifdef CONFIG_ALTIVEC
+       beq     1f
+       bl      load_up_altivec         /* if from user, just load it up */
+       b       fast_exception_return
+#endif /* CONFIG_ALTIVEC */
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_LITE(0xf20, altivec_unavailable_exception)
+
+PerformanceMonitor:
+       EXCEPTION_PROLOG
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       EXC_XFER_STD(0xf00, performance_monitor_exception)
+
+
+/*
+ * This code is jumped to from the startup code to copy
+ * the kernel image to physical address PHYSICAL_START.
+ */
+relocate_kernel:
+       addis   r9,r26,klimit@ha        /* fetch klimit */
+       lwz     r25,klimit@l(r9)
+       addis   r25,r25,-KERNELBASE@h
+       lis     r3,PHYSICAL_START@h     /* Destination base address */
+       li      r6,0                    /* Destination offset */
+       li      r5,0x4000               /* # bytes of memory to copy */
+       bl      copy_and_flush          /* copy the first 0x4000 bytes */
+       addi    r0,r3,4f@l              /* jump to the address of 4f */
+       mtctr   r0                      /* in copy and do the rest. */
+       bctr                            /* jump to the copy */
+4:     mr      r5,r25
+       bl      copy_and_flush          /* copy the rest */
+       b       turn_on_mmu
+
+/*
+ * Copy routine used to copy the kernel to start at physical address 0
+ * and flush and invalidate the caches as needed.
+ * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
+ * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
+ */
+_ENTRY(copy_and_flush)
+       addi    r5,r5,-4
+       addi    r6,r6,-4
+4:     li      r0,L1_CACHE_BYTES/4
+       mtctr   r0
+3:     addi    r6,r6,4                 /* copy a cache line */
+       lwzx    r0,r6,r4
+       stwx    r0,r6,r3
+       bdnz    3b
+       dcbst   r6,r3                   /* write it to memory */
+       sync
+       icbi    r6,r3                   /* flush the icache line */
+       cmplw   0,r6,r5
+       blt     4b
+       sync                            /* additional sync needed on g4 */
+       isync
+       addi    r5,r5,4
+       addi    r6,r6,4
+       blr
+
+#ifdef CONFIG_SMP
+       .globl __secondary_start_mpc86xx
+__secondary_start_mpc86xx:
+       mfspr   r3, SPRN_PIR
+       stw     r3, __secondary_hold_acknowledge@l(0)
+       mr      r24, r3                 /* cpu # */
+       b       __secondary_start
+
+       .globl  __secondary_start_pmac_0
+__secondary_start_pmac_0:
+       /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
+       li      r24,0
+       b       1f
+       li      r24,1
+       b       1f
+       li      r24,2
+       b       1f
+       li      r24,3
+1:
+       /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0
+          set to map the 0xf0000000 - 0xffffffff region */
+       mfmsr   r0
+       rlwinm  r0,r0,0,28,26           /* clear DR (0x10) */
+       mtmsr   r0
+       isync
+
+       .globl  __secondary_start
+__secondary_start:
+       /* Copy some CPU settings from CPU 0 */
+       bl      __restore_cpu_setup
+
+       lis     r3,-KERNELBASE@h
+       mr      r4,r24
+       bl      call_setup_cpu          /* Call setup_cpu for this CPU */
+       lis     r3,-KERNELBASE@h
+       bl      init_idle_6xx
+
+       /* get current's stack and current */
+       lis     r2,secondary_current@ha
+       tophys(r2,r2)
+       lwz     r2,secondary_current@l(r2)
+       tophys(r1,r2)
+       lwz     r1,TASK_STACK(r1)
+
+       /* stack */
+       addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
+       li      r0,0
+       tophys(r3,r1)
+       stw     r0,0(r3)
+
+       /* load up the MMU */
+       bl      load_segment_registers
+       bl      load_up_mmu
+
+       /* ptr to phys current thread */
+       tophys(r4,r2)
+       addi    r4,r4,THREAD    /* phys address of our thread_struct */
+       mtspr   SPRN_SPRG_THREAD,r4
+       lis     r4, (swapper_pg_dir - PAGE_OFFSET)@h
+       ori     r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
+       mtspr   SPRN_SPRG_PGDIR, r4
+
+       /* enable MMU and jump to start_secondary */
+       li      r4,MSR_KERNEL
+       lis     r3,start_secondary@h
+       ori     r3,r3,start_secondary@l
+       mtspr   SPRN_SRR0,r3
+       mtspr   SPRN_SRR1,r4
+       RFI
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
+#include "../kvm/book3s_rmhandlers.S"
+#endif
+
+/*
+ * Load stuff into the MMU.  Intended to be called with
+ * IR=0 and DR=0.
+ */
+early_hash_table:
+       sync                    /* Force all PTE updates to finish */
+       isync
+       tlbia                   /* Clear all TLB entries */
+       sync                    /* wait for tlbia/tlbie to finish */
+       TLBSYNC                 /* ... on all CPUs */
+       /* Load the SDR1 register (hash table base & size) */
+       lis     r6, early_hash - PAGE_OFFSET@h
+       ori     r6, r6, 3       /* 256kB table */
+       mtspr   SPRN_SDR1, r6
+       lis     r6, early_hash@h
+       lis     r3, Hash@ha
+       stw     r6, Hash@l(r3)
+       blr
+
+load_up_mmu:
+       sync                    /* Force all PTE updates to finish */
+       isync
+       tlbia                   /* Clear all TLB entries */
+       sync                    /* wait for tlbia/tlbie to finish */
+       TLBSYNC                 /* ... on all CPUs */
+       /* Load the SDR1 register (hash table base & size) */
+       lis     r6,_SDR1@ha
+       tophys(r6,r6)
+       lwz     r6,_SDR1@l(r6)
+       mtspr   SPRN_SDR1,r6
+
+/* Load the BAT registers with the values set up by MMU_init. */
+       lis     r3,BATS@ha
+       addi    r3,r3,BATS@l
+       tophys(r3,r3)
+       LOAD_BAT(0,r3,r4,r5)
+       LOAD_BAT(1,r3,r4,r5)
+       LOAD_BAT(2,r3,r4,r5)
+       LOAD_BAT(3,r3,r4,r5)
+BEGIN_MMU_FTR_SECTION
+       LOAD_BAT(4,r3,r4,r5)
+       LOAD_BAT(5,r3,r4,r5)
+       LOAD_BAT(6,r3,r4,r5)
+       LOAD_BAT(7,r3,r4,r5)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+       blr
+
+_GLOBAL(load_segment_registers)
+       li      r0, NUM_USER_SEGMENTS /* load up user segment register values */
+       mtctr   r0              /* for context 0 */
+       li      r3, 0           /* Kp = 0, Ks = 0, VSID = 0 */
+#ifdef CONFIG_PPC_KUEP
+       oris    r3, r3, SR_NX@h /* Set Nx */
+#endif
+#ifdef CONFIG_PPC_KUAP
+       oris    r3, r3, SR_KS@h /* Set Ks */
+#endif
+       li      r4, 0
+3:     mtsrin  r3, r4
+       addi    r3, r3, 0x111   /* increment VSID */
+       addis   r4, r4, 0x1000  /* address of next segment */
+       bdnz    3b
+       li      r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
+       mtctr   r0                      /* for context 0 */
+       rlwinm  r3, r3, 0, ~SR_NX       /* Nx = 0 */
+       rlwinm  r3, r3, 0, ~SR_KS       /* Ks = 0 */
+       oris    r3, r3, SR_KP@h         /* Kp = 1 */
+3:     mtsrin  r3, r4
+       addi    r3, r3, 0x111   /* increment VSID */
+       addis   r4, r4, 0x1000  /* address of next segment */
+       bdnz    3b
+       blr
+
+/*
+ * This is where the main kernel code starts.
+ */
+start_here:
+       /* ptr to current */
+       lis     r2,init_task@h
+       ori     r2,r2,init_task@l
+       /* Set up for using our exception vectors */
+       /* ptr to phys current thread */
+       tophys(r4,r2)
+       addi    r4,r4,THREAD    /* init task's THREAD */
+       mtspr   SPRN_SPRG_THREAD,r4
+       lis     r4, (swapper_pg_dir - PAGE_OFFSET)@h
+       ori     r4, r4, (swapper_pg_dir - PAGE_OFFSET)@l
+       mtspr   SPRN_SPRG_PGDIR, r4
+
+       /* stack */
+       lis     r1,init_thread_union@ha
+       addi    r1,r1,init_thread_union@l
+       li      r0,0
+       stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+/*
+ * Do early platform-specific initialization,
+ * and set up the MMU.
+ */
+#ifdef CONFIG_KASAN
+       bl      kasan_early_init
+#endif
+       li      r3,0
+       mr      r4,r31
+       bl      machine_init
+       bl      __save_cpu_setup
+       bl      MMU_init
+       bl      MMU_init_hw_patch
+
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+       lis     r4,2f@h
+       ori     r4,r4,2f@l
+       tophys(r4,r4)
+       li      r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+
+       .align  4
+       mtspr   SPRN_SRR0,r4
+       mtspr   SPRN_SRR1,r3
+       RFI
+/* Load up the kernel context */
+2:     bl      load_up_mmu
+
+#ifdef CONFIG_BDI_SWITCH
+       /* Add helper information for the Abatron bdiGDB debugger.
+        * We do this here because we know the mmu is disabled, and
+        * will be enabled for real in just a few instructions.
+        */
+       lis     r5, abatron_pteptrs@h
+       ori     r5, r5, abatron_pteptrs@l
+       stw     r5, 0xf0(0)     /* This much match your Abatron config */
+       lis     r6, swapper_pg_dir@h
+       ori     r6, r6, swapper_pg_dir@l
+       tophys(r5, r5)
+       stw     r6, 0(r5)
+#endif /* CONFIG_BDI_SWITCH */
+
+/* Now turn on the MMU for real! */
+       li      r4,MSR_KERNEL
+       lis     r3,start_kernel@h
+       ori     r3,r3,start_kernel@l
+       mtspr   SPRN_SRR0,r3
+       mtspr   SPRN_SRR1,r4
+       RFI
+
+/*
+ * void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);
+ *
+ * Set up the segment registers for a new context.
+ */
+_ENTRY(switch_mmu_context)
+       lwz     r3,MMCONTEXTID(r4)
+       cmpwi   cr0,r3,0
+       blt-    4f
+       mulli   r3,r3,897       /* multiply context by skew factor */
+       rlwinm  r3,r3,4,8,27    /* VSID = (context & 0xfffff) << 4 */
+#ifdef CONFIG_PPC_KUEP
+       oris    r3, r3, SR_NX@h /* Set Nx */
+#endif
+#ifdef CONFIG_PPC_KUAP
+       oris    r3, r3, SR_KS@h /* Set Ks */
+#endif
+       li      r0,NUM_USER_SEGMENTS
+       mtctr   r0
+
+       lwz     r4, MM_PGD(r4)
+#ifdef CONFIG_BDI_SWITCH
+       /* Context switch the PTE pointer for the Abatron BDI2000.
+        * The PGDIR is passed as second argument.
+        */
+       lis     r5, abatron_pteptrs@ha
+       stw     r4, abatron_pteptrs@l + 0x4(r5)
+#endif
+       tophys(r4, r4)
+       mtspr   SPRN_SPRG_PGDIR, r4
+       li      r4,0
+       isync
+3:
+       mtsrin  r3,r4
+       addi    r3,r3,0x111     /* next VSID */
+       rlwinm  r3,r3,0,8,3     /* clear out any overflow from VSID field */
+       addis   r4,r4,0x1000    /* address of next segment */
+       bdnz    3b
+       sync
+       isync
+       blr
+4:     trap
+       EMIT_BUG_ENTRY 4b,__FILE__,__LINE__,0
+       blr
+EXPORT_SYMBOL(switch_mmu_context)
+
+/*
+ * An undocumented "feature" of 604e requires that the v bit
+ * be cleared before changing BAT values.
+ *
+ * Also, newer IBM firmware does not clear bat3 and 4 so
+ * this makes sure it's done.
+ *  -- Cort
+ */
+clear_bats:
+       li      r10,0
+
+       mtspr   SPRN_DBAT0U,r10
+       mtspr   SPRN_DBAT0L,r10
+       mtspr   SPRN_DBAT1U,r10
+       mtspr   SPRN_DBAT1L,r10
+       mtspr   SPRN_DBAT2U,r10
+       mtspr   SPRN_DBAT2L,r10
+       mtspr   SPRN_DBAT3U,r10
+       mtspr   SPRN_DBAT3L,r10
+       mtspr   SPRN_IBAT0U,r10
+       mtspr   SPRN_IBAT0L,r10
+       mtspr   SPRN_IBAT1U,r10
+       mtspr   SPRN_IBAT1L,r10
+       mtspr   SPRN_IBAT2U,r10
+       mtspr   SPRN_IBAT2L,r10
+       mtspr   SPRN_IBAT3U,r10
+       mtspr   SPRN_IBAT3L,r10
+BEGIN_MMU_FTR_SECTION
+       /* Here's a tweak: at this point, CPU setup have
+        * not been called yet, so HIGH_BAT_EN may not be
+        * set in HID0 for the 745x processors. However, it
+        * seems that doesn't affect our ability to actually
+        * write to these SPRs.
+        */
+       mtspr   SPRN_DBAT4U,r10
+       mtspr   SPRN_DBAT4L,r10
+       mtspr   SPRN_DBAT5U,r10
+       mtspr   SPRN_DBAT5L,r10
+       mtspr   SPRN_DBAT6U,r10
+       mtspr   SPRN_DBAT6L,r10
+       mtspr   SPRN_DBAT7U,r10
+       mtspr   SPRN_DBAT7L,r10
+       mtspr   SPRN_IBAT4U,r10
+       mtspr   SPRN_IBAT4L,r10
+       mtspr   SPRN_IBAT5U,r10
+       mtspr   SPRN_IBAT5L,r10
+       mtspr   SPRN_IBAT6U,r10
+       mtspr   SPRN_IBAT6L,r10
+       mtspr   SPRN_IBAT7U,r10
+       mtspr   SPRN_IBAT7L,r10
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+       blr
+
+_ENTRY(update_bats)
+       lis     r4, 1f@h
+       ori     r4, r4, 1f@l
+       tophys(r4, r4)
+       mfmsr   r6
+       mflr    r7
+       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)
+       rlwinm  r0, r6, 0, ~MSR_RI
+       rlwinm  r0, r0, 0, ~MSR_EE
+       mtmsr   r0
+
+       .align  4
+       mtspr   SPRN_SRR0, r4
+       mtspr   SPRN_SRR1, r3
+       RFI
+1:     bl      clear_bats
+       lis     r3, BATS@ha
+       addi    r3, r3, BATS@l
+       tophys(r3, r3)
+       LOAD_BAT(0, r3, r4, r5)
+       LOAD_BAT(1, r3, r4, r5)
+       LOAD_BAT(2, r3, r4, r5)
+       LOAD_BAT(3, r3, r4, r5)
+BEGIN_MMU_FTR_SECTION
+       LOAD_BAT(4, r3, r4, r5)
+       LOAD_BAT(5, r3, r4, r5)
+       LOAD_BAT(6, r3, r4, r5)
+       LOAD_BAT(7, r3, r4, r5)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+       li      r3, MSR_KERNEL & ~(MSR_IR | MSR_DR | MSR_RI)
+       mtmsr   r3
+       mtspr   SPRN_SRR0, r7
+       mtspr   SPRN_SRR1, r6
+       RFI
+
+flush_tlbs:
+       lis     r10, 0x40
+1:     addic.  r10, r10, -0x1000
+       tlbie   r10
+       bgt     1b
+       sync
+       blr
+
+mmu_off:
+       addi    r4, r3, __after_mmu_off - _start
+       mfmsr   r3
+       andi.   r0,r3,MSR_DR|MSR_IR             /* MMU enabled? */
+       beqlr
+       andc    r3,r3,r0
+
+       .align  4
+       mtspr   SPRN_SRR0,r4
+       mtspr   SPRN_SRR1,r3
+       sync
+       RFI
+
+/* We use one BAT to map up to 256M of RAM at _PAGE_OFFSET */
+initial_bats:
+       lis     r11,PAGE_OFFSET@h
+       tophys(r8,r11)
+#ifdef CONFIG_SMP
+       ori     r8,r8,0x12              /* R/W access, M=1 */
+#else
+       ori     r8,r8,2                 /* R/W access */
+#endif /* CONFIG_SMP */
+       ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
+
+       mtspr   SPRN_DBAT0L,r8          /* N.B. 6xx have valid */
+       mtspr   SPRN_DBAT0U,r11         /* bit in upper BAT register */
+       mtspr   SPRN_IBAT0L,r8
+       mtspr   SPRN_IBAT0U,r11
+       isync
+       blr
+
+#ifdef CONFIG_BOOTX_TEXT
+setup_disp_bat:
+       /*
+        * setup the display bat prepared for us in prom.c
+        */
+       mflr    r8
+       bl      reloc_offset
+       mtlr    r8
+       addis   r8,r3,disp_BAT@ha
+       addi    r8,r8,disp_BAT@l
+       cmpwi   cr0,r8,0
+       beqlr
+       lwz     r11,0(r8)
+       lwz     r8,4(r8)
+       mtspr   SPRN_DBAT3L,r8
+       mtspr   SPRN_DBAT3U,r11
+       blr
+#endif /* CONFIG_BOOTX_TEXT */
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+setup_cpm_bat:
+       lis     r8, 0xf000
+       ori     r8, r8, 0x002a
+       mtspr   SPRN_DBAT1L, r8
+
+       lis     r11, 0xf000
+       ori     r11, r11, (BL_1M << 2) | 2
+       mtspr   SPRN_DBAT1U, r11
+
+       blr
+#endif
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
+setup_usbgecko_bat:
+       /* prepare a BAT for early io */
+#if defined(CONFIG_GAMECUBE)
+       lis     r8, 0x0c00
+#elif defined(CONFIG_WII)
+       lis     r8, 0x0d00
+#else
+#error Invalid platform for USB Gecko based early debugging.
+#endif
+       /*
+        * The virtual address used must match the virtual address
+        * associated to the fixmap entry FIX_EARLY_DEBUG_BASE.
+        */
+       lis     r11, 0xfffe     /* top 128K */
+       ori     r8, r8, 0x002a  /* uncached, guarded ,rw */
+       ori     r11, r11, 0x2   /* 128K, Vs=1, Vp=0 */
+       mtspr   SPRN_DBAT1L, r8
+       mtspr   SPRN_DBAT1U, r11
+       blr
+#endif
+
+#ifdef CONFIG_8260
+/* Jump into the system reset for the rom.
+ * We first disable the MMU, and then jump to the ROM reset address.
+ *
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
+ */
+       .globl  m8260_gorom
+m8260_gorom:
+       mfmsr   r0
+       rlwinm  r0,r0,0,17,15   /* clear MSR_EE in r0 */
+       sync
+       mtmsr   r0
+       sync
+       mfspr   r11, SPRN_HID0
+       lis     r10, 0
+       ori     r10,r10,HID0_ICE|HID0_DCE
+       andc    r11, r11, r10
+       mtspr   SPRN_HID0, r11
+       isync
+       li      r5, MSR_ME|MSR_RI
+       lis     r6,2f@h
+       addis   r6,r6,-KERNELBASE@h
+       ori     r6,r6,2f@l
+       mtspr   SPRN_SRR0,r6
+       mtspr   SPRN_SRR1,r5
+       isync
+       sync
+       rfi
+2:
+       mtlr    r4
+       blr
+#endif
+
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+       .data
+       .globl  sdata
+sdata:
+       .globl  empty_zero_page
+empty_zero_page:
+       .space  4096
+EXPORT_SYMBOL(empty_zero_page)
+
+       .globl  swapper_pg_dir
+swapper_pg_dir:
+       .space  PGD_TABLE_SIZE
+
+/* Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+       .space  8
index 18f87bf..71c359d 100644 (file)
@@ -176,7 +176,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV)
 #endif
        mtspr   SPRN_SRR1,r10
        mtspr   SPRN_SRR0,r11
-       SYNC
        RFI                             /* jump to handler, enable MMU */
 99:    b       ret_from_kernel_syscall
 .endm
index 1f4a1ef..f4e8f21 100644 (file)
@@ -494,151 +494,6 @@ reset:
        }
 }
 
-static bool dar_in_user_range(unsigned long dar, struct arch_hw_breakpoint *info)
-{
-       return ((info->address <= dar) && (dar - info->address < info->len));
-}
-
-static bool ea_user_range_overlaps(unsigned long ea, int size,
-                                  struct arch_hw_breakpoint *info)
-{
-       return ((ea < info->address + info->len) &&
-               (ea + size > info->address));
-}
-
-static bool dar_in_hw_range(unsigned long dar, struct arch_hw_breakpoint *info)
-{
-       unsigned long hw_start_addr, hw_end_addr;
-
-       hw_start_addr = ALIGN_DOWN(info->address, HW_BREAKPOINT_SIZE);
-       hw_end_addr = ALIGN(info->address + info->len, HW_BREAKPOINT_SIZE);
-
-       return ((hw_start_addr <= dar) && (hw_end_addr > dar));
-}
-
-static bool ea_hw_range_overlaps(unsigned long ea, int size,
-                                struct arch_hw_breakpoint *info)
-{
-       unsigned long hw_start_addr, hw_end_addr;
-
-       hw_start_addr = ALIGN_DOWN(info->address, HW_BREAKPOINT_SIZE);
-       hw_end_addr = ALIGN(info->address + info->len, HW_BREAKPOINT_SIZE);
-
-       return ((ea < hw_end_addr) && (ea + size > hw_start_addr));
-}
-
-/*
- * If hw has multiple DAWR registers, we also need to check all
- * dawrx constraint bits to confirm this is _really_ a valid event.
- * If type is UNKNOWN, but privilege level matches, consider it as
- * a positive match.
- */
-static bool check_dawrx_constraints(struct pt_regs *regs, int type,
-                                   struct arch_hw_breakpoint *info)
-{
-       if (OP_IS_LOAD(type) && !(info->type & HW_BRK_TYPE_READ))
-               return false;
-
-       /*
-        * The Cache Management instructions other than dcbz never
-        * cause a match. i.e. if type is CACHEOP, the instruction
-        * is dcbz, and dcbz is treated as Store.
-        */
-       if ((OP_IS_STORE(type) || type == CACHEOP) && !(info->type & HW_BRK_TYPE_WRITE))
-               return false;
-
-       if (is_kernel_addr(regs->nip) && !(info->type & HW_BRK_TYPE_KERNEL))
-               return false;
-
-       if (user_mode(regs) && !(info->type & HW_BRK_TYPE_USER))
-               return false;
-
-       return true;
-}
-
-/*
- * Return true if the event is valid wrt dawr configuration,
- * including extraneous exception. Otherwise return false.
- */
-static bool check_constraints(struct pt_regs *regs, struct ppc_inst instr,
-                             unsigned long ea, int type, int size,
-                             struct arch_hw_breakpoint *info)
-{
-       bool in_user_range = dar_in_user_range(regs->dar, info);
-       bool dawrx_constraints;
-
-       /*
-        * 8xx supports only one breakpoint and thus we can
-        * unconditionally return true.
-        */
-       if (IS_ENABLED(CONFIG_PPC_8xx)) {
-               if (!in_user_range)
-                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
-               return true;
-       }
-
-       if (unlikely(ppc_inst_equal(instr, ppc_inst(0)))) {
-               if (cpu_has_feature(CPU_FTR_ARCH_31) &&
-                   !dar_in_hw_range(regs->dar, info))
-                       return false;
-
-               return true;
-       }
-
-       dawrx_constraints = check_dawrx_constraints(regs, type, info);
-
-       if (type == UNKNOWN) {
-               if (cpu_has_feature(CPU_FTR_ARCH_31) &&
-                   !dar_in_hw_range(regs->dar, info))
-                       return false;
-
-               return dawrx_constraints;
-       }
-
-       if (ea_user_range_overlaps(ea, size, info))
-               return dawrx_constraints;
-
-       if (ea_hw_range_overlaps(ea, size, info)) {
-               if (dawrx_constraints) {
-                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
-                       return true;
-               }
-       }
-       return false;
-}
-
-static int cache_op_size(void)
-{
-#ifdef __powerpc64__
-       return ppc64_caches.l1d.block_size;
-#else
-       return L1_CACHE_BYTES;
-#endif
-}
-
-static void get_instr_detail(struct pt_regs *regs, struct ppc_inst *instr,
-                            int *type, int *size, unsigned long *ea)
-{
-       struct instruction_op op;
-
-       if (__get_user_instr_inatomic(*instr, (void __user *)regs->nip))
-               return;
-
-       analyse_instr(&op, regs, *instr);
-       *type = GETTYPE(op.type);
-       *ea = op.ea;
-#ifdef __powerpc64__
-       if (!(regs->msr & MSR_64BIT))
-               *ea &= 0xffffffffUL;
-#endif
-
-       *size = GETSIZE(op.type);
-       if (*type == CACHEOP) {
-               *size = cache_op_size();
-               *ea &= ~(*size - 1);
-       }
-}
-
 static bool is_larx_stcx_instr(int type)
 {
        return type == LARX || type == STCX;
@@ -722,7 +577,7 @@ int hw_breakpoint_handler(struct die_args *args)
        rcu_read_lock();
 
        if (!IS_ENABLED(CONFIG_PPC_8xx))
-               get_instr_detail(regs, &instr, &type, &size, &ea);
+               wp_get_instr_detail(regs, &instr, &type, &size, &ea);
 
        for (i = 0; i < nr_wp_slots(); i++) {
                bp[i] = __this_cpu_read(bp_per_reg[i]);
@@ -732,7 +587,7 @@ int hw_breakpoint_handler(struct die_args *args)
                info[i] = counter_arch_bp(bp[i]);
                info[i]->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
 
-               if (check_constraints(regs, instr, ea, type, size, info[i])) {
+               if (wp_check_constraints(regs, instr, ea, type, size, info[i])) {
                        if (!IS_ENABLED(CONFIG_PPC_8xx) &&
                            ppc_inst_equal(instr, ppc_inst(0))) {
                                handler_error(bp[i], info[i]);
diff --git a/arch/powerpc/kernel/hw_breakpoint_constraints.c b/arch/powerpc/kernel/hw_breakpoint_constraints.c
new file mode 100644 (file)
index 0000000..867ee4a
--- /dev/null
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/sstep.h>
+#include <asm/cache.h>
+
+static bool dar_in_user_range(unsigned long dar, struct arch_hw_breakpoint *info)
+{
+       return ((info->address <= dar) && (dar - info->address < info->len));
+}
+
+static bool ea_user_range_overlaps(unsigned long ea, int size,
+                                  struct arch_hw_breakpoint *info)
+{
+       return ((ea < info->address + info->len) &&
+               (ea + size > info->address));
+}
+
+static bool dar_in_hw_range(unsigned long dar, struct arch_hw_breakpoint *info)
+{
+       unsigned long hw_start_addr, hw_end_addr;
+
+       hw_start_addr = ALIGN_DOWN(info->address, HW_BREAKPOINT_SIZE);
+       hw_end_addr = ALIGN(info->address + info->len, HW_BREAKPOINT_SIZE);
+
+       return ((hw_start_addr <= dar) && (hw_end_addr > dar));
+}
+
+static bool ea_hw_range_overlaps(unsigned long ea, int size,
+                                struct arch_hw_breakpoint *info)
+{
+       unsigned long hw_start_addr, hw_end_addr;
+       unsigned long align_size = HW_BREAKPOINT_SIZE;
+
+       /*
+        * On p10 predecessors, quadword is handle differently then
+        * other instructions.
+        */
+       if (!cpu_has_feature(CPU_FTR_ARCH_31) && size == 16)
+               align_size = HW_BREAKPOINT_SIZE_QUADWORD;
+
+       hw_start_addr = ALIGN_DOWN(info->address, align_size);
+       hw_end_addr = ALIGN(info->address + info->len, align_size);
+
+       return ((ea < hw_end_addr) && (ea + size > hw_start_addr));
+}
+
+/*
+ * If hw has multiple DAWR registers, we also need to check all
+ * dawrx constraint bits to confirm this is _really_ a valid event.
+ * If type is UNKNOWN, but privilege level matches, consider it as
+ * a positive match.
+ */
+static bool check_dawrx_constraints(struct pt_regs *regs, int type,
+                                   struct arch_hw_breakpoint *info)
+{
+       if (OP_IS_LOAD(type) && !(info->type & HW_BRK_TYPE_READ))
+               return false;
+
+       /*
+        * The Cache Management instructions other than dcbz never
+        * cause a match. i.e. if type is CACHEOP, the instruction
+        * is dcbz, and dcbz is treated as Store.
+        */
+       if ((OP_IS_STORE(type) || type == CACHEOP) && !(info->type & HW_BRK_TYPE_WRITE))
+               return false;
+
+       if (is_kernel_addr(regs->nip) && !(info->type & HW_BRK_TYPE_KERNEL))
+               return false;
+
+       if (user_mode(regs) && !(info->type & HW_BRK_TYPE_USER))
+               return false;
+
+       return true;
+}
+
+/*
+ * Return true if the event is valid wrt dawr configuration,
+ * including extraneous exception. Otherwise return false.
+ */
+bool wp_check_constraints(struct pt_regs *regs, struct ppc_inst instr,
+                         unsigned long ea, int type, int size,
+                         struct arch_hw_breakpoint *info)
+{
+       bool in_user_range = dar_in_user_range(regs->dar, info);
+       bool dawrx_constraints;
+
+       /*
+        * 8xx supports only one breakpoint and thus we can
+        * unconditionally return true.
+        */
+       if (IS_ENABLED(CONFIG_PPC_8xx)) {
+               if (!in_user_range)
+                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+               return true;
+       }
+
+       if (unlikely(ppc_inst_equal(instr, ppc_inst(0)))) {
+               if (cpu_has_feature(CPU_FTR_ARCH_31) &&
+                   !dar_in_hw_range(regs->dar, info))
+                       return false;
+
+               return true;
+       }
+
+       dawrx_constraints = check_dawrx_constraints(regs, type, info);
+
+       if (type == UNKNOWN) {
+               if (cpu_has_feature(CPU_FTR_ARCH_31) &&
+                   !dar_in_hw_range(regs->dar, info))
+                       return false;
+
+               return dawrx_constraints;
+       }
+
+       if (ea_user_range_overlaps(ea, size, info))
+               return dawrx_constraints;
+
+       if (ea_hw_range_overlaps(ea, size, info)) {
+               if (dawrx_constraints) {
+                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+                       return true;
+               }
+       }
+       return false;
+}
+
+static int cache_op_size(void)
+{
+#ifdef __powerpc64__
+       return ppc64_caches.l1d.block_size;
+#else
+       return L1_CACHE_BYTES;
+#endif
+}
+
+void wp_get_instr_detail(struct pt_regs *regs, struct ppc_inst *instr,
+                        int *type, int *size, unsigned long *ea)
+{
+       struct instruction_op op;
+
+       if (__get_user_instr_inatomic(*instr, (void __user *)regs->nip))
+               return;
+
+       analyse_instr(&op, regs, *instr);
+       *type = GETTYPE(op.type);
+       *ea = op.ea;
+#ifdef __powerpc64__
+       if (!(regs->msr & MSR_64BIT))
+               *ea &= 0xffffffffUL;
+#endif
+
+       *size = GETSIZE(op.type);
+       if (*type == CACHEOP) {
+               *size = cache_op_size();
+               *ea &= ~(*size - 1);
+       } else if (*type == LOAD_VMX || *type == STORE_VMX) {
+               *ea &= ~(*size - 1);
+       }
+}
index 422e31d..ae0e263 100644 (file)
@@ -41,14 +41,6 @@ static int __init powersave_off(char *arg)
 }
 __setup("powersave=off", powersave_off);
 
-#ifdef CONFIG_HOTPLUG_CPU
-void arch_cpu_idle_dead(void)
-{
-       sched_preempt_enable_no_resched();
-       cpu_die();
-}
-#endif
-
 void arch_cpu_idle(void)
 {
        ppc64_runlatch_off();
index bf21ebd..7d0f768 100644 (file)
@@ -104,7 +104,7 @@ static inline notrace unsigned long get_irq_happened(void)
 
 static inline notrace int decrementer_check_overflow(void)
 {
-       u64 now = get_tb_or_rtc();
+       u64 now = get_tb();
        u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
  
        return now >= *next_tb;
@@ -113,7 +113,7 @@ static inline notrace int decrementer_check_overflow(void)
 #ifdef CONFIG_PPC_BOOK3E
 
 /* This is called whenever we are re-enabling interrupts
- * and returns either 0 (nothing to do) or 500/900/280/a00/e80 if
+ * and returns either 0 (nothing to do) or 500/900/280 if
  * there's an EE, DEC or DBELL to generate.
  *
  * This is called in two contexts: From arch_local_irq_restore()
@@ -181,16 +181,6 @@ notrace unsigned int __check_irq_replay(void)
                return 0x500;
        }
 
-       /*
-        * 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 (happened & PACA_IRQ_EE_EDGE) {
-               local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
-               return 0x500;
-       }
-
        if (happened & PACA_IRQ_DBELL) {
                local_paca->irq_happened &= ~PACA_IRQ_DBELL;
                return 0x280;
@@ -201,6 +191,25 @@ notrace unsigned int __check_irq_replay(void)
 
        return 0;
 }
+
+/*
+ * 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...
+ *
+ * NOTE: This is called with interrupts hard disabled but not marked
+ * as such in paca->irq_happened, so we need to resync this.
+ */
+void notrace restore_interrupts(void)
+{
+       if (irqs_disabled()) {
+               local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+               local_irq_enable();
+       } else
+               __hard_irq_enable();
+}
+
 #endif /* CONFIG_PPC_BOOK3E */
 
 void replay_soft_interrupts(void)
@@ -214,7 +223,7 @@ void replay_soft_interrupts(void)
        struct pt_regs regs;
 
        ppc_save_regs(&regs);
-       regs.softe = IRQS_ALL_DISABLED;
+       regs.softe = IRQS_ENABLED;
 
 again:
        if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
@@ -270,19 +279,6 @@ again:
                        hard_irq_disable();
        }
 
-       /*
-        * 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 (IS_ENABLED(CONFIG_PPC_BOOK3E) && (happened & PACA_IRQ_EE_EDGE)) {
-               local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE;
-               regs.trap = 0x500;
-               do_IRQ(&regs);
-               if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
-                       hard_irq_disable();
-       }
-
        if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) {
                local_paca->irq_happened &= ~PACA_IRQ_DBELL;
                if (IS_ENABLED(CONFIG_PPC_BOOK3E))
@@ -368,6 +364,12 @@ notrace void arch_local_irq_restore(unsigned long mask)
                }
        }
 
+       /*
+        * Disable preempt here, so that the below preempt_enable will
+        * perform resched if required (a replayed interrupt may set
+        * need_resched).
+        */
+       preempt_disable();
        irq_soft_mask_set(IRQS_ALL_DISABLED);
        trace_hardirqs_off();
 
@@ -377,27 +379,10 @@ notrace void arch_local_irq_restore(unsigned long mask)
        trace_hardirqs_on();
        irq_soft_mask_set(IRQS_ENABLED);
        __hard_irq_enable();
+       preempt_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...
- *
- * NOTE: This is called with interrupts hard disabled but not marked
- * as such in paca->irq_happened, so we need to resync this.
- */
-void notrace restore_interrupts(void)
-{
-       if (irqs_disabled()) {
-               local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
-               local_irq_enable();
-       } else
-               __hard_irq_enable();
-}
-
 /*
  * This is a helper to use when about to go into idle low-power
  * when the latter has the side effect of re-enabling interrupts
index 5f07aa5..225511d 100644 (file)
@@ -256,7 +256,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
        sync
 
        /* Restore MSR (restores EE and DR bits to original state) */
-       SYNC
        mtmsr   r7
        isync
 
@@ -377,7 +376,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
 1:     bdnz    1b
 
        /* Restore MSR (restores EE and DR bits to original state) */
-4:     SYNC
+4:
        mtmsr   r7
        isync
        blr
index b24f866..717e658 100644 (file)
@@ -215,19 +215,6 @@ _GLOBAL(low_choose_7447a_dfs)
 
 #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_PPC_BOOK3S_32 */
 
-/*
- * complement mask on the msr then "or" some values on.
- *     _nmask_and_or_msr(nmask, value_to_or)
- */
-_GLOBAL(_nmask_and_or_msr)
-       mfmsr   r0              /* Get current msr */
-       andc    r0,r0,r3        /* And off the bits set in r3 (first parm) */
-       or      r0,r0,r4        /* Or on the bits in r4 (second parm) */
-       SYNC                    /* Some chip revs have problems here... */
-       mtmsr   r0              /* Update machine state */
-       isync
-       blr                     /* Done */
-
 #ifdef CONFIG_40x
 
 /*
@@ -268,41 +255,6 @@ _ASM_NOKPROBE_SYMBOL(real_writeb)
 
 #endif /* CONFIG_40x */
 
-
-/*
- * Flush instruction cache.
- * This is a no-op on the 601.
- */
-#ifndef CONFIG_PPC_8xx
-_GLOBAL(flush_instruction_cache)
-#if defined(CONFIG_4xx)
-       lis     r3, KERNELBASE@h
-       iccci   0,r3
-#elif defined(CONFIG_FSL_BOOKE)
-#ifdef CONFIG_E200
-       mfspr   r3,SPRN_L1CSR0
-       ori     r3,r3,L1CSR0_CFI|L1CSR0_CLFC
-       /* msync; isync recommended here */
-       mtspr   SPRN_L1CSR0,r3
-       isync
-       blr
-#endif
-       mfspr   r3,SPRN_L1CSR1
-       ori     r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
-       mtspr   SPRN_L1CSR1,r3
-#elif defined(CONFIG_PPC_BOOK3S_601)
-       blr                     /* for 601, do nothing */
-#else
-       /* 603/604 processor - use invalidate-all bit in HID0 */
-       mfspr   r3,SPRN_HID0
-       ori     r3,r3,HID0_ICFI
-       mtspr   SPRN_HID0,r3
-#endif /* CONFIG_4xx */
-       isync
-       blr
-EXPORT_SYMBOL(flush_instruction_cache)
-#endif /* CONFIG_PPC_8xx */
-
 /*
  * Copy a whole page.  We use the dcbz instruction on the destination
  * to reduce memory traffic (it eliminates the unnecessary reads of
index 7bb46ad..0704658 100644 (file)
@@ -365,7 +365,6 @@ _GLOBAL(kexec_smp_wait)
 
        li      r4,KEXEC_STATE_REAL_MODE
        stb     r4,PACAKEXECSTATE(r13)
-       SYNC
 
        b       kexec_wait
 
index 73a5704..d421a2c 100644 (file)
@@ -124,10 +124,8 @@ unsigned long notrace msr_check_and_set(unsigned long bits)
 
        newmsr = oldmsr | bits;
 
-#ifdef CONFIG_VSX
        if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
                newmsr |= MSR_VSX;
-#endif
 
        if (oldmsr != newmsr)
                mtmsr_isync(newmsr);
@@ -144,10 +142,8 @@ void notrace __msr_check_and_clear(unsigned long bits)
 
        newmsr = oldmsr & ~bits;
 
-#ifdef CONFIG_VSX
        if (cpu_has_feature(CPU_FTR_VSX) && (bits & MSR_FP))
                newmsr &= ~MSR_VSX;
-#endif
 
        if (oldmsr != newmsr)
                mtmsr_isync(newmsr);
@@ -162,10 +158,8 @@ static void __giveup_fpu(struct task_struct *tsk)
        save_fpu(tsk);
        msr = tsk->thread.regs->msr;
        msr &= ~(MSR_FP|MSR_FE0|MSR_FE1);
-#ifdef CONFIG_VSX
        if (cpu_has_feature(CPU_FTR_VSX))
                msr &= ~MSR_VSX;
-#endif
        tsk->thread.regs->msr = msr;
 }
 
@@ -235,6 +229,8 @@ void enable_kernel_fp(void)
        }
 }
 EXPORT_SYMBOL(enable_kernel_fp);
+#else
+static inline void __giveup_fpu(struct task_struct *tsk) { }
 #endif /* CONFIG_PPC_FPU */
 
 #ifdef CONFIG_ALTIVEC
@@ -245,10 +241,8 @@ static void __giveup_altivec(struct task_struct *tsk)
        save_altivec(tsk);
        msr = tsk->thread.regs->msr;
        msr &= ~MSR_VEC;
-#ifdef CONFIG_VSX
        if (cpu_has_feature(CPU_FTR_VSX))
                msr &= ~MSR_VSX;
-#endif
        tsk->thread.regs->msr = msr;
 }
 
@@ -414,21 +408,14 @@ static unsigned long msr_all_available;
 
 static int __init init_msr_all_available(void)
 {
-#ifdef CONFIG_PPC_FPU
-       msr_all_available |= MSR_FP;
-#endif
-#ifdef CONFIG_ALTIVEC
+       if (IS_ENABLED(CONFIG_PPC_FPU))
+               msr_all_available |= MSR_FP;
        if (cpu_has_feature(CPU_FTR_ALTIVEC))
                msr_all_available |= MSR_VEC;
-#endif
-#ifdef CONFIG_VSX
        if (cpu_has_feature(CPU_FTR_VSX))
                msr_all_available |= MSR_VSX;
-#endif
-#ifdef CONFIG_SPE
        if (cpu_has_feature(CPU_FTR_SPE))
                msr_all_available |= MSR_SPE;
-#endif
 
        return 0;
 }
@@ -452,18 +439,12 @@ void giveup_all(struct task_struct *tsk)
 
        WARN_ON((usermsr & MSR_VSX) && !((usermsr & MSR_FP) && (usermsr & MSR_VEC)));
 
-#ifdef CONFIG_PPC_FPU
        if (usermsr & MSR_FP)
                __giveup_fpu(tsk);
-#endif
-#ifdef CONFIG_ALTIVEC
        if (usermsr & MSR_VEC)
                __giveup_altivec(tsk);
-#endif
-#ifdef CONFIG_SPE
        if (usermsr & MSR_SPE)
                __giveup_spe(tsk);
-#endif
 
        msr_check_and_clear(msr_all_available);
 }
@@ -509,19 +490,18 @@ static bool should_restore_altivec(void) { return false; }
 static void do_restore_altivec(void) { }
 #endif /* CONFIG_ALTIVEC */
 
-#ifdef CONFIG_VSX
 static bool should_restore_vsx(void)
 {
        if (cpu_has_feature(CPU_FTR_VSX))
                return true;
        return false;
 }
+#ifdef CONFIG_VSX
 static void do_restore_vsx(void)
 {
        current->thread.used_vsr = 1;
 }
 #else
-static bool should_restore_vsx(void) { return false; }
 static void do_restore_vsx(void) { }
 #endif /* CONFIG_VSX */
 
@@ -581,7 +561,7 @@ void notrace restore_math(struct pt_regs *regs)
                regs->msr |= new_msr | fpexc_mode;
        }
 }
-#endif
+#endif /* CONFIG_PPC_BOOK3S_64 */
 
 static void save_all(struct task_struct *tsk)
 {
@@ -642,6 +622,44 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
                                    (void __user *)address);
 }
 #else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
+
+static void do_break_handler(struct pt_regs *regs)
+{
+       struct arch_hw_breakpoint null_brk = {0};
+       struct arch_hw_breakpoint *info;
+       struct ppc_inst instr = ppc_inst(0);
+       int type = 0;
+       int size = 0;
+       unsigned long ea;
+       int i;
+
+       /*
+        * If underneath hw supports only one watchpoint, we know it
+        * caused exception. 8xx also falls into this category.
+        */
+       if (nr_wp_slots() == 1) {
+               __set_breakpoint(0, &null_brk);
+               current->thread.hw_brk[0] = null_brk;
+               current->thread.hw_brk[0].flags |= HW_BRK_FLAG_DISABLED;
+               return;
+       }
+
+       /* Otherwise findout which DAWR caused exception and disable it. */
+       wp_get_instr_detail(regs, &instr, &type, &size, &ea);
+
+       for (i = 0; i < nr_wp_slots(); i++) {
+               info = &current->thread.hw_brk[i];
+               if (!info->address)
+                       continue;
+
+               if (wp_check_constraints(regs, instr, ea, type, size, info)) {
+                       __set_breakpoint(i, &null_brk);
+                       current->thread.hw_brk[i] = null_brk;
+                       current->thread.hw_brk[i].flags |= HW_BRK_FLAG_DISABLED;
+               }
+       }
+}
+
 void do_break (struct pt_regs *regs, unsigned long address,
                    unsigned long error_code)
 {
@@ -653,6 +671,16 @@ void do_break (struct pt_regs *regs, unsigned long address,
        if (debugger_break_match(regs))
                return;
 
+       /*
+        * We reach here only when watchpoint exception is generated by ptrace
+        * event (or hw is buggy!). Now if CONFIG_HAVE_HW_BREAKPOINT is set,
+        * watchpoint is already handled by hw_breakpoint_handler() so we don't
+        * have to do anything. But when CONFIG_HAVE_HW_BREAKPOINT is not set,
+        * we need to manually handle the watchpoint here.
+        */
+       if (!IS_ENABLED(CONFIG_HAVE_HW_BREAKPOINT))
+               do_break_handler(regs);
+
        /* Deliver the signal to userspace */
        force_sig_fault(SIGTRAP, TRAP_HWBKPT, (void __user *)address);
 }
@@ -783,9 +811,8 @@ static void switch_hw_breakpoint(struct task_struct *new)
 static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
 {
        mtspr(SPRN_DAC1, dabr);
-#ifdef CONFIG_PPC_47x
-       isync();
-#endif
+       if (IS_ENABLED(CONFIG_PPC_47x))
+               isync();
        return 0;
 }
 #elif defined(CONFIG_PPC_BOOK3S)
@@ -1256,15 +1283,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
                restore_math(current->thread.regs);
 
                /*
-                * The copy-paste buffer can only store into foreign real
-                * addresses, so unprivileged processes can not see the
-                * data or use it in any way unless they have foreign real
-                * mappings. If the new process has the foreign real address
-                * mappings, we must issue a cp_abort to clear any state and
-                * prevent snooping, corruption or a covert channel.
+                * On POWER9 the copy-paste buffer can only paste into
+                * foreign real addresses, so unprivileged processes can not
+                * see the data or use it in any way unless they have
+                * foreign real mappings. If the new process has the foreign
+                * real address mappings, we must issue a cp_abort to clear
+                * any state and prevent snooping, corruption or a covert
+                * channel. ISA v3.1 supports paste into local memory.
                 */
                if (current->mm &&
-                       atomic_read(&current->mm->context.vas_windows))
+                       (cpu_has_feature(CPU_FTR_ARCH_31) ||
+                       atomic_read(&current->mm->context.vas_windows)))
                        asm volatile(PPC_CP_ABORT);
        }
 #endif /* CONFIG_PPC_BOOK3S_64 */
@@ -1453,12 +1482,13 @@ void show_regs(struct pt_regs * regs)
        trap = TRAP(regs);
        if (!trap_is_syscall(regs) && cpu_has_feature(CPU_FTR_CFAR))
                pr_cont("CFAR: "REG" ", regs->orig_gpr3);
-       if (trap == 0x200 || trap == 0x300 || trap == 0x600)
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-               pr_cont("DEAR: "REG" ESR: "REG" ", regs->dar, regs->dsisr);
-#else
-               pr_cont("DAR: "REG" DSISR: %08lx ", regs->dar, regs->dsisr);
-#endif
+       if (trap == 0x200 || trap == 0x300 || trap == 0x600) {
+               if (IS_ENABLED(CONFIG_4xx) || IS_ENABLED(CONFIG_BOOKE))
+                       pr_cont("DEAR: "REG" ESR: "REG" ", regs->dar, regs->dsisr);
+               else
+                       pr_cont("DAR: "REG" DSISR: %08lx ", regs->dar, regs->dsisr);
+       }
+
 #ifdef CONFIG_PPC64
        pr_cont("IRQMASK: %lx ", regs->softe);
 #endif
@@ -1475,14 +1505,14 @@ void show_regs(struct pt_regs * regs)
                        break;
        }
        pr_cont("\n");
-#ifdef CONFIG_KALLSYMS
        /*
         * Lookup NIP late so we have the best change of getting the
         * above info out without failing
         */
-       printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
-       printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
-#endif
+       if (IS_ENABLED(CONFIG_KALLSYMS)) {
+               printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
+               printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
+       }
        show_stack(current, (unsigned long *) regs->gpr[1], KERN_DEFAULT);
        if (!user_mode(regs))
                show_instructions(regs);
@@ -1731,10 +1761,8 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
 #ifdef CONFIG_PPC64
        unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */
 
-#ifdef CONFIG_PPC_BOOK3S_64
-       if (!radix_enabled())
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !radix_enabled())
                preload_new_slb_context(start, sp);
-#endif
 #endif
 
        /*
@@ -1866,7 +1894,6 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
         * fpexc_mode.  fpexc_mode is also used for setting FP exception
         * mode (asyn, precise, disabled) for 'Classic' FP. */
        if (val & PR_FP_EXC_SW_ENABLE) {
-#ifdef CONFIG_SPE
                if (cpu_has_feature(CPU_FTR_SPE)) {
                        /*
                         * When the sticky exception bits are set
@@ -1880,16 +1907,15 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
                         * anyway to restore the prctl settings from
                         * the saved environment.
                         */
+#ifdef CONFIG_SPE
                        tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR);
                        tsk->thread.fpexc_mode = val &
                                (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT);
+#endif
                        return 0;
                } else {
                        return -EINVAL;
                }
-#else
-               return -EINVAL;
-#endif
        }
 
        /* on a CONFIG_SPE this does not hurt us.  The bits that
@@ -1908,10 +1934,9 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
 
 int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
 {
-       unsigned int val;
+       unsigned int val = 0;
 
-       if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
-#ifdef CONFIG_SPE
+       if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) {
                if (cpu_has_feature(CPU_FTR_SPE)) {
                        /*
                         * When the sticky exception bits are set
@@ -1925,15 +1950,15 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
                         * anyway to restore the prctl settings from
                         * the saved environment.
                         */
+#ifdef CONFIG_SPE
                        tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR);
                        val = tsk->thread.fpexc_mode;
+#endif
                } else
                        return -EINVAL;
-#else
-               return -EINVAL;
-#endif
-       else
+       } else {
                val = __unpack_fe01(tsk->thread.fpexc_mode);
+       }
        return put_user(val, (unsigned int __user *) adr);
 }
 
@@ -2102,10 +2127,8 @@ void show_stack(struct task_struct *tsk, unsigned long *stack,
        unsigned long sp, ip, lr, newsp;
        int count = 0;
        int firstframe = 1;
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
        unsigned long ret_addr;
        int ftrace_idx = 0;
-#endif
 
        if (tsk == NULL)
                tsk = current;
@@ -2133,12 +2156,10 @@ void show_stack(struct task_struct *tsk, unsigned long *stack,
                if (!firstframe || ip != lr) {
                        printk("%s["REG"] ["REG"] %pS",
                                loglvl, sp, ip, (void *)ip);
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
                        ret_addr = ftrace_graph_ret_addr(current,
                                                &ftrace_idx, ip, stack);
                        if (ret_addr != ip)
                                pr_cont(" (%pS)", (void *)ret_addr);
-#endif
                        if (firstframe)
                                pr_cont(" (unreliable)");
                        pr_cont("\n");
index d8a2fb8..c1545f2 100644 (file)
@@ -776,6 +776,11 @@ void __init early_init_devtree(void *params)
        limit = ALIGN(memory_limit ?: memblock_phys_mem_size(), PAGE_SIZE);
        memblock_enforce_memory_limit(limit);
 
+#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_4K_PAGES)
+       if (!early_radix_enabled())
+               memblock_cap_memory_range(0, 1UL << (H_MAX_PHYSMEM_BITS));
+#endif
+
        memblock_allow_resize();
        memblock_dump_all();
 
index ae7ec99..5090a5a 100644 (file)
@@ -2422,10 +2422,19 @@ static void __init prom_check_displays(void)
                        u32 width, height, pitch, addr;
 
                        prom_printf("Setting btext !\n");
-                       prom_getprop(node, "width", &width, 4);
-                       prom_getprop(node, "height", &height, 4);
-                       prom_getprop(node, "linebytes", &pitch, 4);
-                       prom_getprop(node, "address", &addr, 4);
+
+                       if (prom_getprop(node, "width", &width, 4) == PROM_ERROR)
+                               return;
+
+                       if (prom_getprop(node, "height", &height, 4) == PROM_ERROR)
+                               return;
+
+                       if (prom_getprop(node, "linebytes", &pitch, 4) == PROM_ERROR)
+                               return;
+
+                       if (prom_getprop(node, "address", &addr, 4) == PROM_ERROR)
+                               return;
+
                        prom_printf("W=%d H=%d LB=%d addr=0x%x\n",
                                    width, height, pitch, addr);
                        btext_setup_display(width, height, 8, pitch, addr);
index 697c7e4..aa36fca 100644 (file)
@@ -57,6 +57,8 @@ void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
        } else {
                dbginfo->features = 0;
        }
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_ARCH_31;
 }
 
 int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
@@ -217,8 +219,9 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf
                return -EIO;
 
        brk.address = ALIGN_DOWN(bp_info->addr, HW_BREAKPOINT_SIZE);
-       brk.type = HW_BRK_TYPE_TRANSLATE;
+       brk.type = HW_BRK_TYPE_TRANSLATE | HW_BRK_TYPE_PRIV_ALL;
        brk.len = DABR_MAX_LEN;
+       brk.hw_len = DABR_MAX_LEN;
        if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
                brk.type |= HW_BRK_TYPE_READ;
        if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
@@ -286,11 +289,13 @@ long ppc_del_hwdebug(struct task_struct *child, long data)
        }
        return ret;
 #else /* CONFIG_HAVE_HW_BREAKPOINT */
-       if (child->thread.hw_brk[data - 1].address == 0)
+       if (!(child->thread.hw_brk[data - 1].flags & HW_BRK_FLAG_DISABLED) &&
+           child->thread.hw_brk[data - 1].address == 0)
                return -ENOENT;
 
        child->thread.hw_brk[data - 1].address = 0;
        child->thread.hw_brk[data - 1].type = 0;
+       child->thread.hw_brk[data - 1].flags = 0;
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
        return 0;
index 806d554..954f416 100644 (file)
@@ -992,6 +992,147 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
        return NULL;
 }
 
+#ifdef CONFIG_PPC_RTAS_FILTER
+
+/*
+ * The sys_rtas syscall, as originally designed, allows root to pass
+ * arbitrary physical addresses to RTAS calls. A number of RTAS calls
+ * can be abused to write to arbitrary memory and do other things that
+ * are potentially harmful to system integrity, and thus should only
+ * be used inside the kernel and not exposed to userspace.
+ *
+ * All known legitimate users of the sys_rtas syscall will only ever
+ * pass addresses that fall within the RMO buffer, and use a known
+ * subset of RTAS calls.
+ *
+ * Accordingly, we filter RTAS requests to check that the call is
+ * permitted, and that provided pointers fall within the RMO buffer.
+ * The rtas_filters list contains an entry for each permitted call,
+ * with the indexes of the parameters which are expected to contain
+ * addresses and sizes of buffers allocated inside the RMO buffer.
+ */
+struct rtas_filter {
+       const char *name;
+       int token;
+       /* Indexes into the args buffer, -1 if not used */
+       int buf_idx1;
+       int size_idx1;
+       int buf_idx2;
+       int size_idx2;
+
+       int fixed_size;
+};
+
+static struct rtas_filter rtas_filters[] __ro_after_init = {
+       { "ibm,activate-firmware", -1, -1, -1, -1, -1 },
+       { "ibm,configure-connector", -1, 0, -1, 1, -1, 4096 },  /* Special cased */
+       { "display-character", -1, -1, -1, -1, -1 },
+       { "ibm,display-message", -1, 0, -1, -1, -1 },
+       { "ibm,errinjct", -1, 2, -1, -1, -1, 1024 },
+       { "ibm,close-errinjct", -1, -1, -1, -1, -1 },
+       { "ibm,open-errinct", -1, -1, -1, -1, -1 },
+       { "ibm,get-config-addr-info2", -1, -1, -1, -1, -1 },
+       { "ibm,get-dynamic-sensor-state", -1, 1, -1, -1, -1 },
+       { "ibm,get-indices", -1, 2, 3, -1, -1 },
+       { "get-power-level", -1, -1, -1, -1, -1 },
+       { "get-sensor-state", -1, -1, -1, -1, -1 },
+       { "ibm,get-system-parameter", -1, 1, 2, -1, -1 },
+       { "get-time-of-day", -1, -1, -1, -1, -1 },
+       { "ibm,get-vpd", -1, 0, -1, 1, 2 },
+       { "ibm,lpar-perftools", -1, 2, 3, -1, -1 },
+       { "ibm,platform-dump", -1, 4, 5, -1, -1 },
+       { "ibm,read-slot-reset-state", -1, -1, -1, -1, -1 },
+       { "ibm,scan-log-dump", -1, 0, 1, -1, -1 },
+       { "ibm,set-dynamic-indicator", -1, 2, -1, -1, -1 },
+       { "ibm,set-eeh-option", -1, -1, -1, -1, -1 },
+       { "set-indicator", -1, -1, -1, -1, -1 },
+       { "set-power-level", -1, -1, -1, -1, -1 },
+       { "set-time-for-power-on", -1, -1, -1, -1, -1 },
+       { "ibm,set-system-parameter", -1, 1, -1, -1, -1 },
+       { "set-time-of-day", -1, -1, -1, -1, -1 },
+       { "ibm,suspend-me", -1, -1, -1, -1, -1 },
+       { "ibm,update-nodes", -1, 0, -1, -1, -1, 4096 },
+       { "ibm,update-properties", -1, 0, -1, -1, -1, 4096 },
+       { "ibm,physical-attestation", -1, 0, 1, -1, -1 },
+};
+
+static bool in_rmo_buf(u32 base, u32 end)
+{
+       return base >= rtas_rmo_buf &&
+               base < (rtas_rmo_buf + RTAS_RMOBUF_MAX) &&
+               base <= end &&
+               end >= rtas_rmo_buf &&
+               end < (rtas_rmo_buf + RTAS_RMOBUF_MAX);
+}
+
+static bool block_rtas_call(int token, int nargs,
+                           struct rtas_args *args)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
+               struct rtas_filter *f = &rtas_filters[i];
+               u32 base, size, end;
+
+               if (token != f->token)
+                       continue;
+
+               if (f->buf_idx1 != -1) {
+                       base = be32_to_cpu(args->args[f->buf_idx1]);
+                       if (f->size_idx1 != -1)
+                               size = be32_to_cpu(args->args[f->size_idx1]);
+                       else if (f->fixed_size)
+                               size = f->fixed_size;
+                       else
+                               size = 1;
+
+                       end = base + size - 1;
+                       if (!in_rmo_buf(base, end))
+                               goto err;
+               }
+
+               if (f->buf_idx2 != -1) {
+                       base = be32_to_cpu(args->args[f->buf_idx2]);
+                       if (f->size_idx2 != -1)
+                               size = be32_to_cpu(args->args[f->size_idx2]);
+                       else if (f->fixed_size)
+                               size = f->fixed_size;
+                       else
+                               size = 1;
+                       end = base + size - 1;
+
+                       /*
+                        * Special case for ibm,configure-connector where the
+                        * address can be 0
+                        */
+                       if (!strcmp(f->name, "ibm,configure-connector") &&
+                           base == 0)
+                               return false;
+
+                       if (!in_rmo_buf(base, end))
+                               goto err;
+               }
+
+               return false;
+       }
+
+err:
+       pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n");
+       pr_err_ratelimited("sys_rtas: token=0x%x, nargs=%d (called by %s)\n",
+                          token, nargs, current->comm);
+       return true;
+}
+
+#else
+
+static bool block_rtas_call(int token, int nargs,
+                           struct rtas_args *args)
+{
+       return false;
+}
+
+#endif /* CONFIG_PPC_RTAS_FILTER */
+
 /* We assume to be passed big endian arguments */
 SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
 {
@@ -1029,6 +1170,9 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
        args.rets = &args.args[nargs];
        memset(args.rets, 0, nret * sizeof(rtas_arg_t));
 
+       if (block_rtas_call(token, nargs, &args))
+               return -EINVAL;
+
        /* Need to handle ibm,suspend_me call specially */
        if (token == ibm_suspend_me_token) {
 
@@ -1090,6 +1234,9 @@ void __init rtas_initialize(void)
        unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
        u32 base, size, entry;
        int no_base, no_size, no_entry;
+#ifdef CONFIG_PPC_RTAS_FILTER
+       int i;
+#endif
 
        /* Get RTAS dev node and fill up our "rtas" structure with infos
         * about it.
@@ -1129,6 +1276,12 @@ void __init rtas_initialize(void)
 #ifdef CONFIG_RTAS_ERROR_LOGGING
        rtas_last_error_token = rtas_token("rtas-last-error");
 #endif
+
+#ifdef CONFIG_PPC_RTAS_FILTER
+       for (i = 0; i < ARRAY_SIZE(rtas_filters); i++) {
+               rtas_filters[i].token = rtas_token(rtas_filters[i].name);
+       }
+#endif
 }
 
 int __init early_init_dt_scan_rtas(unsigned long node,
index c9876aa..e4e1a94 100644 (file)
@@ -430,30 +430,44 @@ device_initcall(stf_barrier_debugfs_init);
 
 static void update_branch_cache_flush(void)
 {
+       u32 *site;
+
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       site = &patch__call_kvm_flush_link_stack;
        // This controls the branch from guest_exit_cont to kvm_flush_link_stack
        if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
-               patch_instruction_site(&patch__call_kvm_flush_link_stack,
-                                      ppc_inst(PPC_INST_NOP));
+               patch_instruction_site(site, ppc_inst(PPC_INST_NOP));
        } else {
                // Could use HW flush, but that could also flush count cache
-               patch_branch_site(&patch__call_kvm_flush_link_stack,
-                                 (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
+               patch_branch_site(site, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
        }
 #endif
 
+       // Patch out the bcctr first, then nop the rest
+       site = &patch__call_flush_branch_caches3;
+       patch_instruction_site(site, ppc_inst(PPC_INST_NOP));
+       site = &patch__call_flush_branch_caches2;
+       patch_instruction_site(site, ppc_inst(PPC_INST_NOP));
+       site = &patch__call_flush_branch_caches1;
+       patch_instruction_site(site, ppc_inst(PPC_INST_NOP));
+
        // This controls the branch from _switch to flush_branch_caches
        if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE &&
            link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
-               patch_instruction_site(&patch__call_flush_branch_caches,
-                                      ppc_inst(PPC_INST_NOP));
+               // Nothing to be done
+
        } else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW &&
                   link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) {
-               patch_instruction_site(&patch__call_flush_branch_caches,
-                                      ppc_inst(PPC_INST_BCCTR_FLUSH));
+               // Patch in the bcctr last
+               site = &patch__call_flush_branch_caches1;
+               patch_instruction_site(site, ppc_inst(0x39207fff)); // li r9,0x7fff
+               site = &patch__call_flush_branch_caches2;
+               patch_instruction_site(site, ppc_inst(0x7d2903a6)); // mtctr r9
+               site = &patch__call_flush_branch_caches3;
+               patch_instruction_site(site, ppc_inst(PPC_INST_BCCTR_FLUSH));
+
        } else {
-               patch_branch_site(&patch__call_flush_branch_caches,
-                                 (u64)&flush_branch_caches, BRANCH_SET_LINK);
+               patch_branch_site(site, (u64)&flush_branch_caches, BRANCH_SET_LINK);
 
                // If we just need to flush the link stack, early return
                if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE) {
index 1823706..057d6b8 100644 (file)
@@ -223,6 +223,6 @@ __init void initialize_cache_info(void)
        dcache_bsize = cur_cpu_spec->dcache_bsize;
        icache_bsize = cur_cpu_spec->icache_bsize;
        ucache_bsize = 0;
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601) || IS_ENABLED(CONFIG_E200))
+       if (IS_ENABLED(CONFIG_E200))
                ucache_bsize = icache_bsize = dcache_bsize;
 }
index 6be4301..bb9cab3 100644 (file)
@@ -66,6 +66,7 @@
 #include <asm/feature-fixups.h>
 #include <asm/kup.h>
 #include <asm/early_ioremap.h>
+#include <asm/pgalloc.h>
 
 #include "setup.h"
 
@@ -756,17 +757,46 @@ void __init emergency_stack_init(void)
 }
 
 #ifdef CONFIG_SMP
-#define PCPU_DYN_SIZE          ()
-
-static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
+/**
+ * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu
+ * @cpu: cpu to allocate for
+ * @size: size allocation in bytes
+ * @align: alignment
+ *
+ * Allocate @size bytes aligned at @align for cpu @cpu.  This wrapper
+ * does the right thing for NUMA regardless of the current
+ * configuration.
+ *
+ * RETURNS:
+ * Pointer to the allocated area on success, NULL on failure.
+ */
+static void * __init pcpu_alloc_bootmem(unsigned int cpu, size_t size,
+                                       size_t align)
 {
-       return memblock_alloc_try_nid(size, align, __pa(MAX_DMA_ADDRESS),
-                                     MEMBLOCK_ALLOC_ACCESSIBLE,
-                                     early_cpu_to_node(cpu));
+       const unsigned long goal = __pa(MAX_DMA_ADDRESS);
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+       int node = early_cpu_to_node(cpu);
+       void *ptr;
 
+       if (!node_online(node) || !NODE_DATA(node)) {
+               ptr = memblock_alloc_from(size, align, goal);
+               pr_info("cpu %d has no node %d or node-local memory\n",
+                       cpu, node);
+               pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n",
+                        cpu, size, __pa(ptr));
+       } else {
+               ptr = memblock_alloc_try_nid(size, align, goal,
+                                            MEMBLOCK_ALLOC_ACCESSIBLE, node);
+               pr_debug("per cpu data for cpu%d %lu bytes on node%d at "
+                        "%016lx\n", cpu, size, node, __pa(ptr));
+       }
+       return ptr;
+#else
+       return memblock_alloc_from(size, align, goal);
+#endif
 }
 
-static void __init pcpu_fc_free(void *ptr, size_t size)
+static void __init pcpu_free_bootmem(void *ptr, size_t size)
 {
        memblock_free(__pa(ptr), size);
 }
@@ -782,13 +812,58 @@ static int pcpu_cpu_distance(unsigned int from, unsigned int to)
 unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(__per_cpu_offset);
 
+static void __init pcpu_populate_pte(unsigned long addr)
+{
+       pgd_t *pgd = pgd_offset_k(addr);
+       p4d_t *p4d;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       p4d = p4d_offset(pgd, addr);
+       if (p4d_none(*p4d)) {
+               pud_t *new;
+
+               new = memblock_alloc(PUD_TABLE_SIZE, PUD_TABLE_SIZE);
+               if (!new)
+                       goto err_alloc;
+               p4d_populate(&init_mm, p4d, new);
+       }
+
+       pud = pud_offset(p4d, addr);
+       if (pud_none(*pud)) {
+               pmd_t *new;
+
+               new = memblock_alloc(PMD_TABLE_SIZE, PMD_TABLE_SIZE);
+               if (!new)
+                       goto err_alloc;
+               pud_populate(&init_mm, pud, new);
+       }
+
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd)) {
+               pte_t *new;
+
+               new = memblock_alloc(PTE_TABLE_SIZE, PTE_TABLE_SIZE);
+               if (!new)
+                       goto err_alloc;
+               pmd_populate_kernel(&init_mm, pmd, new);
+       }
+
+       return;
+
+err_alloc:
+       panic("%s: Failed to allocate %lu bytes align=%lx from=%lx\n",
+             __func__, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+}
+
+
 void __init setup_per_cpu_areas(void)
 {
        const size_t dyn_size = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
        size_t atom_size;
        unsigned long delta;
        unsigned int cpu;
-       int rc;
+       int rc = -EINVAL;
 
        /*
         * Linear mapping is one of 4K, 1M and 16M.  For 4K, no need
@@ -800,8 +875,18 @@ void __init setup_per_cpu_areas(void)
        else
                atom_size = 1 << 20;
 
-       rc = pcpu_embed_first_chunk(0, dyn_size, atom_size, pcpu_cpu_distance,
-                                   pcpu_fc_alloc, pcpu_fc_free);
+       if (pcpu_chosen_fc != PCPU_FC_PAGE) {
+               rc = pcpu_embed_first_chunk(0, dyn_size, atom_size, pcpu_cpu_distance,
+                                           pcpu_alloc_bootmem, pcpu_free_bootmem);
+               if (rc)
+                       pr_warn("PERCPU: %s allocator failed (%d), "
+                               "falling back to page size\n",
+                               pcpu_fc_names[pcpu_chosen_fc], rc);
+       }
+
+       if (rc < 0)
+               rc = pcpu_page_first_chunk(0, pcpu_alloc_bootmem, pcpu_free_bootmem,
+                                          pcpu_populate_pte);
        if (rc < 0)
                panic("cannot initialize percpu area (err=%d)", rc);
 
index 8261999..0dc1b85 100644 (file)
@@ -75,17 +75,28 @@ static DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
 struct task_struct *secondary_current;
 bool has_big_cores;
+bool coregroup_enabled;
 
 DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map);
 DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_map);
 DEFINE_PER_CPU(cpumask_var_t, cpu_l2_cache_map);
 DEFINE_PER_CPU(cpumask_var_t, cpu_core_map);
+DEFINE_PER_CPU(cpumask_var_t, cpu_coregroup_map);
 
 EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
 EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map);
 EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 EXPORT_SYMBOL_GPL(has_big_cores);
 
+enum {
+#ifdef CONFIG_SCHED_SMT
+       smt_idx,
+#endif
+       cache_idx,
+       mc_idx,
+       die_idx,
+};
+
 #define MAX_THREAD_LIST_SIZE   8
 #define THREAD_GROUP_SHARE_L1   1
 struct thread_groups {
@@ -659,6 +670,28 @@ static void set_cpus_unrelated(int i, int j,
 }
 #endif
 
+/*
+ * Extends set_cpus_related. Instead of setting one CPU at a time in
+ * dstmask, set srcmask at oneshot. dstmask should be super set of srcmask.
+ */
+static void or_cpumasks_related(int i, int j, struct cpumask *(*srcmask)(int),
+                               struct cpumask *(*dstmask)(int))
+{
+       struct cpumask *mask;
+       int k;
+
+       mask = srcmask(j);
+       for_each_cpu(k, srcmask(i))
+               cpumask_or(dstmask(k), dstmask(k), mask);
+
+       if (i == j)
+               return;
+
+       mask = srcmask(i);
+       for_each_cpu(k, srcmask(j))
+               cpumask_or(dstmask(k), dstmask(k), mask);
+}
+
 /*
  * parse_thread_groups: Parses the "ibm,thread-groups" device tree
  *                      property for the CPU device node @dn and stores
@@ -789,10 +822,6 @@ static int init_cpu_l1_cache_map(int cpu)
        if (err)
                goto out;
 
-       zalloc_cpumask_var_node(&per_cpu(cpu_l1_cache_map, cpu),
-                               GFP_KERNEL,
-                               cpu_to_node(cpu));
-
        cpu_group_start = get_cpu_thread_group_start(cpu, &tg);
 
        if (unlikely(cpu_group_start == -1)) {
@@ -801,6 +830,9 @@ static int init_cpu_l1_cache_map(int cpu)
                goto out;
        }
 
+       zalloc_cpumask_var_node(&per_cpu(cpu_l1_cache_map, cpu),
+                               GFP_KERNEL, cpu_to_node(cpu));
+
        for (i = first_thread; i < first_thread + threads_per_core; i++) {
                int i_group_start = get_cpu_thread_group_start(i, &tg);
 
@@ -819,6 +851,74 @@ out:
        return err;
 }
 
+static bool shared_caches;
+
+#ifdef CONFIG_SCHED_SMT
+/* cpumask of CPUs with asymmetric SMT dependency */
+static int powerpc_smt_flags(void)
+{
+       int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES;
+
+       if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
+               printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
+               flags |= SD_ASYM_PACKING;
+       }
+       return flags;
+}
+#endif
+
+/*
+ * P9 has a slightly odd architecture where pairs of cores share an L2 cache.
+ * This topology makes it *much* cheaper to migrate tasks between adjacent cores
+ * since the migrated task remains cache hot. We want to take advantage of this
+ * at the scheduler level so an extra topology level is required.
+ */
+static int powerpc_shared_cache_flags(void)
+{
+       return SD_SHARE_PKG_RESOURCES;
+}
+
+/*
+ * We can't just pass cpu_l2_cache_mask() directly because
+ * returns a non-const pointer and the compiler barfs on that.
+ */
+static const struct cpumask *shared_cache_mask(int cpu)
+{
+       return per_cpu(cpu_l2_cache_map, cpu);
+}
+
+#ifdef CONFIG_SCHED_SMT
+static const struct cpumask *smallcore_smt_mask(int cpu)
+{
+       return cpu_smallcore_mask(cpu);
+}
+#endif
+
+static struct cpumask *cpu_coregroup_mask(int cpu)
+{
+       return per_cpu(cpu_coregroup_map, cpu);
+}
+
+static bool has_coregroup_support(void)
+{
+       return coregroup_enabled;
+}
+
+static const struct cpumask *cpu_mc_mask(int cpu)
+{
+       return cpu_coregroup_mask(cpu);
+}
+
+static struct sched_domain_topology_level powerpc_topology[] = {
+#ifdef CONFIG_SCHED_SMT
+       { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) },
+#endif
+       { shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) },
+       { cpu_mc_mask, SD_INIT_NAME(MC) },
+       { cpu_cpu_mask, SD_INIT_NAME(DIE) },
+       { NULL, },
+};
+
 static int init_big_cores(void)
 {
        int cpu;
@@ -861,6 +961,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                                        GFP_KERNEL, cpu_to_node(cpu));
                zalloc_cpumask_var_node(&per_cpu(cpu_core_map, cpu),
                                        GFP_KERNEL, cpu_to_node(cpu));
+               if (has_coregroup_support())
+                       zalloc_cpumask_var_node(&per_cpu(cpu_coregroup_map, cpu),
+                                               GFP_KERNEL, cpu_to_node(cpu));
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
                /*
                 * numa_node_id() works after this.
                 */
@@ -869,12 +974,21 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                        set_cpu_numa_mem(cpu,
                                local_memory_node(numa_cpu_lookup_table[cpu]));
                }
+#endif
+               /*
+                * cpu_core_map is now more updated and exists only since
+                * its been exported for long. It only will have a snapshot
+                * of cpu_cpu_mask.
+                */
+               cpumask_copy(per_cpu(cpu_core_map, cpu), cpu_cpu_mask(cpu));
        }
 
        /* Init the cpumasks so the boot CPU is related to itself */
        cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid));
        cpumask_set_cpu(boot_cpuid, cpu_l2_cache_mask(boot_cpuid));
-       cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid));
+
+       if (has_coregroup_support())
+               cpumask_set_cpu(boot_cpuid, cpu_coregroup_mask(boot_cpuid));
 
        init_big_cores();
        if (has_big_cores) {
@@ -1126,30 +1240,61 @@ static struct device_node *cpu_to_l2cache(int cpu)
        return cache;
 }
 
-static bool update_mask_by_l2(int cpu, struct cpumask *(*mask_fn)(int))
+static bool update_mask_by_l2(int cpu)
 {
+       struct cpumask *(*submask_fn)(int) = cpu_sibling_mask;
        struct device_node *l2_cache, *np;
+       cpumask_var_t mask;
        int i;
 
        l2_cache = cpu_to_l2cache(cpu);
-       if (!l2_cache)
+       if (!l2_cache) {
+               struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask;
+
+               /*
+                * If no l2cache for this CPU, assume all siblings to share
+                * cache with this CPU.
+                */
+               if (has_big_cores)
+                       sibling_mask = cpu_smallcore_mask;
+
+               for_each_cpu(i, sibling_mask(cpu))
+                       set_cpus_related(cpu, i, cpu_l2_cache_mask);
+
                return false;
+       }
+
+       alloc_cpumask_var_node(&mask, GFP_KERNEL, cpu_to_node(cpu));
+       cpumask_and(mask, cpu_online_mask, cpu_cpu_mask(cpu));
 
-       for_each_cpu(i, cpu_online_mask) {
+       if (has_big_cores)
+               submask_fn = cpu_smallcore_mask;
+
+       /* Update l2-cache mask with all the CPUs that are part of submask */
+       or_cpumasks_related(cpu, cpu, submask_fn, cpu_l2_cache_mask);
+
+       /* Skip all CPUs already part of current CPU l2-cache mask */
+       cpumask_andnot(mask, mask, cpu_l2_cache_mask(cpu));
+
+       for_each_cpu(i, mask) {
                /*
                 * when updating the marks the current CPU has not been marked
                 * online, but we need to update the cache masks
                 */
                np = cpu_to_l2cache(i);
-               if (!np)
-                       continue;
 
-               if (np == l2_cache)
-                       set_cpus_related(cpu, i, mask_fn);
+               /* Skip all CPUs already part of current CPU l2-cache */
+               if (np == l2_cache) {
+                       or_cpumasks_related(cpu, i, submask_fn, cpu_l2_cache_mask);
+                       cpumask_andnot(mask, mask, submask_fn(i));
+               } else {
+                       cpumask_andnot(mask, mask, cpu_l2_cache_mask(i));
+               }
 
                of_node_put(np);
        }
        of_node_put(l2_cache);
+       free_cpumask_var(mask);
 
        return true;
 }
@@ -1157,59 +1302,75 @@ static bool update_mask_by_l2(int cpu, struct cpumask *(*mask_fn)(int))
 #ifdef CONFIG_HOTPLUG_CPU
 static void remove_cpu_from_masks(int cpu)
 {
+       struct cpumask *(*mask_fn)(int) = cpu_sibling_mask;
        int i;
 
-       /* NB: cpu_core_mask is a superset of the others */
-       for_each_cpu(i, cpu_core_mask(cpu)) {
-               set_cpus_unrelated(cpu, i, cpu_core_mask);
+       if (shared_caches)
+               mask_fn = cpu_l2_cache_mask;
+
+       for_each_cpu(i, mask_fn(cpu)) {
                set_cpus_unrelated(cpu, i, cpu_l2_cache_mask);
                set_cpus_unrelated(cpu, i, cpu_sibling_mask);
                if (has_big_cores)
                        set_cpus_unrelated(cpu, i, cpu_smallcore_mask);
        }
+
+       if (has_coregroup_support()) {
+               for_each_cpu(i, cpu_coregroup_mask(cpu))
+                       set_cpus_unrelated(cpu, i, cpu_coregroup_mask);
+       }
 }
 #endif
 
 static inline void add_cpu_to_smallcore_masks(int cpu)
 {
-       struct cpumask *this_l1_cache_map = per_cpu(cpu_l1_cache_map, cpu);
-       int i, first_thread = cpu_first_thread_sibling(cpu);
+       int i;
 
        if (!has_big_cores)
                return;
 
        cpumask_set_cpu(cpu, cpu_smallcore_mask(cpu));
 
-       for (i = first_thread; i < first_thread + threads_per_core; i++) {
-               if (cpu_online(i) && cpumask_test_cpu(i, this_l1_cache_map))
+       for_each_cpu(i, per_cpu(cpu_l1_cache_map, cpu)) {
+               if (cpu_online(i))
                        set_cpus_related(i, cpu, cpu_smallcore_mask);
        }
 }
 
-int get_physical_package_id(int cpu)
+static void update_coregroup_mask(int cpu)
 {
-       int pkg_id = cpu_to_chip_id(cpu);
+       struct cpumask *(*submask_fn)(int) = cpu_sibling_mask;
+       cpumask_var_t mask;
+       int coregroup_id = cpu_to_coregroup_id(cpu);
+       int i;
 
-       /*
-        * If the platform is PowerNV or Guest on KVM, ibm,chip-id is
-        * defined. Hence we would return the chip-id as the result of
-        * get_physical_package_id.
-        */
-       if (pkg_id == -1 && firmware_has_feature(FW_FEATURE_LPAR) &&
-           IS_ENABLED(CONFIG_PPC_SPLPAR)) {
-               struct device_node *np = of_get_cpu_node(cpu, NULL);
-               pkg_id = of_node_to_nid(np);
-               of_node_put(np);
-       }
+       alloc_cpumask_var_node(&mask, GFP_KERNEL, cpu_to_node(cpu));
+       cpumask_and(mask, cpu_online_mask, cpu_cpu_mask(cpu));
+
+       if (shared_caches)
+               submask_fn = cpu_l2_cache_mask;
 
-       return pkg_id;
+       /* Update coregroup mask with all the CPUs that are part of submask */
+       or_cpumasks_related(cpu, cpu, submask_fn, cpu_coregroup_mask);
+
+       /* Skip all CPUs already part of coregroup mask */
+       cpumask_andnot(mask, mask, cpu_coregroup_mask(cpu));
+
+       for_each_cpu(i, mask) {
+               /* Skip all CPUs not part of this coregroup */
+               if (coregroup_id == cpu_to_coregroup_id(i)) {
+                       or_cpumasks_related(cpu, i, submask_fn, cpu_coregroup_mask);
+                       cpumask_andnot(mask, mask, submask_fn(i));
+               } else {
+                       cpumask_andnot(mask, mask, cpu_coregroup_mask(i));
+               }
+       }
+       free_cpumask_var(mask);
 }
-EXPORT_SYMBOL_GPL(get_physical_package_id);
 
 static void add_cpu_to_masks(int cpu)
 {
        int first_thread = cpu_first_thread_sibling(cpu);
-       int pkg_id = get_physical_package_id(cpu);
        int i;
 
        /*
@@ -1223,36 +1384,16 @@ static void add_cpu_to_masks(int cpu)
                        set_cpus_related(i, cpu, cpu_sibling_mask);
 
        add_cpu_to_smallcore_masks(cpu);
-       /*
-        * Copy the thread sibling mask into the cache sibling mask
-        * and mark any CPUs that share an L2 with this CPU.
-        */
-       for_each_cpu(i, cpu_sibling_mask(cpu))
-               set_cpus_related(cpu, i, cpu_l2_cache_mask);
-       update_mask_by_l2(cpu, cpu_l2_cache_mask);
+       update_mask_by_l2(cpu);
 
-       /*
-        * Copy the cache sibling mask into core sibling mask and mark
-        * any CPUs on the same chip as this CPU.
-        */
-       for_each_cpu(i, cpu_l2_cache_mask(cpu))
-               set_cpus_related(cpu, i, cpu_core_mask);
-
-       if (pkg_id == -1)
-               return;
-
-       for_each_cpu(i, cpu_online_mask)
-               if (get_physical_package_id(i) == pkg_id)
-                       set_cpus_related(cpu, i, cpu_core_mask);
+       if (has_coregroup_support())
+               update_coregroup_mask(cpu);
 }
 
-static bool shared_caches;
-
 /* Activate a secondary processor. */
 void start_secondary(void *unused)
 {
        unsigned int cpu = smp_processor_id();
-       struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask;
 
        mmgrab(&init_mm);
        current->active_mm = &init_mm;
@@ -1278,14 +1419,20 @@ void start_secondary(void *unused)
        /* Update topology CPU masks */
        add_cpu_to_masks(cpu);
 
-       if (has_big_cores)
-               sibling_mask = cpu_smallcore_mask;
        /*
         * Check for any shared caches. Note that this must be done on a
         * per-core basis because one core in the pair might be disabled.
         */
-       if (!cpumask_equal(cpu_l2_cache_mask(cpu), sibling_mask(cpu)))
-               shared_caches = true;
+       if (!shared_caches) {
+               struct cpumask *(*sibling_mask)(int) = cpu_sibling_mask;
+               struct cpumask *mask = cpu_l2_cache_mask(cpu);
+
+               if (has_big_cores)
+                       sibling_mask = cpu_smallcore_mask;
+
+               if (cpumask_weight(mask) > cpumask_weight(sibling_mask(cpu)))
+                       shared_caches = true;
+       }
 
        set_numa_node(numa_cpu_lookup_table[cpu]);
        set_numa_mem(local_memory_node(numa_cpu_lookup_table[cpu]));
@@ -1311,63 +1458,44 @@ int setup_profiling_timer(unsigned int multiplier)
        return 0;
 }
 
-#ifdef CONFIG_SCHED_SMT
-/* cpumask of CPUs with asymetric SMT dependancy */
-static int powerpc_smt_flags(void)
+static void fixup_topology(void)
 {
-       int flags = SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES;
+       int i;
 
-       if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
-               printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
-               flags |= SD_ASYM_PACKING;
+#ifdef CONFIG_SCHED_SMT
+       if (has_big_cores) {
+               pr_info("Big cores detected but using small core scheduling\n");
+               powerpc_topology[smt_idx].mask = smallcore_smt_mask;
        }
-       return flags;
-}
 #endif
 
-static struct sched_domain_topology_level powerpc_topology[] = {
-#ifdef CONFIG_SCHED_SMT
-       { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) },
-#endif
-       { cpu_cpu_mask, SD_INIT_NAME(DIE) },
-       { NULL, },
-};
+       if (!has_coregroup_support())
+               powerpc_topology[mc_idx].mask = powerpc_topology[cache_idx].mask;
 
-/*
- * P9 has a slightly odd architecture where pairs of cores share an L2 cache.
- * This topology makes it *much* cheaper to migrate tasks between adjacent cores
- * since the migrated task remains cache hot. We want to take advantage of this
- * at the scheduler level so an extra topology level is required.
- */
-static int powerpc_shared_cache_flags(void)
-{
-       return SD_SHARE_PKG_RESOURCES;
-}
+       /*
+        * Try to consolidate topology levels here instead of
+        * allowing scheduler to degenerate.
+        * - Dont consolidate if masks are different.
+        * - Dont consolidate if sd_flags exists and are different.
+        */
+       for (i = 1; i <= die_idx; i++) {
+               if (powerpc_topology[i].mask != powerpc_topology[i - 1].mask)
+                       continue;
 
-/*
- * We can't just pass cpu_l2_cache_mask() directly because
- * returns a non-const pointer and the compiler barfs on that.
- */
-static const struct cpumask *shared_cache_mask(int cpu)
-{
-       return cpu_l2_cache_mask(cpu);
-}
+               if (powerpc_topology[i].sd_flags && powerpc_topology[i - 1].sd_flags &&
+                               powerpc_topology[i].sd_flags != powerpc_topology[i - 1].sd_flags)
+                       continue;
 
-#ifdef CONFIG_SCHED_SMT
-static const struct cpumask *smallcore_smt_mask(int cpu)
-{
-       return cpu_smallcore_mask(cpu);
-}
-#endif
+               if (!powerpc_topology[i - 1].sd_flags)
+                       powerpc_topology[i - 1].sd_flags = powerpc_topology[i].sd_flags;
 
-static struct sched_domain_topology_level power9_topology[] = {
-#ifdef CONFIG_SCHED_SMT
-       { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) },
+               powerpc_topology[i].mask = powerpc_topology[i + 1].mask;
+               powerpc_topology[i].sd_flags = powerpc_topology[i + 1].sd_flags;
+#ifdef CONFIG_SCHED_DEBUG
+               powerpc_topology[i].name = powerpc_topology[i + 1].name;
 #endif
-       { shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) },
-       { cpu_cpu_mask, SD_INIT_NAME(DIE) },
-       { NULL, },
-};
+       }
+}
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
@@ -1382,24 +1510,8 @@ void __init smp_cpus_done(unsigned int max_cpus)
 
        dump_numa_cpu_topology();
 
-#ifdef CONFIG_SCHED_SMT
-       if (has_big_cores) {
-               pr_info("Big cores detected but using small core scheduling\n");
-               power9_topology[0].mask = smallcore_smt_mask;
-               powerpc_topology[0].mask = smallcore_smt_mask;
-       }
-#endif
-       /*
-        * If any CPU detects that it's sharing a cache with another CPU then
-        * use the deeper topology that is aware of this sharing.
-        */
-       if (shared_caches) {
-               pr_info("Using shared cache scheduler topology\n");
-               set_sched_topology(power9_topology);
-       } else {
-               pr_info("Using standard scheduler topology\n");
-               set_sched_topology(powerpc_topology);
-       }
+       fixup_topology();
+       set_sched_topology(powerpc_topology);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1429,16 +1541,18 @@ void __cpu_die(unsigned int cpu)
                smp_ops->cpu_die(cpu);
 }
 
-void cpu_die(void)
+void arch_cpu_idle_dead(void)
 {
+       sched_preempt_enable_no_resched();
+
        /*
         * Disable on the down path. This will be re-enabled by
         * start_secondary() via start_secondary_resume() below
         */
        this_cpu_disable_ftrace();
 
-       if (ppc_md.cpu_die)
-               ppc_md.cpu_die();
+       if (smp_ops->cpu_offline_self)
+               smp_ops->cpu_offline_self();
 
        /* If we return, we re-enter start_secondary */
        start_secondary_resume();
index 46b4ebc..2e08640 100644 (file)
 
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
-/*
- * SMT snooze delay stuff, 64-bit only for now
- */
-
 #ifdef CONFIG_PPC64
 
-/* Time in microseconds we delay before sleeping in the idle loop */
-static DEFINE_PER_CPU(long, smt_snooze_delay) = { 100 };
+/*
+ * Snooze delay has not been hooked up since 3fa8cad82b94 ("powerpc/pseries/cpuidle:
+ * smt-snooze-delay cleanup.") and has been broken even longer. As was foretold in
+ * 2014:
+ *
+ *  "ppc64_util currently utilises it. Once we fix ppc64_util, propose to clean
+ *  up the kernel code."
+ *
+ * powerpc-utils stopped using it as of 1.3.8. At some point in the future this
+ * code should be removed.
+ */
 
 static ssize_t store_smt_snooze_delay(struct device *dev,
                                      struct device_attribute *attr,
                                      const char *buf,
                                      size_t count)
 {
-       struct cpu *cpu = container_of(dev, struct cpu, dev);
-       ssize_t ret;
-       long snooze;
-
-       ret = sscanf(buf, "%ld", &snooze);
-       if (ret != 1)
-               return -EINVAL;
-
-       per_cpu(smt_snooze_delay, cpu->dev.id) = snooze;
+       pr_warn_once("%s (%d) stored to unsupported smt_snooze_delay, which has no effect.\n",
+                    current->comm, current->pid);
        return count;
 }
 
@@ -62,9 +60,9 @@ static ssize_t show_smt_snooze_delay(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
 {
-       struct cpu *cpu = container_of(dev, struct cpu, dev);
-
-       return sprintf(buf, "%ld\n", per_cpu(smt_snooze_delay, cpu->dev.id));
+       pr_warn_once("%s (%d) read from unsupported smt_snooze_delay\n",
+                    current->comm, current->pid);
+       return sprintf(buf, "100\n");
 }
 
 static DEVICE_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay,
@@ -72,16 +70,10 @@ static DEVICE_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay,
 
 static int __init setup_smt_snooze_delay(char *str)
 {
-       unsigned int cpu;
-       long snooze;
-
        if (!cpu_has_feature(CPU_FTR_SMT))
                return 1;
 
-       snooze = simple_strtol(str, NULL, 10);
-       for_each_possible_cpu(cpu)
-               per_cpu(smt_snooze_delay, cpu) = snooze;
-
+       pr_warn("smt-snooze-delay command line option has no effect\n");
        return 1;
 }
 __setup("smt-snooze-delay=", setup_smt_snooze_delay);
@@ -225,14 +217,13 @@ static DEVICE_ATTR(dscr_default, 0600,
 static void sysfs_create_dscr_default(void)
 {
        if (cpu_has_feature(CPU_FTR_DSCR)) {
-               int err = 0;
                int cpu;
 
                dscr_default = spr_default_dscr;
                for_each_possible_cpu(cpu)
                        paca_ptrs[cpu]->dscr_default = dscr_default;
 
-               err = device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default);
+               device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default);
        }
 }
 #endif /* CONFIG_PPC64 */
@@ -1168,6 +1159,7 @@ static int __init topology_init(void)
        for_each_possible_cpu(cpu) {
                struct cpu *c = &per_cpu(cpu_devices, cpu);
 
+#ifdef CONFIG_HOTPLUG_CPU
                /*
                 * For now, we just see if the system supports making
                 * the RTAS calls for CPU hotplug.  But, there may be a
@@ -1175,8 +1167,9 @@ static int __init topology_init(void)
                 * CPU.  For instance, the boot cpu might never be valid
                 * for hotplugging.
                 */
-               if (ppc_md.cpu_die)
+               if (smp_ops->cpu_offline_self)
                        c->hotpluggable = 1;
+#endif
 
                if (cpu_online(cpu) || c->hotpluggable) {
                        register_cpu(c, cpu);
index e2ab8a1..0b4694b 100644 (file)
  */
 
 #include <linux/errno.h>
-#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <asm/reg.h>
@@ -39,9 +40,7 @@ static struct tau_temp
        unsigned char grew;
 } tau[NR_CPUS];
 
-struct timer_list tau_timer;
-
-#undef DEBUG
+static bool tau_int_enable;
 
 /* TODO: put these in a /proc interface, with some sanity checks, and maybe
  * dynamic adjustment to minimize # of interrupts */
@@ -50,72 +49,49 @@ struct timer_list tau_timer;
 #define step_size              2       /* step size when temp goes out of range */
 #define window_expand          1       /* expand the window by this much */
 /* configurable values for shrinking the window */
-#define shrink_timer   2*HZ    /* period between shrinking the window */
+#define shrink_timer   2000    /* period between shrinking the window */
 #define min_window     2       /* minimum window size, degrees C */
 
 static void set_thresholds(unsigned long cpu)
 {
-#ifdef CONFIG_TAU_INT
-       /*
-        * setup THRM1,
-        * threshold, valid bit, enable interrupts, interrupt when below threshold
-        */
-       mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID);
+       u32 maybe_tie = tau_int_enable ? THRM1_TIE : 0;
 
-       /* setup THRM2,
-        * threshold, valid bit, enable interrupts, interrupt when above threshold
-        */
-       mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE);
-#else
-       /* same thing but don't enable interrupts */
-       mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID);
-       mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V);
-#endif
+       /* setup THRM1, threshold, valid bit, interrupt when below threshold */
+       mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | maybe_tie | THRM1_TID);
+
+       /* setup THRM2, threshold, valid bit, interrupt when above threshold */
+       mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | maybe_tie);
 }
 
 static void TAUupdate(int cpu)
 {
-       unsigned thrm;
-
-#ifdef DEBUG
-       printk("TAUupdate ");
-#endif
+       u32 thrm;
+       u32 bits = THRM1_TIV | THRM1_TIN | THRM1_V;
 
        /* if both thresholds are crossed, the step_sizes cancel out
         * and the window winds up getting expanded twice. */
-       if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */
-               if(thrm & THRM1_TIN){ /* crossed low threshold */
-                       if (tau[cpu].low >= step_size){
-                               tau[cpu].low -= step_size;
-                               tau[cpu].high -= (step_size - window_expand);
-                       }
-                       tau[cpu].grew = 1;
-#ifdef DEBUG
-                       printk("low threshold crossed ");
-#endif
+       thrm = mfspr(SPRN_THRM1);
+       if ((thrm & bits) == bits) {
+               mtspr(SPRN_THRM1, 0);
+
+               if (tau[cpu].low >= step_size) {
+                       tau[cpu].low -= step_size;
+                       tau[cpu].high -= (step_size - window_expand);
                }
+               tau[cpu].grew = 1;
+               pr_debug("%s: low threshold crossed\n", __func__);
        }
-       if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */
-               if(thrm & THRM1_TIN){ /* crossed high threshold */
-                       if (tau[cpu].high <= 127-step_size){
-                               tau[cpu].low += (step_size - window_expand);
-                               tau[cpu].high += step_size;
-                       }
-                       tau[cpu].grew = 1;
-#ifdef DEBUG
-                       printk("high threshold crossed ");
-#endif
+       thrm = mfspr(SPRN_THRM2);
+       if ((thrm & bits) == bits) {
+               mtspr(SPRN_THRM2, 0);
+
+               if (tau[cpu].high <= 127 - step_size) {
+                       tau[cpu].low += (step_size - window_expand);
+                       tau[cpu].high += step_size;
                }
+               tau[cpu].grew = 1;
+               pr_debug("%s: high threshold crossed\n", __func__);
        }
-
-#ifdef DEBUG
-       printk("grew = %d\n", tau[cpu].grew);
-#endif
-
-#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */
-       set_thresholds(cpu);
-#endif
-
 }
 
 #ifdef CONFIG_TAU_INT
@@ -140,17 +116,16 @@ void TAUException(struct pt_regs * regs)
 static void tau_timeout(void * info)
 {
        int cpu;
-       unsigned long flags;
        int size;
        int shrink;
 
-       /* disabling interrupts *should* be okay */
-       local_irq_save(flags);
        cpu = smp_processor_id();
 
-#ifndef CONFIG_TAU_INT
-       TAUupdate(cpu);
-#endif
+       if (!tau_int_enable)
+               TAUupdate(cpu);
+
+       /* Stop thermal sensor comparisons and interrupts */
+       mtspr(SPRN_THRM3, 0);
 
        size = tau[cpu].high - tau[cpu].low;
        if (size > min_window && ! tau[cpu].grew) {
@@ -173,32 +148,26 @@ static void tau_timeout(void * info)
 
        set_thresholds(cpu);
 
-       /*
-        * Do the enable every time, since otherwise a bunch of (relatively)
-        * complex sleep code needs to be added. One mtspr every time
-        * tau_timeout is called is probably not a big deal.
-        *
-        * Enable thermal sensor and set up sample interval timer
-        * need 20 us to do the compare.. until a nice 'cpu_speed' function
-        * call is implemented, just assume a 500 mhz clock. It doesn't really
-        * matter if we take too long for a compare since it's all interrupt
-        * driven anyway.
-        *
-        * use a extra long time.. (60 us @ 500 mhz)
+       /* Restart thermal sensor comparisons and interrupts.
+        * The "PowerPC 740 and PowerPC 750 Microprocessor Datasheet"
+        * recommends that "the maximum value be set in THRM3 under all
+        * conditions."
         */
-       mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E);
-
-       local_irq_restore(flags);
+       mtspr(SPRN_THRM3, THRM3_SITV(0x1fff) | THRM3_E);
 }
 
-static void tau_timeout_smp(struct timer_list *unused)
-{
+static struct workqueue_struct *tau_workq;
 
-       /* schedule ourselves to be run again */
-       mod_timer(&tau_timer, jiffies + shrink_timer) ;
+static void tau_work_func(struct work_struct *work)
+{
+       msleep(shrink_timer);
        on_each_cpu(tau_timeout, NULL, 0);
+       /* schedule ourselves to be run again */
+       queue_work(tau_workq, work);
 }
 
+DECLARE_WORK(tau_work, tau_work_func);
+
 /*
  * setup the TAU
  *
@@ -231,21 +200,19 @@ static int __init TAU_init(void)
                return 1;
        }
 
+       tau_int_enable = IS_ENABLED(CONFIG_TAU_INT) &&
+                        !strcmp(cur_cpu_spec->platform, "ppc750");
 
-       /* first, set up the window shrinking timer */
-       timer_setup(&tau_timer, tau_timeout_smp, 0);
-       tau_timer.expires = jiffies + shrink_timer;
-       add_timer(&tau_timer);
+       tau_workq = alloc_workqueue("tau", WQ_UNBOUND, 1, 0);
+       if (!tau_workq)
+               return -ENOMEM;
 
        on_each_cpu(TAU_init_smp, NULL, 0);
 
-       printk("Thermal assist unit ");
-#ifdef CONFIG_TAU_INT
-       printk("using interrupts, ");
-#else
-       printk("using timers, ");
-#endif
-       printk("shrink_timer: %d jiffies\n", shrink_timer);
+       queue_work(tau_workq, &tau_work);
+
+       pr_info("Thermal assist unit using %s, shrink_timer: %d ms\n",
+               tau_int_enable ? "interrupts" : "workqueue", shrink_timer);
        tau_initialized = 1;
 
        return 0;
index f85539e..74efe46 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/timekeeper_internal.h>
 
-static u64 rtc_read(struct clocksource *);
-static struct clocksource clocksource_rtc = {
-       .name         = "rtc",
-       .rating       = 400,
-       .flags        = CLOCK_SOURCE_IS_CONTINUOUS,
-       .mask         = CLOCKSOURCE_MASK(64),
-       .read         = rtc_read,
-};
-
 static u64 timebase_read(struct clocksource *);
 static struct clocksource clocksource_timebase = {
        .name         = "timebase",
@@ -447,19 +438,9 @@ void vtime_flush(struct task_struct *tsk)
 void __delay(unsigned long loops)
 {
        unsigned long start;
-       int diff;
 
        spin_begin();
-       if (__USE_RTC()) {
-               start = get_rtcl();
-               do {
-                       /* the RTCL register wraps at 1000000000 */
-                       diff = get_rtcl() - start;
-                       if (diff < 0)
-                               diff += 1000000000;
-                       spin_cpu_relax();
-               } while (diff < loops);
-       } else if (tb_invalid) {
+       if (tb_invalid) {
                /*
                 * TB is in error state and isn't ticking anymore.
                 * HMI handler was unable to recover from TB error.
@@ -467,8 +448,8 @@ void __delay(unsigned long loops)
                 */
                spin_cpu_relax();
        } else {
-               start = get_tbl();
-               while (get_tbl() - start < loops)
+               start = mftb();
+               while (mftb() - start < loops)
                        spin_cpu_relax();
        }
        spin_end();
@@ -614,7 +595,7 @@ void timer_interrupt(struct pt_regs *regs)
                irq_work_run();
        }
 
-       now = get_tb_or_rtc();
+       now = get_tb();
        if (now >= *next_tb) {
                *next_tb = ~(u64)0;
                if (evt->event_handler)
@@ -696,8 +677,6 @@ EXPORT_SYMBOL_GPL(tb_to_ns);
  */
 notrace unsigned long long sched_clock(void)
 {
-       if (__USE_RTC())
-               return get_rtc();
        return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
 }
 
@@ -847,11 +826,6 @@ void read_persistent_clock64(struct timespec64 *ts)
 }
 
 /* clocksource code */
-static notrace u64 rtc_read(struct clocksource *cs)
-{
-       return (u64)get_rtc();
-}
-
 static notrace u64 timebase_read(struct clocksource *cs)
 {
        return (u64)get_tb();
@@ -948,12 +922,7 @@ void update_vsyscall_tz(void)
 
 static void __init clocksource_init(void)
 {
-       struct clocksource *clock;
-
-       if (__USE_RTC())
-               clock = &clocksource_rtc;
-       else
-               clock = &clocksource_timebase;
+       struct clocksource *clock = &clocksource_timebase;
 
        if (clocksource_register_hz(clock, tb_ticks_per_sec)) {
                printk(KERN_ERR "clocksource: %s is already registered\n",
@@ -968,7 +937,7 @@ static void __init clocksource_init(void)
 static int decrementer_set_next_event(unsigned long evt,
                                      struct clock_event_device *dev)
 {
-       __this_cpu_write(decrementers_next_tb, get_tb_or_rtc() + evt);
+       __this_cpu_write(decrementers_next_tb, get_tb() + evt);
        set_dec(evt);
 
        /* We may have raced with new irq work */
@@ -1071,17 +1040,12 @@ void __init time_init(void)
        u64 scale;
        unsigned shift;
 
-       if (__USE_RTC()) {
-               /* 601 processor: dec counts down by 128 every 128ns */
-               ppc_tb_freq = 1000000000;
-       } else {
-               /* Normal PowerPC with timebase register */
-               ppc_md.calibrate_decr();
-               printk(KERN_DEBUG "time_init: decrementer frequency = %lu.%.6lu MHz\n",
-                      ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
-               printk(KERN_DEBUG "time_init: processor frequency   = %lu.%.6lu MHz\n",
-                      ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
-       }
+       /* Normal PowerPC with timebase register */
+       ppc_md.calibrate_decr();
+       printk(KERN_DEBUG "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+              ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
+       printk(KERN_DEBUG "time_init: processor frequency   = %lu.%.6lu MHz\n",
+              ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
 
        tb_ticks_per_jiffy = ppc_tb_freq / HZ;
        tb_ticks_per_sec = ppc_tb_freq;
@@ -1107,7 +1071,7 @@ void __init time_init(void)
        tb_to_ns_scale = scale;
        tb_to_ns_shift = shift;
        /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
-       boot_tb = get_tb_or_rtc();
+       boot_tb = get_tb();
 
        /* If platform provided a timezone (pmac), we correct the time */
        if (timezone_offset) {
index 6ba0fdd..2b91f23 100644 (file)
@@ -122,6 +122,13 @@ _GLOBAL(tm_reclaim)
        std     r3, STK_PARAM(R3)(r1)
        SAVE_NVGPRS(r1)
 
+       /*
+        * Save kernel live AMR since it will be clobbered by treclaim
+        * but can be used elsewhere later in kernel space.
+        */
+       mfspr   r3, SPRN_AMR
+       std     r3, TM_FRAME_L1(r1)
+
        /* We need to setup MSR for VSX register save instructions. */
        mfmsr   r14
        mr      r15, r14
@@ -245,7 +252,7 @@ _GLOBAL(tm_reclaim)
         * but is used in signal return to 'wind back' to the abort handler.
         */
 
-       /* ******************** CR,LR,CCR,MSR ********** */
+       /* ***************** CTR, LR, CR, XER ********** */
        mfctr   r3
        mflr    r4
        mfcr    r5
@@ -256,7 +263,6 @@ _GLOBAL(tm_reclaim)
        std     r5, _CCR(r7)
        std     r6, _XER(r7)
 
-
        /* ******************** TAR, DSCR ********** */
        mfspr   r3, SPRN_TAR
        mfspr   r4, SPRN_DSCR
@@ -264,6 +270,10 @@ _GLOBAL(tm_reclaim)
        std     r3, THREAD_TM_TAR(r12)
        std     r4, THREAD_TM_DSCR(r12)
 
+        /* ******************** AMR **************** */
+        mfspr  r3, SPRN_AMR
+        std    r3, THREAD_TM_AMR(r12)
+
        /*
         * MSR and flags: We don't change CRs, and we don't need to alter MSR.
         */
@@ -308,7 +318,9 @@ _GLOBAL(tm_reclaim)
        std     r3, THREAD_TM_TFHAR(r12)
        std     r4, THREAD_TM_TFIAR(r12)
 
-       /* AMR is checkpointed too, but is unsupported by Linux. */
+       /* Restore kernel live AMR */
+       ld      r8, TM_FRAME_L1(r1)
+       mtspr   SPRN_AMR, r8
 
        /* Restore original MSR/IRQ state & clear TM mode */
        ld      r14, TM_FRAME_L0(r1)            /* Orig MSR */
@@ -355,6 +367,13 @@ _GLOBAL(__tm_recheckpoint)
         */
        SAVE_NVGPRS(r1)
 
+       /*
+        * Save kernel live AMR since it will be clobbered for trechkpt
+        * but can be used elsewhere later in kernel space.
+        */
+       mfspr   r8, SPRN_AMR
+       std     r8, TM_FRAME_L0(r1)
+
        /* Load complete register state from ts_ckpt* registers */
 
        addi    r7, r3, PT_CKPT_REGS            /* Thread's ckpt_regs */
@@ -404,7 +423,7 @@ _GLOBAL(__tm_recheckpoint)
 
 restore_gprs:
 
-       /* ******************** CR,LR,CCR,MSR ********** */
+       /* ****************** CTR, LR, XER ************* */
        ld      r4, _CTR(r7)
        ld      r5, _LINK(r7)
        ld      r8, _XER(r7)
@@ -417,6 +436,10 @@ restore_gprs:
        ld      r4, THREAD_TM_TAR(r3)
        mtspr   SPRN_TAR,       r4
 
+       /* ******************** AMR ******************** */
+       ld      r4, THREAD_TM_AMR(r3)
+       mtspr   SPRN_AMR, r4
+
        /* Load up the PPR and DSCR in GPRs only at this stage */
        ld      r5, THREAD_TM_DSCR(r3)
        ld      r6, THREAD_TM_PPR(r3)
@@ -509,6 +532,10 @@ restore_gprs:
        li      r4, MSR_RI
        mtmsrd  r4, 1
 
+       /* Restore kernel live AMR */
+       ld      r8, TM_FRAME_L0(r1)
+       mtspr   SPRN_AMR, r8
+
        REST_NVGPRS(r1)
 
        addi    r1, r1, TM_FRAME_SIZE
index d1ebe15..c5f39f1 100644 (file)
@@ -529,9 +529,6 @@ out:
  * Check if the NIP corresponds to the address of a sync
  * instruction for which there is an entry in the exception
  * table.
- * Note that the 601 only takes a machine check on TEA
- * (transfer error ack) signal assertion, and does not
- * set any of the top 16 bits of SRR1.
  *  -- paulus.
  */
 static inline int check_io_access(struct pt_regs *regs)
@@ -796,7 +793,6 @@ int machine_check_generic(struct pt_regs *regs)
        case 0x80000:
                pr_cont("Machine check signal\n");
                break;
-       case 0:         /* for 601 */
        case 0x40000:
        case 0x140000:  /* 7450 MSS error and TEA */
                pr_cont("Transfer error ack signal\n");
index 217bb63..1d23e27 100644 (file)
@@ -47,7 +47,6 @@ V_FUNCTION_END(__kernel_get_syscall_map)
  *
  * returns the timebase frequency in HZ
  */
-#ifndef CONFIG_PPC_BOOK3S_601
 V_FUNCTION_BEGIN(__kernel_get_tbfreq)
   .cfi_startproc
        mflr    r12
@@ -60,4 +59,3 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
        blr
   .cfi_endproc
 V_FUNCTION_END(__kernel_get_tbfreq)
-#endif
index 5206c2e..7eadac7 100644 (file)
@@ -144,13 +144,11 @@ VERSION
                __kernel_datapage_offset;
 
                __kernel_get_syscall_map;
-#ifndef CONFIG_PPC_BOOK3S_601
                __kernel_gettimeofday;
                __kernel_clock_gettime;
                __kernel_clock_getres;
                __kernel_time;
                __kernel_get_tbfreq;
-#endif
                __kernel_sync_dicache;
                __kernel_sync_dicache_p5;
                __kernel_sigtramp32;
index 4ba06a2..3bd3118 100644 (file)
@@ -3530,6 +3530,13 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
         */
        asm volatile("eieio; tlbsync; ptesync");
 
+       /*
+        * cp_abort is required if the processor supports local copy-paste
+        * to clear the copy buffer that was under control of the guest.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               asm volatile(PPC_CP_ABORT);
+
        mtspr(SPRN_LPID, vcpu->kvm->arch.host_lpid);    /* restore host LPID */
        isync();
 
index 799d6d0..cd9995e 100644 (file)
@@ -1830,6 +1830,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_RADIX_PREFETCH_BUG)
 2:
 #endif /* CONFIG_PPC_RADIX_MMU */
 
+       /*
+        * cp_abort is required if the processor supports local copy-paste
+        * to clear the copy buffer that was under control of the guest.
+        */
+BEGIN_FTR_SECTION
+       PPC_CP_ABORT
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
+
        /*
         * POWER7/POWER8 guest -> host partition switch code.
         * We don't have to lock against tlbies but we do
index 8c3934e..2333625 100644 (file)
 static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr,
                               struct ppc_inst *patch_addr)
 {
-       int err = 0;
-
-       if (!ppc_inst_prefixed(instr)) {
-               __put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
-       } else {
-               __put_user_asm(ppc_inst_as_u64(instr), patch_addr, err, "std");
-       }
-
-       if (err)
-               return err;
+       if (!ppc_inst_prefixed(instr))
+               __put_user_asm_goto(ppc_inst_val(instr), patch_addr, failed, "stw");
+       else
+               __put_user_asm_goto(ppc_inst_as_u64(instr), patch_addr, failed, "std");
 
        asm ("dcbst 0, %0; sync; icbi 0,%1; sync; isync" :: "r" (patch_addr),
                                                            "r" (exec_addr));
 
        return 0;
+
+failed:
+       return -EFAULT;
 }
 
 int raw_patch_instruction(struct ppc_inst *addr, struct ppc_inst instr)
index caee8cc..e9dcaba 100644 (file)
@@ -219,10 +219,13 @@ static nokprobe_inline unsigned long mlsd_8lsd_ea(unsigned int instr,
                ea += regs->gpr[ra];
        else if (!prefix_r && !ra)
                ; /* Leave ea as is */
-       else if (prefix_r && !ra)
+       else if (prefix_r)
                ea += regs->nip;
-       else if (prefix_r && ra)
-               ; /* Invalid form. Should already be checked for by caller! */
+
+       /*
+        * (prefix_r && ra) is an invalid form. Should already be
+        * checked for by caller!
+        */
 
        return ea;
 }
index 1690d36..b2c912e 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/pgtable.h>
+#include <linux/init.h>
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/cputable.h>
@@ -199,11 +200,9 @@ _GLOBAL(add_hash_page)
         * covered by a BAT).  -- paulus
         */
        mfmsr   r9
-       SYNC
        rlwinm  r0,r9,0,17,15           /* clear bit 16 (MSR_EE) */
        rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
        mtmsr   r0
-       SYNC_601
        isync
 
 #ifdef CONFIG_SMP
@@ -262,7 +261,6 @@ _GLOBAL(add_hash_page)
 
        /* reenable interrupts and DR */
        mtmsr   r9
-       SYNC_601
        isync
 
        lwz     r0,4(r1)
@@ -287,9 +285,9 @@ _ASM_NOKPROBE_SYMBOL(add_hash_page)
  *
  * For speed, 4 of the instructions get patched once the size and
  * physical address of the hash table are known.  These definitions
- * of Hash_base and Hash_bits below are just an example.
+ * of Hash_base and Hash_bits below are for the early hash table.
  */
-Hash_base = 0xc0180000
+Hash_base = early_hash
 Hash_bits = 12                         /* e.g. 256kB hash table */
 Hash_msk = (((1 << Hash_bits) - 1) * 64)
 
@@ -310,6 +308,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
 #define HASH_LEFT      31-(LG_PTEG_SIZE+Hash_bits-1)
 #define HASH_RIGHT     31-LG_PTEG_SIZE
 
+__REF
 _GLOBAL(create_hpte)
        /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
        rlwinm  r8,r5,32-9,30,30        /* _PAGE_RW -> PP msb */
@@ -476,6 +475,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
 
        sync            /* make sure pte updates get to memory */
        blr
+       .previous
 _ASM_NOKPROBE_SYMBOL(create_hpte)
 
        .section .bss
@@ -496,6 +496,7 @@ htab_hash_searches:
  *
  * We assume that there is a hash table in use (Hash != 0).
  */
+__REF
 _GLOBAL(flush_hash_pages)
        /*
         * We disable interrupts here, even on UP, because we want
@@ -506,11 +507,9 @@ _GLOBAL(flush_hash_pages)
         * covered by a BAT).  -- paulus
         */
        mfmsr   r10
-       SYNC
        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
        rlwinm  r0,r0,0,28,26           /* clear MSR_DR */
        mtmsr   r0
-       SYNC_601
        isync
 
        /* First find a PTE in the range that has _PAGE_HASHPTE set */
@@ -629,9 +628,9 @@ _GLOBAL(flush_hash_pages)
 #endif
 
 19:    mtmsr   r10
-       SYNC_601
        isync
        blr
+       .previous
 EXPORT_SYMBOL(flush_hash_pages)
 _ASM_NOKPROBE_SYMBOL(flush_hash_pages)
 
@@ -643,11 +642,9 @@ _GLOBAL(_tlbie)
        lwz     r8,TASK_CPU(r2)
        oris    r8,r8,11
        mfmsr   r10
-       SYNC
        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
        rlwinm  r0,r0,0,28,26           /* clear DR */
        mtmsr   r0
-       SYNC_601
        isync
        lis     r9,mmu_hash_lock@h
        ori     r9,r9,mmu_hash_lock@l
@@ -664,7 +661,6 @@ _GLOBAL(_tlbie)
        li      r0,0
        stw     r0,0(r9)                /* clear mmu_hash_lock */
        mtmsr   r10
-       SYNC_601
        isync
 #else /* CONFIG_SMP */
        tlbie   r3
@@ -681,11 +677,9 @@ _GLOBAL(_tlbia)
        lwz     r8,TASK_CPU(r2)
        oris    r8,r8,10
        mfmsr   r10
-       SYNC
        rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
        rlwinm  r0,r0,0,28,26           /* clear DR */
        mtmsr   r0
-       SYNC_601
        isync
        lis     r9,mmu_hash_lock@h
        ori     r9,r9,mmu_hash_lock@l
@@ -709,7 +703,6 @@ _GLOBAL(_tlbia)
        li      r0,0
        stw     r0,0(r9)                /* clear mmu_hash_lock */
        mtmsr   r10
-       SYNC_601
        isync
 #endif /* CONFIG_SMP */
        blr
index d426eaf..a59e7ec 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <mm/mmu_decl.h>
 
+u8 __initdata early_hash[SZ_256K] __aligned(SZ_256K) = {0};
+
 struct hash_pte *Hash;
 static unsigned long Hash_size, Hash_mask;
 unsigned long _SDR1;
@@ -73,23 +75,13 @@ unsigned long p_block_mapped(phys_addr_t pa)
 static int find_free_bat(void)
 {
        int b;
+       int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
 
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601)) {
-               for (b = 0; b < 4; b++) {
-                       struct ppc_bat *bat = BATS[b];
-
-                       if (!(bat[0].batl & 0x40))
-                               return b;
-               }
-       } else {
-               int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
+       for (b = 0; b < n; b++) {
+               struct ppc_bat *bat = BATS[b];
 
-               for (b = 0; b < n; b++) {
-                       struct ppc_bat *bat = BATS[b];
-
-                       if (!(bat[1].batu & 3))
-                               return b;
-               }
+               if (!(bat[1].batu & 3))
+                       return b;
        }
        return -1;
 }
@@ -97,7 +89,7 @@ static int find_free_bat(void)
 /*
  * This function calculates the size of the larger block usable to map the
  * beginning of an area based on the start address and size of that area:
- * - max block size is 8M on 601 and 256 on other 6xx.
+ * - max block size is 256 on 6xx.
  * - base address must be aligned to the block size. So the maximum block size
  *   is identified by the lowest bit set to 1 in the base address (for instance
  *   if base is 0x16000000, max size is 0x02000000).
@@ -106,7 +98,7 @@ static int find_free_bat(void)
  */
 static unsigned int block_size(unsigned long base, unsigned long top)
 {
-       unsigned int max_size = IS_ENABLED(CONFIG_PPC_BOOK3S_601) ? SZ_8M : SZ_256M;
+       unsigned int max_size = SZ_256M;
        unsigned int base_shift = (ffs(base) - 1) & 31;
        unsigned int block_shift = (fls(top - base) - 1) & 31;
 
@@ -117,7 +109,6 @@ static unsigned int block_size(unsigned long base, unsigned long top)
  * Set up one of the IBAT (block address translation) register pairs.
  * The parameters are not checked; in particular size must be a power
  * of 2 between 128k and 256M.
- * Only for 603+ ...
  */
 static void setibat(int index, unsigned long virt, phys_addr_t phys,
                    unsigned int size, pgprot_t prot)
@@ -214,9 +205,6 @@ void mmu_mark_initmem_nx(void)
        unsigned long border = (unsigned long)__init_begin - PAGE_OFFSET;
        unsigned long size;
 
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-               return;
-
        for (i = 0; i < nb - 1 && base < top && top - base > (128 << 10);) {
                size = block_size(base, top);
                setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
@@ -253,9 +241,6 @@ void mmu_mark_rodata_ro(void)
        int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
        int i;
 
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-               return;
-
        for (i = 0; i < nb; i++) {
                struct ppc_bat *bat = BATS[i];
 
@@ -294,35 +279,22 @@ void __init setbat(int index, unsigned long virt, phys_addr_t phys,
                flags &= ~_PAGE_COHERENT;
 
        bl = (size >> 17) - 1;
-       if (!IS_ENABLED(CONFIG_PPC_BOOK3S_601)) {
-               /* 603, 604, etc. */
-               /* Do DBAT first */
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT | _PAGE_GUARDED);
-               wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
-               bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
-               bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
-               if (flags & _PAGE_USER)
-                       bat[1].batu |= 1;       /* Vp = 1 */
-               if (flags & _PAGE_GUARDED) {
-                       /* G bit must be zero in IBATs */
-                       flags &= ~_PAGE_EXEC;
-               }
-               if (flags & _PAGE_EXEC)
-                       bat[0] = bat[1];
-               else
-                       bat[0].batu = bat[0].batl = 0;
-       } else {
-               /* 601 cpu */
-               if (bl > BL_8M)
-                       bl = BL_8M;
-               wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-                                  | _PAGE_COHERENT);
-               wimgxpp |= (flags & _PAGE_RW)?
-                       ((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
-               bat->batu = virt | wimgxpp | 4; /* Ks=0, Ku=1 */
-               bat->batl = phys | bl | 0x40;   /* V=1 */
+       /* Do DBAT first */
+       wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+                          | _PAGE_COHERENT | _PAGE_GUARDED);
+       wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+       bat[1].batu = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+       bat[1].batl = BAT_PHYS_ADDR(phys) | wimgxpp;
+       if (flags & _PAGE_USER)
+               bat[1].batu |= 1;       /* Vp = 1 */
+       if (flags & _PAGE_GUARDED) {
+               /* G bit must be zero in IBATs */
+               flags &= ~_PAGE_EXEC;
        }
+       if (flags & _PAGE_EXEC)
+               bat[0] = bat[1];
+       else
+               bat[0].batu = bat[0].batl = 0;
 
        bat_addrs[index].start = virt;
        bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
@@ -425,15 +397,6 @@ void __init MMU_init_hw(void)
        hash_mb2 = hash_mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
        if (lg_n_hpteg > 16)
                hash_mb2 = 16 - LG_HPTEG_SIZE;
-
-       /*
-        * When KASAN is selected, there is already an early temporary hash
-        * table and the switch to the final hash table is done later.
-        */
-       if (IS_ENABLED(CONFIG_KASAN))
-               return;
-
-       MMU_init_hw_patch();
 }
 
 void __init MMU_init_hw_patch(void)
@@ -441,6 +404,9 @@ void __init MMU_init_hw_patch(void)
        unsigned int hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
        unsigned int hash = (unsigned int)Hash - PAGE_OFFSET;
 
+       if (!mmu_has_feature(MMU_FTR_HPTE_TABLE))
+               return;
+
        if (ppc_md.progress)
                ppc_md.progress("hash:patch", 0x345);
        if (ppc_md.progress)
@@ -474,11 +440,7 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
         */
        BUG_ON(first_memblock_base != 0);
 
-       /* 601 can only access 16MB at the moment */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01000000));
-       else /* Anything else has 256M mapped */
-               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
+       memblock_set_current_limit(min_t(u64, first_memblock_size, SZ_256M));
 }
 
 void __init print_system_hash_info(void)
index cf20e52..0203cdf 100644 (file)
@@ -82,7 +82,7 @@ static void tlbiel_all_isa206(unsigned int num_sets, unsigned int is)
        for (set = 0; set < num_sets; set++)
                tlbiel_hash_set_isa206(set, is);
 
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
 }
 
 static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
@@ -110,7 +110,7 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
         */
        tlbiel_hash_set_isa300(0, is, 0, 2, 1);
 
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
 
        asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT "; isync" : : :"memory");
 }
@@ -303,7 +303,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize,
        asm volatile("ptesync": : :"memory");
        if (use_local) {
                __tlbiel(vpn, psize, apsize, ssize);
-               asm volatile("ptesync": : :"memory");
+               ppc_after_tlbiel_barrier();
        } else {
                __tlbie(vpn, psize, apsize, ssize);
                fixup_tlbie_vpn(vpn, psize, apsize, ssize);
@@ -879,7 +879,7 @@ static void native_flush_hash_range(unsigned long number, int local)
                                __tlbiel(vpn, psize, psize, ssize);
                        } pte_iterate_hashed_end();
                }
-               asm volatile("ptesync":::"memory");
+               ppc_after_tlbiel_barrier();
        } else {
                int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
 
index b830ade..24702c0 100644 (file)
@@ -260,8 +260,12 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
        DBG("htab_bolt_mapping(%lx..%lx -> %lx (%lx,%d,%d)\n",
            vstart, vend, pstart, prot, psize, ssize);
 
-       for (vaddr = vstart, paddr = pstart; vaddr < vend;
-            vaddr += step, paddr += step) {
+       /* Carefully map only the possible range */
+       vaddr = ALIGN(vstart, step);
+       paddr = ALIGN(pstart, step);
+       vend  = ALIGN_DOWN(vend, step);
+
+       for (; vaddr < vend; vaddr += step, paddr += step) {
                unsigned long hash, hpteg;
                unsigned long vsid = get_kernel_vsid(vaddr, ssize);
                unsigned long vpn  = hpt_vpn(vaddr, vsid, ssize);
@@ -343,7 +347,9 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend,
        if (!mmu_hash_ops.hpte_removebolted)
                return -ENODEV;
 
-       for (vaddr = vstart; vaddr < vend; vaddr += step) {
+       /* Unmap the full range specificied */
+       vaddr = ALIGN_DOWN(vstart, step);
+       for (;vaddr < vend; vaddr += step) {
                rc = mmu_hash_ops.hpte_removebolted(vaddr, psize, ssize);
                if (rc == -ENOENT) {
                        ret = -ENOENT;
index 7eda0d3..c12d78e 100644 (file)
@@ -13,4 +13,6 @@ static inline bool stress_slb(void)
        return static_branch_unlikely(&stress_slb_key);
 }
 
+void slb_setup_new_exec(void);
+
 #endif /* ARCH_POWERPC_MM_BOOK3S64_INTERNAL_H */
index 0ba30b8..1c54821 100644 (file)
@@ -21,6 +21,8 @@
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 
+#include "internal.h"
+
 static DEFINE_IDA(mmu_context_ida);
 
 static int alloc_context_id(int min_id, int max_id)
@@ -48,8 +50,6 @@ int hash__alloc_context_id(void)
 }
 EXPORT_SYMBOL_GPL(hash__alloc_context_id);
 
-void slb_setup_new_exec(void);
-
 static int realloc_context_ids(mm_context_t *ctx)
 {
        int i, id;
index cc72666..3adcf73 100644 (file)
@@ -34,7 +34,7 @@
 
 unsigned int mmu_pid_bits;
 unsigned int mmu_base_pid;
-unsigned int radix_mem_block_size __ro_after_init;
+unsigned long radix_mem_block_size __ro_after_init;
 
 static __ref void *early_alloc_pgtable(unsigned long size, int nid,
                        unsigned long region_start, unsigned long region_end)
@@ -276,6 +276,7 @@ static int __meminit create_physical_mapping(unsigned long start,
        int psize;
 
        start = ALIGN(start, PAGE_SIZE);
+       end   = ALIGN_DOWN(end, PAGE_SIZE);
        for (addr = start; addr < end; addr += mapping_size) {
                unsigned long gap, previous_size;
                int rc;
@@ -497,7 +498,7 @@ static int __init probe_memory_block_size(unsigned long node, const char *uname,
                                          depth, void *data)
 {
        unsigned long *mem_block_size = (unsigned long *)data;
-       const __be64 *prop;
+       const __be32 *prop;
        int len;
 
        if (depth != 1)
@@ -507,13 +508,14 @@ static int __init probe_memory_block_size(unsigned long node, const char *uname,
                return 0;
 
        prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len);
-       if (!prop || len < sizeof(__be64))
+
+       if (!prop || len < dt_root_size_cells * sizeof(__be32))
                /*
                 * Nothing in the device tree
                 */
                *mem_block_size = MIN_MEMORY_BLOCK_SIZE;
        else
-               *mem_block_size = be64_to_cpup(prop);
+               *mem_block_size = of_read_number(prop, dt_root_size_cells);
        return 1;
 }
 
index 0d23376..b487b48 100644 (file)
@@ -65,7 +65,7 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
        for (set = 1; set < num_sets; set++)
                tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1);
 
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
 }
 
 void radix__tlbiel_all(unsigned int action)
@@ -296,7 +296,7 @@ static __always_inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
 
        /* For PWC, only one flush is needed */
        if (ric == RIC_FLUSH_PWC) {
-               asm volatile("ptesync": : :"memory");
+               ppc_after_tlbiel_barrier();
                return;
        }
 
@@ -304,7 +304,7 @@ static __always_inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
        for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
                __tlbiel_pid(pid, set, RIC_FLUSH_TLB);
 
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
        asm volatile(PPC_RADIX_INVALIDATE_ERAT_USER "; isync" : : :"memory");
 }
 
@@ -431,7 +431,7 @@ static __always_inline void _tlbiel_va(unsigned long va, unsigned long pid,
 
        asm volatile("ptesync": : :"memory");
        __tlbiel_va(va, pid, ap, ric);
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
 }
 
 static inline void _tlbiel_va_range(unsigned long start, unsigned long end,
@@ -442,7 +442,7 @@ static inline void _tlbiel_va_range(unsigned long start, unsigned long end,
        if (also_pwc)
                __tlbiel_pid(pid, 0, RIC_FLUSH_PWC);
        __tlbiel_va_range(start, end, pid, page_size, psize);
-       asm volatile("ptesync": : :"memory");
+       ppc_after_tlbiel_barrier();
 }
 
 static inline void __tlbie_va_range(unsigned long start, unsigned long end,
@@ -645,19 +645,29 @@ static void do_exit_flush_lazy_tlb(void *arg)
        struct mm_struct *mm = arg;
        unsigned long pid = mm->context.id;
 
+       /*
+        * A kthread could have done a mmget_not_zero() after the flushing CPU
+        * checked mm_is_singlethreaded, and be in the process of
+        * kthread_use_mm when interrupted here. In that case, current->mm will
+        * be set to mm, because kthread_use_mm() setting ->mm and switching to
+        * the mm is done with interrupts off.
+        */
        if (current->mm == mm)
-               return; /* Local CPU */
+               goto out_flush;
 
        if (current->active_mm == mm) {
-               /*
-                * Must be a kernel thread because sender is single-threaded.
-                */
-               BUG_ON(current->mm);
+               WARN_ON_ONCE(current->mm != NULL);
+               /* Is a kernel thread and is using mm as the lazy tlb */
                mmgrab(&init_mm);
-               switch_mm(mm, &init_mm, current);
                current->active_mm = &init_mm;
+               switch_mm_irqs_off(mm, &init_mm, current);
                mmdrop(mm);
        }
+
+       atomic_dec(&mm->context.active_cpus);
+       cpumask_clear_cpu(smp_processor_id(), mm_cpumask(mm));
+
+out_flush:
        _tlbiel_pid(pid, RIC_FLUSH_ALL);
 }
 
@@ -672,7 +682,6 @@ static void exit_flush_lazy_tlbs(struct mm_struct *mm)
         */
        smp_call_function_many(mm_cpumask(mm), do_exit_flush_lazy_tlb,
                                (void *)mm, 1);
-       mm_reset_thread_local(mm);
 }
 
 void radix__flush_tlb_mm(struct mm_struct *mm)
@@ -940,7 +949,7 @@ is_local:
                        if (hflush)
                                __tlbiel_va_range(hstart, hend, pid,
                                                PMD_SIZE, MMU_PAGE_2M);
-                       asm volatile("ptesync": : :"memory");
+                       ppc_after_tlbiel_barrier();
                } else if (cputlb_use_tlbie()) {
                        asm volatile("ptesync": : :"memory");
                        __tlbie_va_range(start, end, pid, page_size, mmu_virtual_psize);
index 156c38f..c30fcbf 100644 (file)
@@ -765,8 +765,8 @@ static long slb_allocate_kernel(unsigned long ea, unsigned long id)
 
        if (id == LINEAR_MAP_REGION_ID) {
 
-               /* We only support upto MAX_PHYSMEM_BITS */
-               if ((ea & EA_MASK) > (1UL << MAX_PHYSMEM_BITS))
+               /* We only support upto H_MAX_PHYSMEM_BITS */
+               if ((ea & EA_MASK) > (1UL << H_MAX_PHYSMEM_BITS))
                        return -EFAULT;
 
                flags = SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp;
index b2eeea3..9af3832 100644 (file)
@@ -389,10 +389,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)
        if (!drmem_info->lmbs)
                return;
 
-       for_each_drmem_lmb(lmb) {
+       for_each_drmem_lmb(lmb)
                read_drconf_v1_cell(lmb, &prop);
-               lmb_set_nid(lmb);
-       }
 }
 
 static void __init init_drmem_v2_lmbs(const __be32 *prop)
@@ -437,8 +435,6 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop)
 
                        lmb->aa_index = dr_cell.aa_index;
                        lmb->flags = dr_cell.flags;
-
-                       lmb_set_nid(lmb);
                }
        }
 }
index 2629254..36c3800 100644 (file)
@@ -180,7 +180,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
        if (!hpdp)
                return NULL;
 
-       if (IS_ENABLED(CONFIG_PPC_8xx) && sz == SZ_512K)
+       if (IS_ENABLED(CONFIG_PPC_8xx) && pshift < PMD_SHIFT)
                return pte_alloc_map(mm, (pmd_t *)hpdp, addr);
 
        BUG_ON(!hugepd_none(*hpdp) && !hugepd_ok(*hpdp));
@@ -330,10 +330,24 @@ static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshif
                                 get_hugepd_cache_index(pdshift - shift));
 }
 
-static void hugetlb_free_pte_range(struct mmu_gather *tlb, pmd_t *pmd, unsigned long addr)
+static void hugetlb_free_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
+                                  unsigned long addr, unsigned long end,
+                                  unsigned long floor, unsigned long ceiling)
 {
+       unsigned long start = addr;
        pgtable_t token = pmd_pgtable(*pmd);
 
+       start &= PMD_MASK;
+       if (start < floor)
+               return;
+       if (ceiling) {
+               ceiling &= PMD_MASK;
+               if (!ceiling)
+                       return;
+       }
+       if (end - 1 > ceiling - 1)
+               return;
+
        pmd_clear(pmd);
        pte_free_tlb(tlb, token, addr);
        mm_dec_nr_ptes(tlb->mm);
@@ -363,7 +377,7 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
                         */
                        WARN_ON(!IS_ENABLED(CONFIG_PPC_8xx));
 
-                       hugetlb_free_pte_range(tlb, pmd, addr);
+                       hugetlb_free_pte_range(tlb, pmd, addr, end, floor, ceiling);
 
                        continue;
                }
index 8459056..386be13 100644 (file)
@@ -162,16 +162,16 @@ static __meminit struct vmemmap_backing * vmemmap_list_alloc(int node)
        return next++;
 }
 
-static __meminit void vmemmap_list_populate(unsigned long phys,
-                                           unsigned long start,
-                                           int node)
+static __meminit int vmemmap_list_populate(unsigned long phys,
+                                          unsigned long start,
+                                          int node)
 {
        struct vmemmap_backing *vmem_back;
 
        vmem_back = vmemmap_list_alloc(node);
        if (unlikely(!vmem_back)) {
-               WARN_ON(1);
-               return;
+               pr_debug("vmemap list allocation failed\n");
+               return -ENOMEM;
        }
 
        vmem_back->phys = phys;
@@ -179,6 +179,7 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
        vmem_back->list = vmemmap_list;
 
        vmemmap_list = vmem_back;
+       return 0;
 }
 
 static bool altmap_cross_boundary(struct vmem_altmap *altmap, unsigned long start,
@@ -199,6 +200,7 @@ static bool altmap_cross_boundary(struct vmem_altmap *altmap, unsigned long star
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
                struct vmem_altmap *altmap)
 {
+       bool altmap_alloc;
        unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
 
        /* Align to the page size of the linear mapping. */
@@ -228,13 +230,32 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
                        p = vmemmap_alloc_block_buf(page_size, node, altmap);
                        if (!p)
                                pr_debug("altmap block allocation failed, falling back to system memory");
+                       else
+                               altmap_alloc = true;
                }
-               if (!p)
+               if (!p) {
                        p = vmemmap_alloc_block_buf(page_size, node, NULL);
+                       altmap_alloc = false;
+               }
                if (!p)
                        return -ENOMEM;
 
-               vmemmap_list_populate(__pa(p), start, node);
+               if (vmemmap_list_populate(__pa(p), start, node)) {
+                       /*
+                        * If we don't populate vmemap list, we don't have
+                        * the ability to free the allocated vmemmap
+                        * pages in section_deactivate. Hence free them
+                        * here.
+                        */
+                       int nr_pfns = page_size >> PAGE_SHIFT;
+                       unsigned long page_order = get_order(page_size);
+
+                       if (altmap_alloc)
+                               vmem_altmap_free(altmap, nr_pfns);
+                       else
+                               free_pages((unsigned long)p, page_order);
+                       return -ENOMEM;
+               }
 
                pr_debug("      * %016lx..%016lx allocated at %p\n",
                         start, start + page_size, p);
@@ -264,10 +285,8 @@ static unsigned long vmemmap_list_free(unsigned long start)
                vmem_back_prev = vmem_back;
        }
 
-       if (unlikely(!vmem_back)) {
-               WARN_ON(1);
+       if (unlikely(!vmem_back))
                return 0;
-       }
 
        /* remove it from vmemmap_list */
        if (vmem_back == vmemmap_list) /* remove head */
index 26fda32..cf8770b 100644 (file)
@@ -127,8 +127,7 @@ void __init kasan_mmu_init(void)
 {
        int ret;
 
-       if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE) ||
-           IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
+       if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
                ret = kasan_init_shadow_page_tables(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
                if (ret)
@@ -140,10 +139,10 @@ void __init kasan_init(void)
 {
        phys_addr_t base, end;
        u64 i;
+       int ret;
 
        for_each_mem_range(i, &base, &end) {
                phys_addr_t top = min(end, total_lowmem);
-               int ret;
 
                if (base >= top)
                        continue;
@@ -153,6 +152,13 @@ void __init kasan_init(void)
                        panic("kasan: kasan_init_region() failed");
        }
 
+       if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
+               ret = kasan_init_shadow_page_tables(KASAN_SHADOW_START, KASAN_SHADOW_END);
+
+               if (ret)
+                       panic("kasan: kasan_init_shadow_page_tables() failed");
+       }
+
        kasan_remap_early_shadow_ro();
 
        clear_page(kasan_early_shadow_page);
@@ -168,22 +174,6 @@ void __init kasan_late_init(void)
                kasan_unmap_early_shadow_vmalloc();
 }
 
-#ifdef CONFIG_PPC_BOOK3S_32
-u8 __initdata early_hash[256 << 10] __aligned(256 << 10) = {0};
-
-static void __init kasan_early_hash_table(void)
-{
-       unsigned int hash = __pa(early_hash);
-
-       modify_instruction_site(&patch__hash_page_A0, 0xffff, hash >> 16);
-       modify_instruction_site(&patch__flush_hash_A0, 0xffff, hash >> 16);
-
-       Hash = (struct hash_pte *)early_hash;
-}
-#else
-static void __init kasan_early_hash_table(void) {}
-#endif
-
 void __init kasan_early_init(void)
 {
        unsigned long addr = KASAN_SHADOW_START;
@@ -199,7 +189,4 @@ void __init kasan_early_init(void)
                next = pgd_addr_end(addr, end);
                pmd_populate_kernel(&init_mm, pmd, kasan_early_shadow_pte);
        } while (pmd++, addr = next, addr != end);
-
-       if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
-               kasan_early_hash_table();
 }
index 5e2e7c0..01ec2a2 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/swiotlb.h>
 #include <asm/rtas.h>
 #include <asm/kasan.h>
+#include <asm/svm.h>
 
 #include <mm/mmu_decl.h>
 
@@ -283,7 +284,10 @@ void __init mem_init(void)
         * back to to-down.
         */
        memblock_set_bottom_up(true);
-       swiotlb_init(0);
+       if (is_secure_guest())
+               svm_swiotlb_init();
+       else
+               swiotlb_init(0);
 #endif
 
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
index d2b3714..231ca95 100644 (file)
@@ -244,13 +244,6 @@ void set_context(unsigned long id, pgd_t *pgd)
        mb();
 }
 
-void flush_instruction_cache(void)
-{
-       isync();
-       mtspr(SPRN_IC_CST, IDC_INVALL);
-       isync();
-}
-
 #ifdef CONFIG_PPC_KUEP
 void __init setup_kuep(bool disabled)
 {
index 0c29482..36bda96 100644 (file)
@@ -219,6 +219,22 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
        return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1;
 }
 
+void flush_instruction_cache(void)
+{
+       unsigned long tmp;
+
+       if (IS_ENABLED(CONFIG_E200)) {
+               tmp = mfspr(SPRN_L1CSR0);
+               tmp |= L1CSR0_CFI | L1CSR0_CLFC;
+               mtspr(SPRN_L1CSR0, tmp);
+       } else {
+               tmp = mfspr(SPRN_L1CSR1);
+               tmp |= L1CSR1_ICFI | L1CSR1_ICLFR;
+               mtspr(SPRN_L1CSR1, tmp);
+       }
+       isync();
+}
+
 /*
  * MMU_init_hw does the chip-specific initialization of the MMU hardware.
  */
index 1451458..5872f69 100644 (file)
@@ -83,16 +83,12 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
 };
 #elif defined(CONFIG_PPC_8xx)
 struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
-       /* we only manage 4k and 16k pages as normal pages */
-#ifdef CONFIG_PPC_4K_PAGES
        [MMU_PAGE_4K] = {
                .shift  = 12,
        },
-#else
        [MMU_PAGE_16K] = {
                .shift  = 14,
        },
-#endif
        [MMU_PAGE_512K] = {
                .shift  = 19,
        },
index f4e20d8..63f61d8 100644 (file)
@@ -430,7 +430,7 @@ static int of_get_assoc_arrays(struct assoc_arrays *aa)
  * This is like of_node_to_nid_single() for memory represented in the
  * ibm,dynamic-reconfiguration-memory node.
  */
-static int of_drconf_to_nid_single(struct drmem_lmb *lmb)
+int of_drconf_to_nid_single(struct drmem_lmb *lmb)
 {
        struct assoc_arrays aa = { .arrays = NULL };
        int default_nid = NUMA_NO_NODE;
@@ -507,6 +507,11 @@ static int numa_setup_cpu(unsigned long lcpu)
        int fcpu = cpu_first_thread_sibling(lcpu);
        int nid = NUMA_NO_NODE;
 
+       if (!cpu_present(lcpu)) {
+               set_cpu_numa_node(lcpu, first_online_node);
+               return first_online_node;
+       }
+
        /*
         * If a valid cpu-to-node mapping is already available, use it
         * directly instead of querying the firmware, since it represents
@@ -723,21 +728,22 @@ static int __init parse_numa_properties(void)
         */
        for_each_present_cpu(i) {
                struct device_node *cpu;
-               int nid;
-
-               cpu = of_get_cpu_node(i, NULL);
-               BUG_ON(!cpu);
-               nid = of_node_to_nid_single(cpu);
-               of_node_put(cpu);
+               int nid = vphn_get_nid(i);
 
                /*
                 * Don't fall back to default_nid yet -- we will plug
                 * cpus into nodes once the memory scan has discovered
                 * the topology.
                 */
-               if (nid < 0)
-                       continue;
-               node_set_online(nid);
+               if (nid == NUMA_NO_NODE) {
+                       cpu = of_get_cpu_node(i, NULL);
+                       BUG_ON(!cpu);
+                       nid = of_node_to_nid_single(cpu);
+                       of_node_put(cpu);
+               }
+
+               if (likely(nid > 0))
+                       node_set_online(nid);
        }
 
        get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells);
@@ -888,7 +894,9 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn)
 static void __init find_possible_nodes(void)
 {
        struct device_node *rtas;
-       u32 numnodes, i;
+       const __be32 *domains;
+       int prop_length, max_nodes;
+       u32 i;
 
        if (!numa_enabled)
                return;
@@ -897,16 +905,31 @@ static void __init find_possible_nodes(void)
        if (!rtas)
                return;
 
-       if (of_property_read_u32_index(rtas,
-                               "ibm,max-associativity-domains",
-                               min_common_depth, &numnodes))
-               goto out;
+       /*
+        * ibm,current-associativity-domains is a fairly recent property. If
+        * it doesn't exist, then fallback on ibm,max-associativity-domains.
+        * Current denotes what the platform can support compared to max
+        * which denotes what the Hypervisor can support.
+        */
+       domains = of_get_property(rtas, "ibm,current-associativity-domains",
+                                       &prop_length);
+       if (!domains) {
+               domains = of_get_property(rtas, "ibm,max-associativity-domains",
+                                       &prop_length);
+               if (!domains)
+                       goto out;
+       }
 
-       for (i = 0; i < numnodes; i++) {
+       max_nodes = of_read_number(&domains[min_common_depth], 1);
+       for (i = 0; i < max_nodes; i++) {
                if (!node_possible(i))
                        node_set(i, node_possible_map);
        }
 
+       prop_length /= sizeof(int);
+       if (prop_length > min_common_depth + 2)
+               coregroup_enabled = 1;
+
 out:
        of_node_put(rtas);
 }
@@ -915,6 +938,16 @@ void __init mem_topology_setup(void)
 {
        int cpu;
 
+       /*
+        * Linux/mm assumes node 0 to be online at boot. However this is not
+        * true on PowerPC, where node 0 is similar to any other node, it
+        * could be cpuless, memoryless node. So force node 0 to be offline
+        * for now. This will prevent cpuless, memoryless node 0 showing up
+        * unnecessarily as online. If a node has cpus or memory that need
+        * to be online, then node will anyway be marked online.
+        */
+       node_set_offline(0);
+
        if (parse_numa_properties())
                setup_nonnuma();
 
@@ -932,8 +965,17 @@ void __init mem_topology_setup(void)
 
        reset_numa_cpu_lookup_table();
 
-       for_each_present_cpu(cpu)
+       for_each_possible_cpu(cpu) {
+               /*
+                * Powerpc with CONFIG_NUMA always used to have a node 0,
+                * even if it was memoryless or cpuless. For all cpus that
+                * are possible but not present, cpu_to_node() would point
+                * to node 0. To remove a cpuless, memoryless dummy node,
+                * powerpc need to make sure all possible but not present
+                * cpu_to_node are set to a proper node.
+                */
                numa_setup_cpu(cpu);
+       }
 }
 
 void __init initmem_init(void)
@@ -1200,6 +1242,31 @@ int find_and_online_cpu_nid(int cpu)
        return new_nid;
 }
 
+int cpu_to_coregroup_id(int cpu)
+{
+       __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};
+       int index;
+
+       if (cpu < 0 || cpu > nr_cpu_ids)
+               return -1;
+
+       if (!coregroup_enabled)
+               goto out;
+
+       if (!firmware_has_feature(FW_FEATURE_VPHN))
+               goto out;
+
+       if (vphn_get_associativity(cpu, associativity))
+               goto out;
+
+       index = of_read_number(associativity, 1);
+       if (index > min_common_depth + 1)
+               return of_read_number(&associativity[index - 1], 1);
+
+out:
+       return cpu_to_core_id(cpu);
+}
+
 static int topology_update_init(void)
 {
        topology_inited = 1;
index ab57b07..15555c9 100644 (file)
@@ -263,8 +263,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_
        pmd_t *pmd = pmd_off(mm, addr);
        pte_basic_t val;
        pte_basic_t *entry = &ptep->pte;
-       int num = is_hugepd(*((hugepd_t *)pmd)) ? 1 : SZ_512K / SZ_4K;
-       int i;
+       int num, i;
 
        /*
         * Make sure hardware valid bit is not set. We don't do
@@ -275,6 +274,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_
        pte = set_pte_filter(pte);
 
        val = pte_val(pte);
+
+       num = number_of_cells_per_pte(pmd, val, 1);
+
        for (i = 0; i < num; i++, entry++, val += SZ_4K)
                *entry = val;
 }
index 8a797dc..86da2a6 100644 (file)
 
 static const struct flag_info flag_array[] = {
        {
+#ifdef CONFIG_PPC_16K_PAGES
                .mask   = _PAGE_HUGE,
                .val    = _PAGE_HUGE,
+#else
+               .mask   = _PAGE_SPS,
+               .val    = _PAGE_SPS,
+#endif
                .set    = "huge",
                .clear  = "    ",
        }, {
index e29b338..c4c628b 100644 (file)
 
 #include "ptdump.h"
 
-static char *pp_601(int k, int pp)
-{
-       if (pp == 0)
-               return k ? "   " : "rwx";
-       if (pp == 1)
-               return k ? "r x" : "rwx";
-       if (pp == 2)
-               return "rwx";
-       return "r x";
-}
-
-static void bat_show_601(struct seq_file *m, int idx, u32 lower, u32 upper)
-{
-       u32 blpi = upper & 0xfffe0000;
-       u32 k = (upper >> 2) & 3;
-       u32 pp = upper & 3;
-       phys_addr_t pbn = PHYS_BAT_ADDR(lower);
-       u32 bsm = lower & 0x3ff;
-       u32 size = (bsm + 1) << 17;
-
-       seq_printf(m, "%d: ", idx);
-       if (!(lower & 0x40)) {
-               seq_puts(m, "        -\n");
-               return;
-       }
-
-       seq_printf(m, "0x%08x-0x%08x ", blpi, blpi + size - 1);
-#ifdef CONFIG_PHYS_64BIT
-       seq_printf(m, "0x%016llx ", pbn);
-#else
-       seq_printf(m, "0x%08x ", pbn);
-#endif
-       pt_dump_size(m, size);
-
-       seq_printf(m, "Kernel %s User %s", pp_601(k & 2, pp), pp_601(k & 1, pp));
-
-       seq_puts(m, lower & _PAGE_WRITETHRU ? "w " : "  ");
-       seq_puts(m, lower & _PAGE_NO_CACHE ? "i " : "  ");
-       seq_puts(m, lower & _PAGE_COHERENT ? "m " : "  ");
-       seq_puts(m, "\n");
-}
-
-#define BAT_SHOW_601(_m, _n, _l, _u) bat_show_601(_m, _n, mfspr(_l), mfspr(_u))
-
-static int bats_show_601(struct seq_file *m, void *v)
-{
-       seq_puts(m, "---[ Block Address Translation ]---\n");
-
-       BAT_SHOW_601(m, 0, SPRN_IBAT0L, SPRN_IBAT0U);
-       BAT_SHOW_601(m, 1, SPRN_IBAT1L, SPRN_IBAT1U);
-       BAT_SHOW_601(m, 2, SPRN_IBAT2L, SPRN_IBAT2U);
-       BAT_SHOW_601(m, 3, SPRN_IBAT3L, SPRN_IBAT3U);
-
-       return 0;
-}
-
 static void bat_show_603(struct seq_file *m, int idx, u32 lower, u32 upper, bool is_d)
 {
        u32 bepi = upper & 0xfffe0000;
@@ -146,9 +90,6 @@ static int bats_show_603(struct seq_file *m, void *v)
 
 static int bats_open(struct inode *inode, struct file *file)
 {
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_601))
-               return single_open(file, bats_show_601, NULL);
-
        return single_open(file, bats_show_603, NULL);
 }
 
index df59d0b..489f993 100644 (file)
@@ -572,7 +572,7 @@ void spu_sync_buffer(int spu_num, unsigned int *samples,
                 * samples are recorded.
                 * No big deal -- so we just drop a few samples.
                 */
-               pr_debug("SPU_PROF: No cached SPU contex "
+               pr_debug("SPU_PROF: No cached SPU context "
                          "for SPU #%d. Dropping samples.\n", spu_num);
                goto out;
        }
index e608f9d..8965b44 100644 (file)
@@ -95,7 +95,7 @@ REQUEST(__field(0,    8,      partition_id)
 
 #define REQUEST_NAME system_performance_capabilities
 #define REQUEST_NUM 0x40
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__field(0,     1,      perf_collect_privileged)
        __field(0x1,    1,      capability_mask)
@@ -223,7 +223,7 @@ REQUEST(__field(0,  2, partition_id)
 
 #define REQUEST_NAME system_hypervisor_times
 #define REQUEST_NUM 0xF0
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__count(0,     8,      time_spent_to_dispatch_virtual_processors)
        __count(0x8,    8,      time_spent_processing_virtual_processor_timers)
@@ -234,7 +234,7 @@ REQUEST(__count(0,  8,      time_spent_to_dispatch_virtual_processors)
 
 #define REQUEST_NAME system_tlbie_count_and_time
 #define REQUEST_NUM 0xF4
-#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
+#define REQUEST_IDX_KIND "starting_index=0xffffffff"
 #include I(REQUEST_BEGIN)
 REQUEST(__count(0,     8,      tlbie_instructions_issued)
        /*
index 6884d16..d48413e 100644 (file)
@@ -48,6 +48,8 @@ EVENT_DEFINE_RANGE_FORMAT(length, config1, 24, 31);
 /* u32, byte offset */
 EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
 
+static cpumask_t hv_gpci_cpumask;
+
 static struct attribute *format_attrs[] = {
        &format_attr_request.attr,
        &format_attr_starting_index.attr,
@@ -94,7 +96,15 @@ static ssize_t kernel_version_show(struct device *dev,
        return sprintf(page, "0x%x\n", COUNTER_INFO_VERSION_CURRENT);
 }
 
+static ssize_t cpumask_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       return cpumap_print_to_pagebuf(true, buf, &hv_gpci_cpumask);
+}
+
 static DEVICE_ATTR_RO(kernel_version);
+static DEVICE_ATTR_RO(cpumask);
+
 HV_CAPS_ATTR(version, "0x%x\n");
 HV_CAPS_ATTR(ga, "%d\n");
 HV_CAPS_ATTR(expanded, "%d\n");
@@ -111,6 +121,15 @@ static struct attribute *interface_attrs[] = {
        NULL,
 };
 
+static struct attribute *cpumask_attrs[] = {
+       &dev_attr_cpumask.attr,
+       NULL,
+};
+
+static struct attribute_group cpumask_attr_group = {
+       .attrs = cpumask_attrs,
+};
+
 static struct attribute_group interface_group = {
        .name = "interface",
        .attrs = interface_attrs,
@@ -120,20 +139,12 @@ static const struct attribute_group *attr_groups[] = {
        &format_group,
        &event_group,
        &interface_group,
+       &cpumask_attr_group,
        NULL,
 };
 
-#define HGPCI_REQ_BUFFER_SIZE  4096
-#define HGPCI_MAX_DATA_BYTES \
-       (HGPCI_REQ_BUFFER_SIZE - sizeof(struct hv_get_perf_counter_info_params))
-
 static DEFINE_PER_CPU(char, hv_gpci_reqb[HGPCI_REQ_BUFFER_SIZE]) __aligned(sizeof(uint64_t));
 
-struct hv_gpci_request_buffer {
-       struct hv_get_perf_counter_info_params params;
-       uint8_t bytes[HGPCI_MAX_DATA_BYTES];
-} __packed;
-
 static unsigned long single_gpci_request(u32 req, u32 starting_index,
                u16 secondary_index, u8 version_in, u32 offset, u8 length,
                u64 *value)
@@ -275,6 +286,45 @@ static struct pmu h_gpci_pmu = {
        .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
 };
 
+static int ppc_hv_gpci_cpu_online(unsigned int cpu)
+{
+       if (cpumask_empty(&hv_gpci_cpumask))
+               cpumask_set_cpu(cpu, &hv_gpci_cpumask);
+
+       return 0;
+}
+
+static int ppc_hv_gpci_cpu_offline(unsigned int cpu)
+{
+       int target;
+
+       /* Check if exiting cpu is used for collecting gpci events */
+       if (!cpumask_test_and_clear_cpu(cpu, &hv_gpci_cpumask))
+               return 0;
+
+       /* Find a new cpu to collect gpci events */
+       target = cpumask_last(cpu_active_mask);
+
+       if (target < 0 || target >= nr_cpu_ids) {
+               pr_err("hv_gpci: CPU hotplug init failed\n");
+               return -1;
+       }
+
+       /* Migrate gpci events to the new target */
+       cpumask_set_cpu(target, &hv_gpci_cpumask);
+       perf_pmu_migrate_context(&h_gpci_pmu, cpu, target);
+
+       return 0;
+}
+
+static int hv_gpci_cpu_hotplug_init(void)
+{
+       return cpuhp_setup_state(CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE,
+                         "perf/powerpc/hv_gcpi:online",
+                         ppc_hv_gpci_cpu_online,
+                         ppc_hv_gpci_cpu_offline);
+}
+
 static int hv_gpci_init(void)
 {
        int r;
@@ -295,6 +345,11 @@ static int hv_gpci_init(void)
                return -ENODEV;
        }
 
+       /* init cpuhotplug */
+       r = hv_gpci_cpu_hotplug_init();
+       if (r)
+               return r;
+
        /* sampling not supported */
        h_gpci_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
 
index a3053ed..4d10826 100644 (file)
@@ -2,33 +2,6 @@
 #ifndef LINUX_POWERPC_PERF_HV_GPCI_H_
 #define LINUX_POWERPC_PERF_HV_GPCI_H_
 
-#include <linux/types.h>
-
-/* From the document "H_GetPerformanceCounterInfo Interface" v1.07 */
-
-/* H_GET_PERF_COUNTER_INFO argument */
-struct hv_get_perf_counter_info_params {
-       __be32 counter_request; /* I */
-       __be32 starting_index;  /* IO */
-       __be16 secondary_index; /* IO */
-       __be16 returned_values; /* O */
-       __be32 detail_rc; /* O, only needed when called via *_norets() */
-
-       /*
-        * O, size each of counter_value element in bytes, only set for version
-        * >= 0x3
-        */
-       __be16 cv_element_size;
-
-       /* I, 0 (zero) for versions < 0x3 */
-       __u8 counter_info_version_in;
-
-       /* O, 0 (zero) if version < 0x3. Must be set to 0 when making hcall */
-       __u8 counter_info_version_out;
-       __u8 reserved[0xC];
-       __u8 counter_value[];
-} __packed;
-
 /*
  * counter info version => fw version/reference (spec version)
  *
index 62d0b54..9ed4fcc 100644 (file)
@@ -1426,8 +1426,6 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
 
 static int trace_imc_event_init(struct perf_event *event)
 {
-       struct task_struct *target;
-
        if (event->attr.type != event->pmu->type)
                return -ENOENT;
 
@@ -1458,7 +1456,6 @@ static int trace_imc_event_init(struct perf_event *event)
        mutex_unlock(&imc_global_refc.lock);
 
        event->hw.idx = -1;
-       target = event->hw.target;
 
        event->pmu->task_ctx_nr = perf_hw_context;
        event->destroy = reset_global_refc;
index 964437a..2848904 100644 (file)
@@ -288,6 +288,15 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
 
                mask  |= CNST_PMC_MASK(pmc);
                value |= CNST_PMC_VAL(pmc);
+
+               /*
+                * PMC5 and PMC6 are used to count cycles and instructions and
+                * they do not support most of the constraint bits. Add a check
+                * to exclude PMC5/6 from most of the constraints except for
+                * EBB/BHRB.
+                */
+               if (pmc >= 5)
+                       goto ebb_bhrb;
        }
 
        if (pmc <= 4) {
@@ -357,6 +366,7 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
                }
        }
 
+ebb_bhrb:
        if (!pmc && ebb)
                /* EBB events must specify the PMC */
                return -1;
index 044de65..7025de5 100644 (file)
@@ -13,6 +13,8 @@
 #include <asm/firmware.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 #define EVENT_EBB_MASK         1ull
 #define EVENT_EBB_SHIFT                PERF_EVENT_CONFIG_EBB_SHIFT
 #define EVENT_BHRB_MASK                1ull
index 8314865..9dbe8f9 100644 (file)
@@ -9,7 +9,6 @@
 #define pr_fmt(fmt)    "power10-pmu: " fmt
 
 #include "isa207-common.h"
-#include "internal.h"
 
 /*
  * Raw event encoding for Power10:
index a62b2cd..3e64b4a 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 /*
  * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
  */
index 8732b58..017bb19 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 /*
  * Bits in event code for POWER5 (not POWER5++)
  */
index 0e318cf..1899744 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 /*
  * Bits in event code for POWER6
  */
index 5e0bf09..bacfab1 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 /*
  * Bits in event code for POWER7
  */
index d35223f..7d78df9 100644 (file)
@@ -9,6 +9,8 @@
 #include <asm/reg.h>
 #include <asm/cputable.h>
 
+#include "internal.h"
+
 /*
  * Bits in event code for PPC970
  */
index 90ad6ac..a5c898b 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/ptrace.h>
 
 #include <asm/reg.h>
+#include <asm/cacheflush.h>
 
 int machine_check_440A(struct pt_regs *regs)
 {
index cba83ee..07f7e3c 100644 (file)
@@ -86,8 +86,7 @@ static void __noreturn avr_reset_system(char *cmd)
        avr_halt_system(AVR_PWRCTL_RESET);
 }
 
-static int avr_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
+static int avr_probe(struct i2c_client *client)
 {
        avr_i2c_client = client;
        ppc_md.restart = avr_reset_system;
@@ -104,7 +103,7 @@ static struct i2c_driver avr_driver = {
        .driver = {
                .name = "akebono-avr",
        },
-       .probe = avr_probe,
+       .probe_new = avr_probe,
        .id_table = avr_id,
 };
 
index 0967bdf..4094810 100644 (file)
@@ -142,7 +142,7 @@ static int mcu_gpiochip_remove(struct mcu *mcu)
        return 0;
 }
 
-static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int mcu_probe(struct i2c_client *client)
 {
        struct mcu *mcu;
        int ret;
@@ -221,7 +221,7 @@ static struct i2c_driver mcu_driver = {
                .name = "mcu-mpc8349emitx",
                .of_match_table = mcu_of_match_table,
        },
-       .probe = mcu_probe,
+       .probe_new = mcu_probe,
        .remove = mcu_remove,
        .id_table = mcu_ids,
 };
index fda108b..c6df294 100644 (file)
@@ -112,7 +112,7 @@ static void mpc85xx_take_timebase(void)
        local_irq_restore(flags);
 }
 
-static void smp_85xx_mach_cpu_die(void)
+static void smp_85xx_cpu_offline_self(void)
 {
        unsigned int cpu = smp_processor_id();
 
@@ -506,7 +506,7 @@ void __init mpc85xx_smp_init(void)
        if (qoriq_pm_ops) {
                smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
                smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
-               ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+               smp_85xx_ops.cpu_offline_self = smp_85xx_cpu_offline_self;
                smp_85xx_ops.cpu_die = qoriq_cpu_kill;
        }
 #endif
index fb7515b..7a5e8f4 100644 (file)
@@ -199,21 +199,6 @@ source "drivers/cpuidle/Kconfig"
 
 endmenu
 
-config PPC601_SYNC_FIX
-       bool "Workarounds for PPC601 bugs"
-       depends on PPC_BOOK3S_601 && PPC_PMAC
-       default y
-       help
-         Some versions of the PPC601 (the first PowerPC chip) have bugs which
-         mean that extra synchronization instructions are required near
-         certain instructions, typically those that make major changes to the
-         CPU state.  These extra instructions reduce performance slightly.
-         If you say N here, these extra instructions will not be included,
-         resulting in a kernel which will run faster but may not run at all
-         on some systems with the PPC601 chip.
-
-         If in doubt, say Y here.
-
 config TAU
        bool "On-chip CPU temperature sensor support"
        depends on PPC_BOOK3S_32
@@ -223,12 +208,11 @@ config TAU
          temperature within 2-4 degrees Celsius. This option shows the current
          on-die temperature in /proc/cpuinfo if the cpu supports it.
 
-         Unfortunately, on some chip revisions, this sensor is very inaccurate
-         and in many cases, does not work at all, so don't assume the cpu
-         temp is actually what /proc/cpuinfo says it is.
+         Unfortunately, this sensor is very inaccurate when uncalibrated, so
+         don't assume the cpu temp is actually what /proc/cpuinfo says it is.
 
 config TAU_INT
-       bool "Interrupt driven TAU driver (DANGEROUS)"
+       bool "Interrupt driven TAU driver (EXPERIMENTAL)"
        depends on TAU
        help
          The TAU supports an interrupt driven mode which causes an interrupt
@@ -236,12 +220,7 @@ config TAU_INT
          to get notified the temp has exceeded a range. With this option off,
          a timer is used to re-check the temperature periodically.
 
-         However, on some cpus it appears that the TAU interrupt hardware
-         is buggy and can cause a situation which would lead unexplained hard
-         lockups.
-
-         Unless you are extending the TAU driver, or enjoy kernel/hardware
-         debugging, leave this option off.
+         If in doubt, say N here.
 
 config TAU_AVERAGE
        bool "Average high and low temp"
index 1dc9d3c..c194c4a 100644 (file)
@@ -20,7 +20,7 @@ choice
        depends on PPC32
        help
          There are five families of 32 bit PowerPC chips supported.
-         The most common ones are the desktop and server CPUs (601, 603,
+         The most common ones are the desktop and server CPUs (603,
          604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
          embedded 512x/52xx/82xx/83xx/86xx counterparts.
          The other embedded parts, namely 4xx, 8xx, e200 (55xx) and e500
@@ -30,7 +30,7 @@ choice
          If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
 
 config PPC_BOOK3S_6xx
-       bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx except 601"
+       bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
        select PPC_BOOK3S_32
        select PPC_FPU
        select PPC_HAVE_PMU_SUPPORT
@@ -38,13 +38,6 @@ config PPC_BOOK3S_6xx
        select PPC_HAVE_KUAP
        select HAVE_ARCH_VMAP_STACK if !ADB_PMU
 
-config PPC_BOOK3S_601
-       bool "PowerPC 601"
-       select PPC_BOOK3S_32
-       select PPC_FPU
-       select PPC_HAVE_KUAP
-       select HAVE_ARCH_VMAP_STACK
-
 config PPC_85xx
        bool "Freescale 85xx"
        select E500
@@ -490,13 +483,12 @@ endmenu
 
 config VDSO32
        def_bool y
-       depends on PPC32 || CPU_BIG_ENDIAN
+       depends on PPC32 || COMPAT
        help
          This symbol controls whether we build the 32-bit VDSO. We obviously
          want to do that if we're building a 32-bit kernel. If we're building
-         a 64-bit kernel then we only want a 32-bit VDSO if we're building for
-         big endian. That is because the only little endian configuration we
-         support is ppc64le which is 64-bit only.
+         a 64-bit kernel then we only want a 32-bit VDSO if we're also enabling
+         COMPAT.
 
 choice
        prompt "Endianness selection"
index 15437ab..b95c338 100644 (file)
@@ -147,7 +147,8 @@ static void __noreturn mpc7448_hpc2_restart(char *cmd)
        local_irq_disable();
 
        /* Set exception prefix high - to the firmware */
-       _nmask_and_or_msr(0, MSR_IP);
+       mtmsr(mfmsr() | MSR_IP);
+       isync();
 
        for (;;) ;              /* Spin until reset happens */
 }
index ed1914d..e346ddc 100644 (file)
@@ -101,7 +101,8 @@ static void __noreturn storcenter_restart(char *cmd)
        local_irq_disable();
 
        /* Set exception prefix high - to the firmware */
-       _nmask_and_or_msr(0, MSR_IP);
+       mtmsr(mfmsr() | MSR_IP);
+       isync();
 
        /* Wait for reset to happen */
        for (;;) ;
index 16a52af..0d715db 100644 (file)
@@ -34,7 +34,7 @@ extern void pmac_check_ht_link(void);
 
 extern void pmac_setup_smp(void);
 extern int psurge_secondary_virq;
-extern void low_cpu_die(void) __attribute__((noreturn));
+extern void low_cpu_offline_self(void) __attribute__((noreturn));
 
 extern int pmac_nvram_init(void);
 extern void pmac_pic_init(void);
index f002b0f..2e2cc0c 100644 (file)
@@ -284,7 +284,7 @@ static void __init pmac_setup_arch(void)
                                /* 604, G3, G4 etc. */
                                loops_per_jiffy = *fp / HZ;
                        else
-                               /* 601, 603, etc. */
+                               /* 603, etc. */
                                loops_per_jiffy = *fp / (2 * HZ);
                        of_node_put(cpu);
                        break;
index f9a680f..7e0f8ba 100644 (file)
@@ -201,8 +201,8 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
        addi r3,r3,sleep_storage@l
        stw r5,0(r3)
 
-       .globl  low_cpu_die
-low_cpu_die:
+       .globl  low_cpu_offline_self
+low_cpu_offline_self:
        /* Flush & disable all caches */
        bl      flush_disable_caches
 
@@ -244,7 +244,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
        mtmsr   r2
        isync
        b       1b
-_ASM_NOKPROBE_SYMBOL(low_cpu_die)
+_ASM_NOKPROBE_SYMBOL(low_cpu_offline_self)
 /*
  * Here is the resume code.
  */
@@ -294,14 +294,7 @@ grackle_wake_up:
         * we do any r1 memory access as we are not sure they
         * are in a sane state above the first 256Mb region
         */
-       li      r0,16           /* load up segment register values */
-       mtctr   r0              /* for context 0 */
-       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
-       li      r4,0
-3:     mtsrin  r3,r4
-       addi    r3,r3,0x111     /* increment VSID */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
+       bl      load_segment_registers
        sync
        isync
 
index eb23264..74ebe66 100644 (file)
@@ -270,10 +270,6 @@ static void __init smp_psurge_probe(void)
        int i, ncpus;
        struct device_node *dn;
 
-       /* We don't do SMP on the PPC601 -- paulus */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               return;
-
        /*
         * The powersurge cpu board can be used in the generation
         * of powermacs that have a socket for an upgradeable cpu card,
@@ -920,7 +916,7 @@ static int smp_core99_cpu_disable(void)
 
 #ifdef CONFIG_PPC32
 
-static void pmac_cpu_die(void)
+static void pmac_cpu_offline_self(void)
 {
        int cpu = smp_processor_id();
 
@@ -930,12 +926,12 @@ static void pmac_cpu_die(void)
        generic_set_cpu_dead(cpu);
        smp_wmb();
        mb();
-       low_cpu_die();
+       low_cpu_offline_self();
 }
 
 #else /* CONFIG_PPC32 */
 
-static void pmac_cpu_die(void)
+static void pmac_cpu_offline_self(void)
 {
        int cpu = smp_processor_id();
 
@@ -1020,7 +1016,7 @@ void __init pmac_setup_smp(void)
 #endif /* CONFIG_PPC_PMAC32_PSURGE */
 
 #ifdef CONFIG_HOTPLUG_CPU
-       ppc_md.cpu_die = pmac_cpu_die;
+       smp_ops->cpu_offline_self = pmac_cpu_offline_self;
 #endif
 }
 
index 9af8c3b..89e22c4 100644 (file)
 
 static int eeh_event_irq = -EINVAL;
 
-void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
+static void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
 {
        dev_dbg(&pdev->dev, "EEH: Setting up device\n");
        eeh_probe_device(pdev);
 }
 
-static int pnv_eeh_init(void)
-{
-       struct pci_controller *hose;
-       struct pnv_phb *phb;
-       int max_diag_size = PNV_PCI_DIAG_BUF_SIZE;
-
-       if (!firmware_has_feature(FW_FEATURE_OPAL)) {
-               pr_warn("%s: OPAL is required !\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       /* Set probe mode */
-       eeh_add_flag(EEH_PROBE_MODE_DEV);
-
-       /*
-        * P7IOC blocks PCI config access to frozen PE, but PHB3
-        * doesn't do that. So we have to selectively enable I/O
-        * prior to collecting error log.
-        */
-       list_for_each_entry(hose, &hose_list, list_node) {
-               phb = hose->private_data;
-
-               if (phb->model == PNV_PHB_MODEL_P7IOC)
-                       eeh_add_flag(EEH_ENABLE_IO_FOR_LOG);
-
-               if (phb->diag_data_size > max_diag_size)
-                       max_diag_size = phb->diag_data_size;
-
-               /*
-                * PE#0 should be regarded as valid by EEH core
-                * if it's not the reserved one. Currently, we
-                * have the reserved PE#255 and PE#127 for PHB3
-                * and P7IOC separately. So we should regard
-                * PE#0 as valid for PHB3 and P7IOC.
-                */
-               if (phb->ioda.reserved_pe_idx != 0)
-                       eeh_add_flag(EEH_VALID_PE_ZERO);
-
-               break;
-       }
-
-       eeh_set_pe_aux_size(max_diag_size);
-       ppc_md.pcibios_bus_add_device = pnv_pcibios_bus_add_device;
-
-       return 0;
-}
-
 static irqreturn_t pnv_eeh_event(int irq, void *data)
 {
        /*
@@ -135,7 +87,7 @@ static ssize_t pnv_eeh_ei_write(struct file *filp,
                return -EINVAL;
 
        /* Retrieve PE */
-       pe = eeh_pe_get(hose, pe_no, 0);
+       pe = eeh_pe_get(hose, pe_no);
        if (!pe)
                return -ENODEV;
 
@@ -190,7 +142,7 @@ PNV_EEH_DBGFS_ENTRY(inbB, 0xE10);
 
 #endif /* CONFIG_DEBUG_FS */
 
-void pnv_eeh_enable_phbs(void)
+static void pnv_eeh_enable_phbs(void)
 {
        struct pci_controller *hose;
        struct pnv_phb *phb;
@@ -354,7 +306,7 @@ static struct eeh_pe *pnv_eeh_get_upstream_pe(struct pci_dev *pdev)
        if (parent) {
                struct pnv_ioda_pe *ioda_pe = pnv_ioda_get_pe(parent);
 
-               return eeh_pe_get(phb->hose, ioda_pe->pe_number, 0);
+               return eeh_pe_get(phb->hose, ioda_pe->pe_number);
        }
 
        return NULL;
@@ -1406,7 +1358,7 @@ static int pnv_eeh_get_pe(struct pci_controller *hose,
        }
 
        /* Find the PE according to PE# */
-       dev_pe = eeh_pe_get(hose, pe_no, 0);
+       dev_pe = eeh_pe_get(hose, pe_no);
        if (!dev_pe)
                return -EEXIST;
 
@@ -1674,7 +1626,6 @@ static int pnv_eeh_restore_config(struct eeh_dev *edev)
 
 static struct eeh_ops pnv_eeh_ops = {
        .name                   = "powernv",
-       .init                   = pnv_eeh_init,
        .probe                  = pnv_eeh_probe,
        .set_option             = pnv_eeh_set_option,
        .get_state              = pnv_eeh_get_state,
@@ -1715,9 +1666,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pnv_pci_fixup_vf_mps);
  */
 static int __init eeh_powernv_init(void)
 {
+       int max_diag_size = PNV_PCI_DIAG_BUF_SIZE;
+       struct pci_controller *hose;
+       struct pnv_phb *phb;
        int ret = -EINVAL;
 
-       ret = eeh_ops_register(&pnv_eeh_ops);
+       if (!firmware_has_feature(FW_FEATURE_OPAL)) {
+               pr_warn("%s: OPAL is required !\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Set probe mode */
+       eeh_add_flag(EEH_PROBE_MODE_DEV);
+
+       /*
+        * P7IOC blocks PCI config access to frozen PE, but PHB3
+        * doesn't do that. So we have to selectively enable I/O
+        * prior to collecting error log.
+        */
+       list_for_each_entry(hose, &hose_list, list_node) {
+               phb = hose->private_data;
+
+               if (phb->model == PNV_PHB_MODEL_P7IOC)
+                       eeh_add_flag(EEH_ENABLE_IO_FOR_LOG);
+
+               if (phb->diag_data_size > max_diag_size)
+                       max_diag_size = phb->diag_data_size;
+
+               break;
+       }
+
+       /*
+        * eeh_init() allocates the eeh_pe and its aux data buf so the
+        * size needs to be set before calling eeh_init().
+        */
+       eeh_set_pe_aux_size(max_diag_size);
+       ppc_md.pcibios_bus_add_device = pnv_pcibios_bus_add_device;
+
+       ret = eeh_init(&pnv_eeh_ops);
        if (!ret)
                pr_info("EEH: PowerNV platform initialized\n");
        else
@@ -1725,4 +1711,4 @@ static int __init eeh_powernv_init(void)
 
        return ret;
 }
-machine_early_initcall(powernv, eeh_powernv_init);
+machine_arch_initcall(powernv, eeh_powernv_init);
index 345ab06..1ed7c52 100644 (file)
@@ -565,7 +565,7 @@ void power7_idle_type(unsigned long type)
        irq_set_pending_from_srr1(srr1);
 }
 
-void power7_idle(void)
+static void power7_idle(void)
 {
        if (!powersave_nap)
                return;
@@ -659,20 +659,6 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
                mmcr0           = mfspr(SPRN_MMCR0);
        }
 
-       if (cpu_has_feature(CPU_FTR_ARCH_31)) {
-               /*
-                * POWER10 uses MMCRA (BHRBRD) as BHRB disable bit.
-                * If the user hasn't asked for the BHRB to be
-                * written, the value of MMCRA[BHRBRD] is 1.
-                * On wakeup from stop, MMCRA[BHRBD] will be 0,
-                * since it is previleged resource and will be lost.
-                * Thus, if we do not save and restore the MMCRA[BHRBD],
-                * hardware will be needlessly writing to the BHRB
-                * in problem mode.
-                */
-               mmcra           = mfspr(SPRN_MMCRA);
-       }
-
        if ((psscr & PSSCR_RL_MASK) >= deep_spr_loss_state) {
                sprs.lpcr       = mfspr(SPRN_LPCR);
                sprs.hfscr      = mfspr(SPRN_HFSCR);
@@ -735,10 +721,6 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
                        mtspr(SPRN_MMCR0, mmcr0);
                }
 
-               /* Reload MMCRA to restore BHRB disable bit for POWER10 */
-               if (cpu_has_feature(CPU_FTR_ARCH_31))
-                       mtspr(SPRN_MMCRA, mmcra);
-
                /*
                 * DD2.2 and earlier need to set then clear bit 60 in MMCRA
                 * to ensure the PMU starts running.
@@ -823,73 +805,6 @@ out:
        return srr1;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static unsigned long power9_offline_stop(unsigned long psscr)
-{
-       unsigned long srr1;
-
-#ifndef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-       __ppc64_runlatch_off();
-       srr1 = power9_idle_stop(psscr, true);
-       __ppc64_runlatch_on();
-#else
-       /*
-        * Tell KVM we're entering idle.
-        * This does not have to be done in real mode because the P9 MMU
-        * is independent per-thread. Some steppings share radix/hash mode
-        * between threads, but in that case KVM has a barrier sync in real
-        * mode before and after switching between radix and hash.
-        *
-        * kvm_start_guest must still be called in real mode though, hence
-        * the false argument.
-        */
-       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_IDLE;
-
-       __ppc64_runlatch_off();
-       srr1 = power9_idle_stop(psscr, false);
-       __ppc64_runlatch_on();
-
-       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_KERNEL;
-       /* Order setting hwthread_state vs. testing hwthread_req */
-       smp_mb();
-       if (local_paca->kvm_hstate.hwthread_req)
-               srr1 = idle_kvm_start_guest(srr1);
-       mtmsr(MSR_KERNEL);
-#endif
-
-       return srr1;
-}
-#endif
-
-void power9_idle_type(unsigned long stop_psscr_val,
-                                     unsigned long stop_psscr_mask)
-{
-       unsigned long psscr;
-       unsigned long srr1;
-
-       if (!prep_irq_for_idle_irqsoff())
-               return;
-
-       psscr = mfspr(SPRN_PSSCR);
-       psscr = (psscr & ~stop_psscr_mask) | stop_psscr_val;
-
-       __ppc64_runlatch_off();
-       srr1 = power9_idle_stop(psscr, true);
-       __ppc64_runlatch_on();
-
-       fini_irq_for_idle_irqsoff();
-
-       irq_set_pending_from_srr1(srr1);
-}
-
-/*
- * Used for ppc_md.power_save which needs a function with no parameters
- */
-void power9_idle(void)
-{
-       power9_idle_type(pnv_default_stop_val, pnv_default_stop_mask);
-}
-
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 /*
  * This is used in working around bugs in thread reconfiguration
@@ -962,6 +877,198 @@ void pnv_power9_force_smt4_release(void)
 EXPORT_SYMBOL_GPL(pnv_power9_force_smt4_release);
 #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 
+struct p10_sprs {
+       /*
+        * SPRs that get lost in shallow states:
+        *
+        * P10 loses CR, LR, CTR, FPSCR, VSCR, XER, TAR, SPRG2, and HSPRG1
+        * isa300 idle routines restore CR, LR.
+        * CTR is volatile
+        * idle thread doesn't use FP or VEC
+        * kernel doesn't use TAR
+        * HSPRG1 is only live in HV interrupt entry
+        * SPRG2 is only live in KVM guests, KVM handles it.
+        */
+};
+
+static unsigned long power10_idle_stop(unsigned long psscr, bool mmu_on)
+{
+       int cpu = raw_smp_processor_id();
+       int first = cpu_first_thread_sibling(cpu);
+       unsigned long *state = &paca_ptrs[first]->idle_state;
+       unsigned long core_thread_mask = (1UL << threads_per_core) - 1;
+       unsigned long srr1;
+       unsigned long pls;
+//     struct p10_sprs sprs = {}; /* avoid false used-uninitialised */
+       bool sprs_saved = false;
+
+       if (!(psscr & (PSSCR_EC|PSSCR_ESL))) {
+               /* EC=ESL=0 case */
+
+               BUG_ON(!mmu_on);
+
+               /*
+                * Wake synchronously. SRESET via xscom may still cause
+                * a 0x100 powersave wakeup with SRR1 reason!
+                */
+               srr1 = isa300_idle_stop_noloss(psscr);          /* go idle */
+               if (likely(!srr1))
+                       return 0;
+
+               /*
+                * Registers not saved, can't recover!
+                * This would be a hardware bug
+                */
+               BUG_ON((srr1 & SRR1_WAKESTATE) != SRR1_WS_NOLOSS);
+
+               goto out;
+       }
+
+       /* EC=ESL=1 case */
+       if ((psscr & PSSCR_RL_MASK) >= deep_spr_loss_state) {
+               /* XXX: save SPRs for deep state loss here. */
+
+               sprs_saved = true;
+
+               atomic_start_thread_idle();
+       }
+
+       srr1 = isa300_idle_stop_mayloss(psscr);         /* go idle */
+
+       psscr = mfspr(SPRN_PSSCR);
+
+       WARN_ON_ONCE(!srr1);
+       WARN_ON_ONCE(mfmsr() & (MSR_IR|MSR_DR));
+
+       if (unlikely((srr1 & SRR1_WAKEMASK_P8) == SRR1_WAKEHMI))
+               hmi_exception_realmode(NULL);
+
+       /*
+        * On POWER10, SRR1 bits do not match exactly as expected.
+        * SRR1_WS_GPRLOSS (10b) can also result in SPR loss, so
+        * just always test PSSCR for SPR/TB state loss.
+        */
+       pls = (psscr & PSSCR_PLS) >> PSSCR_PLS_SHIFT;
+       if (likely(pls < deep_spr_loss_state)) {
+               if (sprs_saved)
+                       atomic_stop_thread_idle();
+               goto out;
+       }
+
+       /* HV state loss */
+       BUG_ON(!sprs_saved);
+
+       atomic_lock_thread_idle();
+
+       if ((*state & core_thread_mask) != 0)
+               goto core_woken;
+
+       /* XXX: restore per-core SPRs here */
+
+       if (pls >= pnv_first_tb_loss_level) {
+               /* TB loss */
+               if (opal_resync_timebase() != OPAL_SUCCESS)
+                       BUG();
+       }
+
+       /*
+        * isync after restoring shared SPRs and before unlocking. Unlock
+        * only contains hwsync which does not necessarily do the right
+        * thing for SPRs.
+        */
+       isync();
+
+core_woken:
+       atomic_unlock_and_stop_thread_idle();
+
+       /* XXX: restore per-thread SPRs here */
+
+       if (!radix_enabled())
+               __slb_restore_bolted_realmode();
+
+out:
+       if (mmu_on)
+               mtmsr(MSR_KERNEL);
+
+       return srr1;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static unsigned long arch300_offline_stop(unsigned long psscr)
+{
+       unsigned long srr1;
+
+#ifndef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       __ppc64_runlatch_off();
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               srr1 = power10_idle_stop(psscr, true);
+       else
+               srr1 = power9_idle_stop(psscr, true);
+       __ppc64_runlatch_on();
+#else
+       /*
+        * Tell KVM we're entering idle.
+        * This does not have to be done in real mode because the P9 MMU
+        * is independent per-thread. Some steppings share radix/hash mode
+        * between threads, but in that case KVM has a barrier sync in real
+        * mode before and after switching between radix and hash.
+        *
+        * kvm_start_guest must still be called in real mode though, hence
+        * the false argument.
+        */
+       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_IDLE;
+
+       __ppc64_runlatch_off();
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               srr1 = power10_idle_stop(psscr, false);
+       else
+               srr1 = power9_idle_stop(psscr, false);
+       __ppc64_runlatch_on();
+
+       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_KERNEL;
+       /* Order setting hwthread_state vs. testing hwthread_req */
+       smp_mb();
+       if (local_paca->kvm_hstate.hwthread_req)
+               srr1 = idle_kvm_start_guest(srr1);
+       mtmsr(MSR_KERNEL);
+#endif
+
+       return srr1;
+}
+#endif
+
+void arch300_idle_type(unsigned long stop_psscr_val,
+                                     unsigned long stop_psscr_mask)
+{
+       unsigned long psscr;
+       unsigned long srr1;
+
+       if (!prep_irq_for_idle_irqsoff())
+               return;
+
+       psscr = mfspr(SPRN_PSSCR);
+       psscr = (psscr & ~stop_psscr_mask) | stop_psscr_val;
+
+       __ppc64_runlatch_off();
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               srr1 = power10_idle_stop(psscr, true);
+       else
+               srr1 = power9_idle_stop(psscr, true);
+       __ppc64_runlatch_on();
+
+       fini_irq_for_idle_irqsoff();
+
+       irq_set_pending_from_srr1(srr1);
+}
+
+/*
+ * Used for ppc_md.power_save which needs a function with no parameters
+ */
+static void arch300_idle(void)
+{
+       arch300_idle_type(pnv_default_stop_val, pnv_default_stop_mask);
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 void pnv_program_cpu_hotplug_lpcr(unsigned int cpu, u64 lpcr_val)
@@ -995,7 +1102,7 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
                psscr = mfspr(SPRN_PSSCR);
                psscr = (psscr & ~pnv_deepest_stop_psscr_mask) |
                                                pnv_deepest_stop_psscr_val;
-               srr1 = power9_offline_stop(psscr);
+               srr1 = arch300_offline_stop(psscr);
        } else if (cpu_has_feature(CPU_FTR_ARCH_206) && power7_offline_type) {
                srr1 = power7_offline();
        } else {
@@ -1093,11 +1200,15 @@ int validate_psscr_val_mask(u64 *psscr_val, u64 *psscr_mask, u32 flags)
  * @dt_idle_states: Number of idle state entries
  * Returns 0 on success
  */
-static void __init pnv_power9_idle_init(void)
+static void __init pnv_arch300_idle_init(void)
 {
        u64 max_residency_ns = 0;
        int i;
 
+       /* stop is not really architected, we only have p9,p10 drivers */
+       if (!pvr_version_is(PVR_POWER10) && !pvr_version_is(PVR_POWER9))
+               return;
+
        /*
         * pnv_deepest_stop_{val,mask} should be set to values corresponding to
         * the deepest stop state.
@@ -1112,6 +1223,11 @@ static void __init pnv_power9_idle_init(void)
                struct pnv_idle_states_t *state = &pnv_idle_states[i];
                u64 psscr_rl = state->psscr_val & PSSCR_RL_MASK;
 
+               /* No deep loss driver implemented for POWER10 yet */
+               if (pvr_version_is(PVR_POWER10) &&
+                               state->flags & (OPAL_PM_TIMEBASE_STOP|OPAL_PM_LOSE_FULL_CONTEXT))
+                       continue;
+
                if ((state->flags & OPAL_PM_TIMEBASE_STOP) &&
                     (pnv_first_tb_loss_level > psscr_rl))
                        pnv_first_tb_loss_level = psscr_rl;
@@ -1162,7 +1278,7 @@ static void __init pnv_power9_idle_init(void)
        if (unlikely(!default_stop_found)) {
                pr_warn("cpuidle-powernv: No suitable default stop state found. Disabling platform idle.\n");
        } else {
-               ppc_md.power_save = power9_idle;
+               ppc_md.power_save = arch300_idle;
                pr_info("cpuidle-powernv: Default stop: psscr = 0x%016llx,mask=0x%016llx\n",
                        pnv_default_stop_val, pnv_default_stop_mask);
        }
@@ -1224,7 +1340,7 @@ static void __init pnv_probe_idle_states(void)
        }
 
        if (cpu_has_feature(CPU_FTR_ARCH_300))
-               pnv_power9_idle_init();
+               pnv_arch300_idle_init();
 
        for (i = 0; i < nr_pnv_idle_states; i++)
                supported_cpuidle_states |= pnv_idle_states[i].flags;
@@ -1295,7 +1411,7 @@ static int pnv_parse_cpuidle_dt(void)
        for (i = 0; i < nr_idle_states; i++)
                pnv_idle_states[i].residency_ns = temp_u32[i];
 
-       /* For power9 */
+       /* For power9 and later */
        if (cpu_has_feature(CPU_FTR_ARCH_300)) {
                /* Read pm_crtl_val */
                if (of_property_read_u64_array(np, "ibm,cpu-idle-state-psscr",
@@ -1358,8 +1474,8 @@ static int __init pnv_init_idle_states(void)
                if (!cpu_has_feature(CPU_FTR_ARCH_300)) {
                        /* P7/P8 nap */
                        p->thread_idle_state = PNV_THREAD_RUNNING;
-               } else {
-                       /* P9 stop */
+               } else if (pvr_version_is(PVR_POWER9)) {
+                       /* P9 stop workarounds */
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
                        p->requested_psscr = 0;
                        atomic_set(&p->dont_stop, 0);
index 8c65aac..ecdad21 100644 (file)
@@ -2,7 +2,6 @@
 // Copyright 2017 IBM Corp.
 #include <asm/pnv-ocxl.h>
 #include <asm/opal.h>
-#include <asm/xive.h>
 #include <misc/ocxl-config.h>
 #include "pci.h"
 
@@ -484,32 +483,3 @@ int pnv_ocxl_spa_remove_pe_from_cache(void *platform_data, int pe_handle)
        return rc;
 }
 EXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe_from_cache);
-
-int pnv_ocxl_alloc_xive_irq(u32 *irq, u64 *trigger_addr)
-{
-       __be64 flags, trigger_page;
-       s64 rc;
-       u32 hwirq;
-
-       hwirq = xive_native_alloc_irq();
-       if (!hwirq)
-               return -ENOENT;
-
-       rc = opal_xive_get_irq_info(hwirq, &flags, NULL, &trigger_page, NULL,
-                               NULL);
-       if (rc || !trigger_page) {
-               xive_native_free_irq(hwirq);
-               return -ENOENT;
-       }
-       *irq = hwirq;
-       *trigger_addr = be64_to_cpu(trigger_page);
-       return 0;
-
-}
-EXPORT_SYMBOL_GPL(pnv_ocxl_alloc_xive_irq);
-
-void pnv_ocxl_free_xive_irq(u32 irq)
-{
-       xive_native_free_irq(irq);
-}
-EXPORT_SYMBOL_GPL(pnv_ocxl_free_xive_irq);
index 6dba3b6..23571f0 100644 (file)
@@ -510,7 +510,7 @@ static void __init opalcore_config_init(void)
        idx = be32_to_cpu(opalc_metadata->region_cnt);
        if (idx > MAX_PT_LOAD_CNT) {
                pr_warn("WARNING: OPAL regions count (%d) adjusted to limit (%d)",
-                       MAX_PT_LOAD_CNT, idx);
+                       idx, MAX_PT_LOAD_CNT);
                idx = MAX_PT_LOAD_CNT;
        }
        for (i = 0; i < idx; i++) {
index 62ef7ad..5e33b1f 100644 (file)
@@ -179,14 +179,14 @@ static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
        return count;
 }
 
-static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
+static void create_elog_obj(uint64_t id, size_t size, uint64_t type)
 {
        struct elog_obj *elog;
        int rc;
 
        elog = kzalloc(sizeof(*elog), GFP_KERNEL);
        if (!elog)
-               return NULL;
+               return;
 
        elog->kobj.kset = elog_kset;
 
@@ -219,18 +219,37 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
        rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
        if (rc) {
                kobject_put(&elog->kobj);
-               return NULL;
+               return;
        }
 
+       /*
+        * As soon as the sysfs file for this elog is created/activated there is
+        * a chance the opal_errd daemon (or any userspace) might read and
+        * acknowledge the elog before kobject_uevent() is called. If that
+        * happens then there is a potential race between
+        * elog_ack_store->kobject_put() and kobject_uevent() which leads to a
+        * use-after-free of a kernfs object resulting in a kernel crash.
+        *
+        * To avoid that, we need to take a reference on behalf of the bin file,
+        * so that our reference remains valid while we call kobject_uevent().
+        * We then drop our reference before exiting the function, leaving the
+        * bin file to drop the last reference (if it hasn't already).
+        */
+
+       /* Take a reference for the bin file */
+       kobject_get(&elog->kobj);
        rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
-       if (rc) {
+       if (rc == 0) {
+               kobject_uevent(&elog->kobj, KOBJ_ADD);
+       } else {
+               /* Drop the reference taken for the bin file */
                kobject_put(&elog->kobj);
-               return NULL;
        }
 
-       kobject_uevent(&elog->kobj, KOBJ_ADD);
+       /* Drop our reference */
+       kobject_put(&elog->kobj);
 
-       return elog;
+       return;
 }
 
 static irqreturn_t elog_event(int irq, void *data)
index d26da19..d3b6e13 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/types.h>
 #include <asm/barrier.h>
 
+#include "powernv.h"
+
 /* OPAL in-memory console. Defined in OPAL source at core/console.c */
 struct memcons {
        __be64 magic;
index 45f4223..deddaeb 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/uaccess.h>
 
 
-/**
+/*
  * The msg member must be at the end of the struct, as it's followed by the
  * message data.
  */
index 023a4f9..2b4ceb5 100644 (file)
@@ -894,7 +894,6 @@ int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 
 int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 {
-       struct pci_dev *parent;
        uint8_t bcomp, dcomp, fcomp;
        long rc, rid_end, rid;
 
@@ -904,7 +903,6 @@ int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 
                dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER;
                fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER;
-               parent = pe->pbus->self;
                if (pe->flags & PNV_IODA_PE_BUS_ALL)
                        count = resource_size(&pe->pbus->busn_res);
                else
@@ -925,12 +923,6 @@ int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
                }
                rid_end = pe->rid + (count << 8);
        } else {
-#ifdef CONFIG_PCI_IOV
-               if (pe->flags & PNV_IODA_PE_VF)
-                       parent = pe->parent_dev;
-               else
-#endif /* CONFIG_PCI_IOV */
-                       parent = pe->pdev->bus->self;
                bcomp = OpalPciBusAll;
                dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
                fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
index 1aa51c4..11df4e1 100644 (file)
@@ -2,6 +2,13 @@
 #ifndef _POWERNV_H
 #define _POWERNV_H
 
+/*
+ * There's various hacks scattered throughout the generic powerpc arch code
+ * that needs to call into powernv platform stuff. The prototypes for those
+ * functions are in asm/powernv.h
+ */
+#include <asm/powernv.h>
+
 #ifdef CONFIG_SMP
 extern void pnv_smp_init(void);
 #else
index 8035caf..72c2529 100644 (file)
@@ -65,7 +65,7 @@ int powernv_get_random_real_mode(unsigned long *v)
        return 1;
 }
 
-int powernv_get_random_darn(unsigned long *v)
+static int powernv_get_random_darn(unsigned long *v)
 {
        unsigned long val;
 
index 7fcb886..9acaa0f 100644 (file)
@@ -130,6 +130,28 @@ static void pnv_setup_rfi_flush(void)
        setup_count_cache_flush();
 }
 
+static void __init pnv_check_guarded_cores(void)
+{
+       struct device_node *dn;
+       int bad_count = 0;
+
+       for_each_node_by_type(dn, "cpu") {
+               if (of_property_match_string(dn, "status", "bad") >= 0)
+                       bad_count++;
+       };
+
+       if (bad_count) {
+               printk("  _     _______________\n");
+               pr_cont(" | |   /               \\\n");
+               pr_cont(" | |   |    WARNING!   |\n");
+               pr_cont(" | |   |               |\n");
+               pr_cont(" | |   | It looks like |\n");
+               pr_cont(" |_|   |  you have %*d |\n", 3, bad_count);
+               pr_cont("  _    | guarded cores |\n");
+               pr_cont(" (_)   \\_______________/\n");
+       }
+}
+
 static void __init pnv_setup_arch(void)
 {
        set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
@@ -150,6 +172,8 @@ static void __init pnv_setup_arch(void)
        /* Enable NAP mode */
        powersave_nap = 1;
 
+       pnv_check_guarded_cores();
+
        /* XXX PMCS */
 }
 
index b2ba3e9..54c4ba4 100644 (file)
@@ -43,7 +43,7 @@
 #include <asm/udbg.h>
 #define DBG(fmt...) udbg_printf(fmt)
 #else
-#define DBG(fmt...)
+#define DBG(fmt...) do { } while (0)
 #endif
 
 static void pnv_smp_setup_cpu(int cpu)
@@ -158,7 +158,7 @@ static void pnv_flush_interrupts(void)
        }
 }
 
-static void pnv_smp_cpu_kill_self(void)
+static void pnv_cpu_offline_self(void)
 {
        unsigned long srr1, unexpected_mask, wmask;
        unsigned int cpu;
@@ -417,6 +417,7 @@ static struct smp_ops_t pnv_smp_ops = {
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_disable    = pnv_smp_cpu_disable,
        .cpu_die        = generic_cpu_die,
+       .cpu_offline_self = pnv_cpu_offline_self,
 #endif /* CONFIG_HOTPLUG_CPU */
 };
 
@@ -430,7 +431,6 @@ void __init pnv_smp_init(void)
        smp_ops = &pnv_smp_ops;
 
 #ifdef CONFIG_HOTPLUG_CPU
-       ppc_md.cpu_die  = pnv_smp_cpu_kill_self;
 #ifdef CONFIG_KEXEC_CORE
        crash_wake_offline = 1;
 #endif
index 6434f9c..5f5fe63 100644 (file)
@@ -186,7 +186,7 @@ static void unmap_winctx_mmio_bars(struct vas_window *window)
  * OS/User Window Context (UWC) MMIO Base Address Region for the given window.
  * Map these bus addresses and save the mapped kernel addresses in @window.
  */
-int map_winctx_mmio_bars(struct vas_window *window)
+static int map_winctx_mmio_bars(struct vas_window *window)
 {
        int len;
        u64 start;
@@ -214,7 +214,7 @@ int map_winctx_mmio_bars(struct vas_window *window)
  *      registers are not sequential. And, we can only write to offsets
  *      with valid registers.
  */
-void reset_window_regs(struct vas_window *window)
+static void reset_window_regs(struct vas_window *window)
 {
        write_hvwc_reg(window, VREG(LPID), 0ULL);
        write_hvwc_reg(window, VREG(PID), 0ULL);
@@ -357,7 +357,8 @@ static void init_rsvd_tx_buf_count(struct vas_window *txwin,
  *     as a one-time task? That could work for NX but what about other
  *     receivers?  Let the receivers tell us the rx-fifo buffers for now.
  */
-int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
+static void init_winctx_regs(struct vas_window *window,
+                            struct vas_winctx *winctx)
 {
        u64 val;
        int fifo_size;
@@ -499,8 +500,6 @@ int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
        val = SET_FIELD(VAS_WINCTL_NX_WIN, val, winctx->nx_win);
        val = SET_FIELD(VAS_WINCTL_OPEN, val, 1);
        write_hvwc_reg(window, VREG(WINCTL), val);
-
-       return 0;
 }
 
 static void vas_release_window_id(struct ida *ida, int winid)
index 1193c29..0c25247 100644 (file)
@@ -448,7 +448,7 @@ static void ps3_disable_spu(struct spu_context *ctx)
        ctx->ops->runcntl_stop(ctx);
 }
 
-const struct spu_management_ops spu_management_ps3_ops = {
+static const struct spu_management_ops spu_management_ps3_ops = {
        .enumerate_spus = ps3_enumerate_spus,
        .create_spu = ps3_create_spu,
        .destroy_spu = ps3_destroy_spu,
@@ -589,7 +589,7 @@ static u64 resource_allocation_enable_get(struct spu *spu)
        return 0; /* No support. */
 }
 
-const struct spu_priv1_ops spu_priv1_ps3_ops = {
+static const struct spu_priv1_ops spu_priv1_ps3_ops = {
        .int_mask_and = int_mask_and,
        .int_mask_or = int_mask_or,
        .int_mask_set = int_mask_set,
index cb2d9a9..cf024fa 100644 (file)
@@ -33,8 +33,6 @@
 #include <asm/ppc-pci.h>
 #include <asm/rtas.h>
 
-static int pseries_eeh_get_pe_addr(struct pci_dn *pdn);
-
 /* RTAS tokens */
 static int ibm_set_eeh_option;
 static int ibm_set_slot_reset;
@@ -86,42 +84,43 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
 
 
 /**
- * pseries_eeh_get_config_addr - Retrieve config address
+ * pseries_eeh_get_pe_config_addr - Find the pe_config_addr for a device
+ * @pdn: pci_dn of the input device
+ *
+ * The EEH RTAS calls use a tuple consisting of: (buid_hi, buid_lo,
+ * pe_config_addr) as a handle to a given PE. This function finds the
+ * pe_config_addr based on the device's config addr.
  *
- * Retrieve the assocated config 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.
+ * Keep in mind that the pe_config_addr *might* be numerically identical to the
+ * device's config addr, but the two are conceptually distinct.
  *
- * It's notable that zero'ed return value means invalid PE config
- * address.
+ * Returns the pe_config_addr, or a negative error code.
  */
-static int pseries_eeh_get_config_addr(struct pci_controller *phb, int config_addr)
+static int pseries_eeh_get_pe_config_addr(struct pci_dn *pdn)
 {
-       int ret = 0;
-       int rets[3];
+       int config_addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+       struct pci_controller *phb = pdn->phb;
+       int ret, rets[3];
 
        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.
+                * First of all, use function 1 to determine if this device is
+                * part of a PE or not. ret[0] being zero indicates it's not.
                 */
                ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
                                config_addr, BUID_HI(phb->buid),
                                BUID_LO(phb->buid), 1);
                if (ret || (rets[0] == 0))
-                       return 0;
+                       return -ENOENT;
 
-               /* Retrieve the associated PE config address */
+               /* Retrieve the associated PE config address with function 0 */
                ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
                                config_addr, BUID_HI(phb->buid),
                                BUID_LO(phb->buid), 0);
                if (ret) {
                        pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
                                __func__, phb->global_number, config_addr);
-                       return 0;
+                       return -ENXIO;
                }
 
                return rets[0];
@@ -134,13 +133,20 @@ static int pseries_eeh_get_config_addr(struct pci_controller *phb, int config_ad
                if (ret) {
                        pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
                                __func__, phb->global_number, config_addr);
-                       return 0;
+                       return -ENXIO;
                }
 
                return rets[0];
        }
 
-       return ret;
+       /*
+        * PAPR does describe a process for finding the pe_config_addr that was
+        * used before the ibm,get-config-addr-info calls were added. However,
+        * I haven't found *any* systems that don't have that RTAS call
+        * implemented. If you happen to find one that needs the old DT based
+        * process, patches are welcome!
+        */
+       return -ENOENT;
 }
 
 /**
@@ -161,8 +167,7 @@ static int pseries_eeh_phb_reset(struct pci_controller *phb, int config_addr, in
                        BUID_LO(phb->buid), option);
 
        /* If fundamental-reset not supported, try hot-reset */
-       if (option == EEH_RESET_FUNDAMENTAL &&
-           ret == -8) {
+       if (option == EEH_RESET_FUNDAMENTAL && ret == -8) {
                option = EEH_RESET_HOT;
                ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
                                config_addr, BUID_HI(phb->buid),
@@ -170,8 +175,7 @@ static int pseries_eeh_phb_reset(struct pci_controller *phb, int config_addr, in
        }
 
        /* We need reset hold or settlement delay */
-       if (option == EEH_RESET_FUNDAMENTAL ||
-           option == EEH_RESET_HOT)
+       if (option == EEH_RESET_FUNDAMENTAL || option == EEH_RESET_HOT)
                msleep(EEH_PE_RST_HOLD_TIME);
        else
                msleep(EEH_PE_RST_SETTLE_TIME);
@@ -239,88 +243,6 @@ 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)
-{
-       struct pci_controller *phb;
-       struct pci_dn *pdn;
-       int addr, config_addr;
-
-       /* 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-pe and ibm,configure-bridge have the same semantics,
-        * however ibm,configure-pe can be faster.  If we can't find
-        * ibm,configure-pe then fall back to using ibm,configure-bridge.
-        */
-       if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE)
-               ibm_configure_pe        = rtas_token("ibm,configure-bridge");
-
-       /*
-        * Necessary sanity check. We needn't check "get-config-addr-info"
-        * and its variant since the old firmware probably support address
-        * of domain/bus/slot/function for EEH RTAS operations.
-        */
-       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE          ||
-           ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE          ||
-           (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
-            ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) ||
-           ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE       ||
-           ibm_configure_pe == RTAS_UNKNOWN_SERVICE) {
-               pr_info("EEH functionality not supported\n");
-               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_info("%s: unknown EEH error log size\n",
-                       __func__);
-               eeh_error_buf_size = 1024;
-       } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
-               pr_info("%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;
-       }
-
-       /* Set EEH probe mode */
-       eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG);
-
-       /* Set EEH machine dependent code */
-       ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device;
-
-       if (is_kdump_kernel() || reset_devices) {
-               pr_info("Issue PHB reset ...\n");
-               list_for_each_entry(phb, &hose_list, list_node) {
-                       pdn = list_first_entry(&PCI_DN(phb->dn)->child_list, struct pci_dn, list);
-                       addr = (pdn->busno << 16) | (pdn->devfn << 8);
-                       config_addr = pseries_eeh_get_config_addr(phb, addr);
-                       /* invalid PE config addr */
-                       if (config_addr == 0)
-                               continue;
-
-                       pseries_eeh_phb_reset(phb, config_addr, EEH_RESET_FUNDAMENTAL);
-                       pseries_eeh_phb_reset(phb, config_addr, EEH_RESET_DEACTIVATE);
-                       pseries_eeh_phb_configure_bridge(phb, config_addr);
-               }
-       }
-
-       return 0;
-}
-
 static int pseries_eeh_cap_start(struct pci_dn *pdn)
 {
        u32 status;
@@ -439,10 +361,9 @@ static struct eeh_pe *pseries_eeh_pe_get_parent(struct eeh_dev *edev)
  */
 void pseries_eeh_init_edev(struct pci_dn *pdn)
 {
+       struct eeh_pe pe, *parent;
        struct eeh_dev *edev;
-       struct eeh_pe pe;
        u32 pcie_flags;
-       int enable = 0;
        int ret;
 
        if (WARN_ON_ONCE(!eeh_has_flag(EEH_PROBE_MODE_DEVTREE)))
@@ -499,51 +420,38 @@ void pseries_eeh_init_edev(struct pci_dn *pdn)
                }
        }
 
-       /* Initialize the fake PE */
+       /* first up, find the pe_config_addr for the PE containing the device */
+       ret = pseries_eeh_get_pe_config_addr(pdn);
+       if (ret < 0) {
+               eeh_edev_dbg(edev, "Unable to find pe_config_addr\n");
+               goto err;
+       }
+
+       /* Try enable EEH on the fake PE */
        memset(&pe, 0, sizeof(struct eeh_pe));
        pe.phb = pdn->phb;
-       pe.config_addr = (pdn->busno << 16) | (pdn->devfn << 8);
+       pe.addr = ret;
 
-       /* Enable EEH on the device */
        eeh_edev_dbg(edev, "Enabling EEH on device\n");
        ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE);
        if (ret) {
                eeh_edev_dbg(edev, "EEH failed to enable on device (code %d)\n", ret);
-       } else {
-               struct eeh_pe *parent;
+               goto err;
+       }
 
-               /* Retrieve PE address */
-               edev->pe_config_addr = pseries_eeh_get_pe_addr(pdn);
-               pe.addr = edev->pe_config_addr;
+       edev->pe_config_addr = pe.addr;
 
-               /* 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 = eeh_ops->get_state(&pe, NULL);
-               if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
-                       enable = 1;
+       eeh_add_flag(EEH_ENABLED);
 
-               /*
-                * This device doesn't support EEH, but it may have an
-                * EEH parent. In this case any error on the device will
-                * freeze the PE of it's upstream bridge, so added it to
-                * the upstream PE.
-                */
-               parent = pseries_eeh_pe_get_parent(edev);
-               if (parent && !enable)
-                       edev->pe_config_addr = parent->addr;
+       parent = pseries_eeh_pe_get_parent(edev);
+       eeh_pe_tree_insert(edev, parent);
+       eeh_save_bars(edev);
+       eeh_edev_dbg(edev, "EEH enabled for device");
 
-               if (enable || parent) {
-                       eeh_add_flag(EEH_ENABLED);
-                       eeh_pe_tree_insert(edev, parent);
-               }
-               eeh_edev_dbg(edev, "EEH is %s on device (code %d)\n",
-                            (enable ? "enabled" : "unsupported"), ret);
-       }
+       return;
 
-       /* Save memory bars */
-       eeh_save_bars(edev);
+err:
+       eeh_edev_dbg(edev, "EEH is unsupported on device (code = %d)\n", ret);
 }
 
 static struct eeh_dev *pseries_eeh_probe(struct pci_dev *pdev)
@@ -600,7 +508,6 @@ EXPORT_SYMBOL_GPL(pseries_eeh_init_edev_recursive);
 static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
 {
        int ret = 0;
-       int config_addr;
 
        /*
         * When we're enabling or disabling EEH functioality on
@@ -613,84 +520,22 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
        case EEH_OPT_ENABLE:
        case EEH_OPT_THAW_MMIO:
        case EEH_OPT_THAW_DMA:
-               config_addr = pe->config_addr;
-               if (pe->addr)
-                       config_addr = pe->addr;
                break;
        case EEH_OPT_FREEZE_PE:
                /* Not support */
                return 0;
        default:
-               pr_err("%s: Invalid option %d\n",
-                       __func__, option);
+               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(pe->phb->buid),
+                       pe->addr, BUID_HI(pe->phb->buid),
                        BUID_LO(pe->phb->buid), option);
 
        return ret;
 }
 
-/**
- * pseries_eeh_get_pe_addr - Retrieve PE address
- * @pe: EEH PE
- *
- * 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 pci_dn *pdn)
-{
-       int config_addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
-       unsigned long buid = pdn->phb->buid;
-       int ret = 0;
-       int rets[3];
-
-       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,
-                               config_addr, BUID_HI(buid), BUID_LO(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,
-                               config_addr, BUID_HI(buid), BUID_LO(buid), 0);
-               if (ret) {
-                       pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
-                               __func__, pdn->phb->global_number, config_addr);
-                       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,
-                               config_addr, BUID_HI(buid), BUID_LO(buid), 0);
-               if (ret) {
-                       pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
-                               __func__, pdn->phb->global_number, config_addr);
-                       return 0;
-               }
-
-               return rets[0];
-       }
-
-       return ret;
-}
-
 /**
  * pseries_eeh_get_state - Retrieve PE state
  * @pe: EEH PE
@@ -706,25 +551,19 @@ static int pseries_eeh_get_pe_addr(struct pci_dn *pdn)
  */
 static int pseries_eeh_get_state(struct eeh_pe *pe, int *delay)
 {
-       int config_addr;
        int ret;
        int rets[4];
        int result;
 
-       /* Figure out PE config address if possible */
-       config_addr = pe->config_addr;
-       if (pe->addr)
-               config_addr = pe->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(pe->phb->buid),
+                               pe->addr, BUID_HI(pe->phb->buid),
                                BUID_LO(pe->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(pe->phb->buid),
+                               pe->addr, BUID_HI(pe->phb->buid),
                                BUID_LO(pe->phb->buid));
        } else {
                return EEH_STATE_NOT_SUPPORT;
@@ -778,14 +617,7 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *delay)
  */
 static int pseries_eeh_reset(struct eeh_pe *pe, int option)
 {
-       int config_addr;
-
-       /* Figure out PE address */
-       config_addr = pe->config_addr;
-       if (pe->addr)
-               config_addr = pe->addr;
-
-       return pseries_eeh_phb_reset(pe->phb, config_addr, option);
+       return pseries_eeh_phb_reset(pe->phb, pe->addr, option);
 }
 
 /**
@@ -801,19 +633,13 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
  */
 static int pseries_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len)
 {
-       int config_addr;
        unsigned long flags;
        int ret;
 
        spin_lock_irqsave(&slot_errbuf_lock, flags);
        memset(slot_errbuf, 0, eeh_error_buf_size);
 
-       /* Figure out the PE address */
-       config_addr = pe->config_addr;
-       if (pe->addr)
-               config_addr = pe->addr;
-
-       ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
+       ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, pe->addr,
                        BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid),
                        virt_to_phys(drv_log), len,
                        virt_to_phys(slot_errbuf), eeh_error_buf_size,
@@ -832,14 +658,7 @@ static int pseries_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, u
  */
 static int pseries_eeh_configure_bridge(struct eeh_pe *pe)
 {
-       int config_addr;
-
-       /* Figure out the PE address */
-       config_addr = pe->config_addr;
-       if (pe->addr)
-               config_addr = pe->addr;
-
-       return pseries_eeh_phb_configure_bridge(pe->phb, config_addr);
+       return pseries_eeh_phb_configure_bridge(pe->phb, pe->addr);
 }
 
 /**
@@ -954,8 +773,7 @@ static int pseries_notify_resume(struct eeh_dev *edev)
        if (!edev)
                return -EEXIST;
 
-       if (rtas_token("ibm,open-sriov-allow-unfreeze")
-           == RTAS_UNKNOWN_SERVICE)
+       if (rtas_token("ibm,open-sriov-allow-unfreeze") == RTAS_UNKNOWN_SERVICE)
                return -EINVAL;
 
        if (edev->pdev->is_physfn || edev->pdev->is_virtfn)
@@ -967,7 +785,6 @@ static int pseries_notify_resume(struct eeh_dev *edev)
 
 static struct eeh_ops pseries_eeh_ops = {
        .name                   = "pseries",
-       .init                   = pseries_eeh_init,
        .probe                  = pseries_eeh_probe,
        .set_option             = pseries_eeh_set_option,
        .get_state              = pseries_eeh_get_state,
@@ -992,15 +809,84 @@ static struct eeh_ops pseries_eeh_ops = {
  */
 static int __init eeh_pseries_init(void)
 {
-       int ret;
+       struct pci_controller *phb;
+       struct pci_dn *pdn;
+       int ret, config_addr;
 
-       ret = eeh_ops_register(&pseries_eeh_ops);
+       /* 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-pe and ibm,configure-bridge have the same semantics,
+        * however ibm,configure-pe can be faster.  If we can't find
+        * ibm,configure-pe then fall back to using ibm,configure-bridge.
+        */
+       if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE)
+               ibm_configure_pe        = rtas_token("ibm,configure-bridge");
+
+       /*
+        * Necessary sanity check. We needn't check "get-config-addr-info"
+        * and its variant since the old firmware probably support address
+        * of domain/bus/slot/function for EEH RTAS operations.
+        */
+       if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE          ||
+           ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE          ||
+           (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
+            ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) ||
+           ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE       ||
+           ibm_configure_pe == RTAS_UNKNOWN_SERVICE) {
+               pr_info("EEH functionality not supported\n");
+               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_info("%s: unknown EEH error log size\n",
+                       __func__);
+               eeh_error_buf_size = 1024;
+       } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
+               pr_info("%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;
+       }
+
+       /* Set EEH probe mode */
+       eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG);
+
+       /* Set EEH machine dependent code */
+       ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device;
+
+       if (is_kdump_kernel() || reset_devices) {
+               pr_info("Issue PHB reset ...\n");
+               list_for_each_entry(phb, &hose_list, list_node) {
+                       pdn = list_first_entry(&PCI_DN(phb->dn)->child_list, struct pci_dn, list);
+                       config_addr = pseries_eeh_get_pe_config_addr(pdn);
+
+                       /* invalid PE config addr */
+                       if (config_addr < 0)
+                               continue;
+
+                       pseries_eeh_phb_reset(phb, config_addr, EEH_RESET_FUNDAMENTAL);
+                       pseries_eeh_phb_reset(phb, config_addr, EEH_RESET_DEACTIVATE);
+                       pseries_eeh_phb_configure_bridge(phb, config_addr);
+               }
+       }
+
+       ret = eeh_init(&pseries_eeh_ops);
        if (!ret)
                pr_info("EEH: pSeries platform initialized\n");
        else
                pr_info("EEH: pSeries platform initialization failure (%d)\n",
                        ret);
-
        return ret;
 }
-machine_early_initcall(pseries, eeh_pseries_init);
+machine_arch_initcall(pseries, eeh_pseries_init);
index 7a974ed..f2837e3 100644 (file)
@@ -55,7 +55,7 @@ static void rtas_stop_self(void)
        panic("Alas, I survived.\n");
 }
 
-static void pseries_mach_cpu_die(void)
+static void pseries_cpu_offline_self(void)
 {
        unsigned int hwcpu = hard_smp_processor_id();
 
@@ -102,7 +102,7 @@ static int pseries_cpu_disable(void)
  * to self-destroy so that the cpu-offline thread can send the CPU_DEAD
  * notifications.
  *
- * OTOH, pseries_mach_cpu_die() is called by the @cpu when it wants to
+ * OTOH, pseries_cpu_offline_self() is called by the @cpu when it wants to
  * self-destruct.
  */
 static void pseries_cpu_die(unsigned int cpu)
@@ -901,7 +901,7 @@ static int __init pseries_cpu_hotplug_init(void)
                return 0;
        }
 
-       ppc_md.cpu_die = pseries_mach_cpu_die;
+       smp_ops->cpu_offline_self = pseries_cpu_offline_self;
        smp_ops->cpu_disable = pseries_cpu_disable;
        smp_ops->cpu_die = pseries_cpu_die;
 
index d8bbf0c..7efe6ec 100644 (file)
@@ -30,12 +30,17 @@ unsigned long pseries_memory_block_size(void)
 
        np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
        if (np) {
-               const __be64 *size;
+               int len;
+               int size_cells;
+               const __be32 *prop;
 
-               size = of_get_property(np, "ibm,lmb-size", NULL);
-               if (size)
-                       memblock_size = be64_to_cpup(size);
+               size_cells = of_n_size_cells(np);
+
+               prop = of_get_property(np, "ibm,lmb-size", &len);
+               if (prop && len >= size_cells * sizeof(__be32))
+                       memblock_size = of_read_number(prop, size_cells);
                of_node_put(np);
+
        } else  if (machine_is(pseries)) {
                /* This fallback really only applies to pseries */
                unsigned int memzero_size = 0;
@@ -277,7 +282,7 @@ static int dlpar_offline_lmb(struct drmem_lmb *lmb)
        return dlpar_change_lmb_state(lmb, false);
 }
 
-static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
+static int pseries_remove_memblock(unsigned long base, unsigned long memblock_size)
 {
        unsigned long block_sz, start_pfn;
        int sections_per_block;
@@ -308,10 +313,11 @@ out:
 
 static int pseries_remove_mem_node(struct device_node *np)
 {
-       const __be32 *regs;
+       const __be32 *prop;
        unsigned long base;
-       unsigned int lmb_size;
+       unsigned long lmb_size;
        int ret = -EINVAL;
+       int addr_cells, size_cells;
 
        /*
         * Check to see if we are actually removing memory
@@ -322,12 +328,19 @@ static int pseries_remove_mem_node(struct device_node *np)
        /*
         * Find the base address and size of the memblock
         */
-       regs = of_get_property(np, "reg", NULL);
-       if (!regs)
+       prop = of_get_property(np, "reg", NULL);
+       if (!prop)
                return ret;
 
-       base = be64_to_cpu(*(unsigned long *)regs);
-       lmb_size = be32_to_cpu(regs[3]);
+       addr_cells = of_n_addr_cells(np);
+       size_cells = of_n_size_cells(np);
+
+       /*
+        * "reg" property represents (addr,size) tuple.
+        */
+       base = of_read_number(prop, addr_cells);
+       prop += addr_cells;
+       lmb_size = of_read_number(prop, size_cells);
 
        pseries_remove_memblock(base, lmb_size);
        return 0;
@@ -354,25 +367,32 @@ static int dlpar_add_lmb(struct drmem_lmb *);
 
 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
 {
+       struct memory_block *mem_block;
        unsigned long block_sz;
        int rc;
 
        if (!lmb_is_removable(lmb))
                return -EINVAL;
 
+       mem_block = lmb_to_memblock(lmb);
+       if (mem_block == NULL)
+               return -EINVAL;
+
        rc = dlpar_offline_lmb(lmb);
-       if (rc)
+       if (rc) {
+               put_device(&mem_block->dev);
                return rc;
+       }
 
        block_sz = pseries_memory_block_size();
 
-       __remove_memory(lmb->nid, lmb->base_addr, block_sz);
+       __remove_memory(mem_block->nid, lmb->base_addr, block_sz);
+       put_device(&mem_block->dev);
 
        /* Update memory regions for memory remove */
        memblock_remove(lmb->base_addr, block_sz);
 
        invalidate_lmb_associativity_index(lmb);
-       lmb_clear_nid(lmb);
        lmb->flags &= ~DRCONF_MEM_ASSIGNED;
 
        return 0;
@@ -557,7 +577,7 @@ static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
 
 #else
 static inline int pseries_remove_memblock(unsigned long base,
-                                         unsigned int memblock_size)
+                                         unsigned long memblock_size)
 {
        return -EOPNOTSUPP;
 }
@@ -591,7 +611,7 @@ static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
 static int dlpar_add_lmb(struct drmem_lmb *lmb)
 {
        unsigned long block_sz;
-       int rc;
+       int nid, rc;
 
        if (lmb->flags & DRCONF_MEM_ASSIGNED)
                return -EINVAL;
@@ -602,11 +622,15 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb)
                return rc;
        }
 
-       lmb_set_nid(lmb);
        block_sz = memory_block_size_bytes();
 
+       /* Find the node id for this LMB.  Fake one if necessary. */
+       nid = of_drconf_to_nid_single(lmb);
+       if (nid < 0 || !node_possible(nid))
+               nid = first_online_node;
+
        /* Add the memory */
-       rc = __add_memory(lmb->nid, lmb->base_addr, block_sz, MHP_NONE);
+       rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_NONE);
        if (rc) {
                invalidate_lmb_associativity_index(lmb);
                return rc;
@@ -614,9 +638,8 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb)
 
        rc = dlpar_online_lmb(lmb);
        if (rc) {
-               __remove_memory(lmb->nid, lmb->base_addr, block_sz);
+               __remove_memory(nid, lmb->base_addr, block_sz);
                invalidate_lmb_associativity_index(lmb);
-               lmb_clear_nid(lmb);
        } else {
                lmb->flags |= DRCONF_MEM_ASSIGNED;
        }
@@ -878,10 +901,11 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
 
 static int pseries_add_mem_node(struct device_node *np)
 {
-       const __be32 *regs;
+       const __be32 *prop;
        unsigned long base;
-       unsigned int lmb_size;
+       unsigned long lmb_size;
        int ret = -EINVAL;
+       int addr_cells, size_cells;
 
        /*
         * Check to see if we are actually adding memory
@@ -892,12 +916,18 @@ static int pseries_add_mem_node(struct device_node *np)
        /*
         * Find the base and size of the memblock
         */
-       regs = of_get_property(np, "reg", NULL);
-       if (!regs)
+       prop = of_get_property(np, "reg", NULL);
+       if (!prop)
                return ret;
 
-       base = be64_to_cpu(*(unsigned long *)regs);
-       lmb_size = be32_to_cpu(regs[3]);
+       addr_cells = of_n_addr_cells(np);
+       size_cells = of_n_size_cells(np);
+       /*
+        * "reg" property represents (addr,size) tuple.
+        */
+       base = of_read_number(prop, addr_cells);
+       prop += addr_cells;
+       lmb_size = of_read_number(prop, size_cells);
 
        /*
         * Update memory region to represent the memory add
index c40c62e..2c59b49 100644 (file)
@@ -70,31 +70,14 @@ static int hc_show(struct seq_file *m, void *p)
        return 0;
 }
 
-static const struct seq_operations hcall_inst_seq_ops = {
+static const struct seq_operations hcall_inst_sops = {
         .start = hc_start,
         .next  = hc_next,
         .stop  = hc_stop,
         .show  = hc_show
 };
 
-static int hcall_inst_seq_open(struct inode *inode, struct file *file)
-{
-       int rc;
-       struct seq_file *seq;
-
-       rc = seq_open(file, &hcall_inst_seq_ops);
-       seq = file->private_data;
-       seq->private = file_inode(file)->i_private;
-
-       return rc;
-}
-
-static const struct file_operations hcall_inst_seq_fops = {
-       .open = hcall_inst_seq_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = seq_release,
-};
+DEFINE_SEQ_ATTRIBUTE(hcall_inst);
 
 #define        HCALL_ROOT_DIR          "hcall_inst"
 #define CPU_NAME_BUF_SIZE      32
@@ -149,7 +132,7 @@ static int __init hcall_inst_init(void)
                snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
                debugfs_create_file(cpu_name_buf, 0444, hcall_root,
                                    per_cpu(hcall_stats, cpu),
-                                   &hcall_inst_seq_fops);
+                                   &hcall_inst_fops);
        }
 
        return 0;
index 6d47b4a..e419870 100644 (file)
 
 #include "pseries.h"
 
+enum {
+       DDW_QUERY_PE_DMA_WIN  = 0,
+       DDW_CREATE_PE_DMA_WIN = 1,
+       DDW_REMOVE_PE_DMA_WIN = 2,
+
+       DDW_APPLICABLE_SIZE
+};
+
+enum {
+       DDW_EXT_SIZE = 0,
+       DDW_EXT_RESET_DMA_WIN = 1,
+       DDW_EXT_QUERY_OUT_SIZE = 2
+};
+
 static struct iommu_table_group *iommu_pseries_alloc_group(int node)
 {
        struct iommu_table_group *table_group;
@@ -334,7 +348,7 @@ struct direct_window {
 /* Dynamic DMA Window support */
 struct ddw_query_response {
        u32 windows_available;
-       u32 largest_available_block;
+       u64 largest_available_block;
        u32 page_size;
        u32 migration_capable;
 };
@@ -767,25 +781,14 @@ static int __init disable_ddw_setup(char *str)
 
 early_param("disable_ddw", disable_ddw_setup);
 
-static void remove_ddw(struct device_node *np, bool remove_prop)
+static void remove_dma_window(struct device_node *np, u32 *ddw_avail,
+                             struct property *win)
 {
        struct dynamic_dma_window_prop *dwp;
-       struct property *win64;
-       u32 ddw_avail[3];
        u64 liobn;
-       int ret = 0;
-
-       ret = of_property_read_u32_array(np, "ibm,ddw-applicable",
-                                        &ddw_avail[0], 3);
-
-       win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
-       if (!win64)
-               return;
-
-       if (ret || win64->length < sizeof(*dwp))
-               goto delprop;
+       int ret;
 
-       dwp = win64->value;
+       dwp = win->value;
        liobn = (u64)be32_to_cpu(dwp->liobn);
 
        /* clear the whole window, note the arg is in kernel pages */
@@ -798,19 +801,39 @@ static void remove_ddw(struct device_node *np, bool remove_prop)
                pr_debug("%pOF successfully cleared tces in window.\n",
                         np);
 
-       ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
+       ret = rtas_call(ddw_avail[DDW_REMOVE_PE_DMA_WIN], 1, 1, NULL, liobn);
        if (ret)
                pr_warn("%pOF: failed to remove direct window: rtas returned "
                        "%d to ibm,remove-pe-dma-window(%x) %llx\n",
-                       np, ret, ddw_avail[2], liobn);
+                       np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn);
        else
                pr_debug("%pOF: successfully removed direct window: rtas returned "
                        "%d to ibm,remove-pe-dma-window(%x) %llx\n",
-                       np, ret, ddw_avail[2], liobn);
+                       np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn);
+}
+
+static void remove_ddw(struct device_node *np, bool remove_prop)
+{
+       struct property *win;
+       u32 ddw_avail[DDW_APPLICABLE_SIZE];
+       int ret = 0;
 
-delprop:
-       if (remove_prop)
-               ret = of_remove_property(np, win64);
+       ret = of_property_read_u32_array(np, "ibm,ddw-applicable",
+                                        &ddw_avail[0], DDW_APPLICABLE_SIZE);
+       if (ret)
+               return;
+
+       win = of_find_property(np, DIRECT64_PROPNAME, NULL);
+       if (!win)
+               return;
+
+       if (win->length >= sizeof(struct dynamic_dma_window_prop))
+               remove_dma_window(np, ddw_avail, win);
+
+       if (!remove_prop)
+               return;
+
+       ret = of_remove_property(np, win);
        if (ret)
                pr_warn("%pOF: failed to remove direct window property: %d\n",
                        np, ret);
@@ -869,14 +892,62 @@ static int find_existing_ddw_windows(void)
 }
 machine_arch_initcall(pseries, find_existing_ddw_windows);
 
+/**
+ * ddw_read_ext - Get the value of an DDW extension
+ * @np:                device node from which the extension value is to be read.
+ * @extnum:    index number of the extension.
+ * @value:     pointer to return value, modified when extension is available.
+ *
+ * Checks if "ibm,ddw-extensions" exists for this node, and get the value
+ * on index 'extnum'.
+ * It can be used only to check if a property exists, passing value == NULL.
+ *
+ * Returns:
+ *     0 if extension successfully read
+ *     -EINVAL if the "ibm,ddw-extensions" does not exist,
+ *     -ENODATA if "ibm,ddw-extensions" does not have a value, and
+ *     -EOVERFLOW if "ibm,ddw-extensions" does not contain this extension.
+ */
+static inline int ddw_read_ext(const struct device_node *np, int extnum,
+                              u32 *value)
+{
+       static const char propname[] = "ibm,ddw-extensions";
+       u32 count;
+       int ret;
+
+       ret = of_property_read_u32_index(np, propname, DDW_EXT_SIZE, &count);
+       if (ret)
+               return ret;
+
+       if (count < extnum)
+               return -EOVERFLOW;
+
+       if (!value)
+               value = &count;
+
+       return of_property_read_u32_index(np, propname, extnum, value);
+}
+
 static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
-                       struct ddw_query_response *query)
+                    struct ddw_query_response *query,
+                    struct device_node *parent)
 {
        struct device_node *dn;
        struct pci_dn *pdn;
-       u32 cfg_addr;
+       u32 cfg_addr, ext_query, query_out[5];
        u64 buid;
-       int ret;
+       int ret, out_sz;
+
+       /*
+        * From LoPAR level 2.8, "ibm,ddw-extensions" index 3 can rule how many
+        * output parameters ibm,query-pe-dma-windows will have, ranging from
+        * 5 to 6.
+        */
+       ret = ddw_read_ext(parent, DDW_EXT_QUERY_OUT_SIZE, &ext_query);
+       if (!ret && ext_query == 1)
+               out_sz = 6;
+       else
+               out_sz = 5;
 
        /*
         * Get the config address and phb buid of the PE window.
@@ -889,11 +960,28 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
        buid = pdn->phb->buid;
        cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8));
 
-       ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
-                 cfg_addr, BUID_HI(buid), BUID_LO(buid));
-       dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
-               " returned %d\n", ddw_avail[0], cfg_addr, BUID_HI(buid),
-               BUID_LO(buid), ret);
+       ret = rtas_call(ddw_avail[DDW_QUERY_PE_DMA_WIN], 3, out_sz, query_out,
+                       cfg_addr, BUID_HI(buid), BUID_LO(buid));
+       dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x returned %d\n",
+                ddw_avail[DDW_QUERY_PE_DMA_WIN], cfg_addr, BUID_HI(buid),
+                BUID_LO(buid), ret);
+
+       switch (out_sz) {
+       case 5:
+               query->windows_available = query_out[0];
+               query->largest_available_block = query_out[1];
+               query->page_size = query_out[2];
+               query->migration_capable = query_out[3];
+               break;
+       case 6:
+               query->windows_available = query_out[0];
+               query->largest_available_block = ((u64)query_out[1] << 32) |
+                                                query_out[2];
+               query->page_size = query_out[3];
+               query->migration_capable = query_out[4];
+               break;
+       }
+
        return ret;
 }
 
@@ -920,15 +1008,16 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
 
        do {
                /* extra outputs are LIOBN and dma-addr (hi, lo) */
-               ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create,
-                               cfg_addr, BUID_HI(buid), BUID_LO(buid),
-                               page_shift, window_shift);
+               ret = rtas_call(ddw_avail[DDW_CREATE_PE_DMA_WIN], 5, 4,
+                               (u32 *)create, cfg_addr, BUID_HI(buid),
+                               BUID_LO(buid), page_shift, window_shift);
        } while (rtas_busy_delay(ret));
        dev_info(&dev->dev,
                "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
-               "(liobn = 0x%x starting addr = %x %x)\n", ddw_avail[1],
-                cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift,
-                window_shift, ret, create->liobn, create->addr_hi, create->addr_lo);
+               "(liobn = 0x%x starting addr = %x %x)\n",
+                ddw_avail[DDW_CREATE_PE_DMA_WIN], cfg_addr, BUID_HI(buid),
+                BUID_LO(buid), page_shift, window_shift, ret, create->liobn,
+                create->addr_hi, create->addr_lo);
 
        return ret;
 }
@@ -977,6 +1066,38 @@ static phys_addr_t ddw_memory_hotplug_max(void)
        return max_addr;
 }
 
+/*
+ * Platforms supporting the DDW option starting with LoPAR level 2.7 implement
+ * ibm,ddw-extensions, which carries the rtas token for
+ * ibm,reset-pe-dma-windows.
+ * That rtas-call can be used to restore the default DMA window for the device.
+ */
+static void reset_dma_window(struct pci_dev *dev, struct device_node *par_dn)
+{
+       int ret;
+       u32 cfg_addr, reset_dma_win;
+       u64 buid;
+       struct device_node *dn;
+       struct pci_dn *pdn;
+
+       ret = ddw_read_ext(par_dn, DDW_EXT_RESET_DMA_WIN, &reset_dma_win);
+       if (ret)
+               return;
+
+       dn = pci_device_to_OF_node(dev);
+       pdn = PCI_DN(dn);
+       buid = pdn->phb->buid;
+       cfg_addr = (pdn->busno << 16) | (pdn->devfn << 8);
+
+       ret = rtas_call(reset_dma_win, 3, 1, NULL, cfg_addr, BUID_HI(buid),
+                       BUID_LO(buid));
+       if (ret)
+               dev_info(&dev->dev,
+                        "ibm,reset-pe-dma-windows(%x) %x %x %x returned %d ",
+                        reset_dma_win, cfg_addr, BUID_HI(buid), BUID_LO(buid),
+                        ret);
+}
+
 /*
  * If the PE supports dynamic dma windows, and there is space for a table
  * that can map all pages in a linear offset, then setup such a table,
@@ -996,11 +1117,12 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        int page_shift;
        u64 dma_addr, max_addr;
        struct device_node *dn;
-       u32 ddw_avail[3];
+       u32 ddw_avail[DDW_APPLICABLE_SIZE];
        struct direct_window *window;
        struct property *win64;
        struct dynamic_dma_window_prop *ddwprop;
        struct failed_ddw_pdn *fpdn;
+       bool default_win_removed = false;
 
        mutex_lock(&direct_window_init_mutex);
 
@@ -1029,7 +1151,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
         * the property is actually in the parent, not the PE
         */
        ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable",
-                                        &ddw_avail[0], 3);
+                                        &ddw_avail[0], DDW_APPLICABLE_SIZE);
        if (ret)
                goto out_failed;
 
@@ -1040,18 +1162,42 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
         * of page sizes: supported and supported for migrate-dma.
         */
        dn = pci_device_to_OF_node(dev);
-       ret = query_ddw(dev, ddw_avail, &query);
+       ret = query_ddw(dev, ddw_avail, &query, pdn);
        if (ret != 0)
                goto out_failed;
 
+       /*
+        * If there is no window available, remove the default DMA window,
+        * if it's present. This will make all the resources available to the
+        * new DDW window.
+        * If anything fails after this, we need to restore it, so also check
+        * for extensions presence.
+        */
        if (query.windows_available == 0) {
-               /*
-                * no additional windows are available for this device.
-                * We might be able to reallocate the existing window,
-                * trading in for a larger page size.
-                */
-               dev_dbg(&dev->dev, "no free dynamic windows");
-               goto out_failed;
+               struct property *default_win;
+               int reset_win_ext;
+
+               default_win = of_find_property(pdn, "ibm,dma-window", NULL);
+               if (!default_win)
+                       goto out_failed;
+
+               reset_win_ext = ddw_read_ext(pdn, DDW_EXT_RESET_DMA_WIN, NULL);
+               if (reset_win_ext)
+                       goto out_failed;
+
+               remove_dma_window(pdn, ddw_avail, default_win);
+               default_win_removed = true;
+
+               /* Query again, to check if the window is available */
+               ret = query_ddw(dev, ddw_avail, &query, pdn);
+               if (ret != 0)
+                       goto out_failed;
+
+               if (query.windows_available == 0) {
+                       /* no windows are available for this device. */
+                       dev_dbg(&dev->dev, "no free dynamic windows");
+                       goto out_failed;
+               }
        }
        if (query.page_size & 4) {
                page_shift = 24; /* 16MB */
@@ -1068,7 +1214,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        /* check largest block * page size > max memory hotplug addr */
        max_addr = ddw_memory_hotplug_max();
        if (query.largest_available_block < (max_addr >> page_shift)) {
-               dev_dbg(&dev->dev, "can't map partition max 0x%llx with %u "
+               dev_dbg(&dev->dev, "can't map partition max 0x%llx with %llu "
                          "%llu-sized pages\n", max_addr,  query.largest_available_block,
                          1ULL << page_shift);
                goto out_failed;
@@ -1142,6 +1288,8 @@ out_free_prop:
        kfree(win64);
 
 out_failed:
+       if (default_win_removed)
+               reset_dma_window(dev, pdn);
 
        fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL);
        if (!fpdn)
index baf24ea..764170f 100644 (file)
@@ -1724,6 +1724,7 @@ void __init hpte_init_pseries(void)
                pseries_lpar_register_process_table(0, 0, 0);
 }
 
+#ifdef CONFIG_PPC_RADIX_MMU
 void radix_init_pseries(void)
 {
        pr_info("Using radix MMU under hypervisor\n");
@@ -1731,6 +1732,7 @@ void radix_init_pseries(void)
        pseries_lpar_register_process_table(__pa(process_tb),
                                                0, PRTB_SIZE_SHIFT - 12);
 }
+#endif
 
 #ifdef CONFIG_PPC_SMLPAR
 #define CMO_FREE_HINT_DEFAULT 1
index b8d28ab..e278390 100644 (file)
@@ -136,6 +136,39 @@ static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data)
        return rc;
 }
 
+static void show_gpci_data(struct seq_file *m)
+{
+       struct hv_gpci_request_buffer *buf;
+       unsigned int affinity_score;
+       long ret;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (buf == NULL)
+               return;
+
+       /*
+        * Show the local LPAR's affinity score.
+        *
+        * 0xB1 selects the Affinity_Domain_Info_By_Partition subcall.
+        * The score is at byte 0xB in the output buffer.
+        */
+       memset(&buf->params, 0, sizeof(buf->params));
+       buf->params.counter_request = cpu_to_be32(0xB1);
+       buf->params.starting_index = cpu_to_be32(-1);   /* local LPAR */
+       buf->params.counter_info_version_in = 0x5;      /* v5+ for score */
+       ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, virt_to_phys(buf),
+                                sizeof(*buf));
+       if (ret != H_SUCCESS) {
+               pr_debug("hcall failed: H_GET_PERF_COUNTER_INFO: %ld, %x\n",
+                        ret, be32_to_cpu(buf->params.detail_rc));
+               goto out;
+       }
+       affinity_score = buf->bytes[0xB];
+       seq_printf(m, "partition_affinity_score=%u\n", affinity_score);
+out:
+       kfree(buf);
+}
+
 static unsigned h_pic(unsigned long *pool_idle_time,
                      unsigned long *num_procs)
 {
@@ -487,6 +520,8 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
                           partition_active_processors * 100);
        }
 
+       show_gpci_data(m);
+
        seq_printf(m, "partition_active_processors=%d\n",
                   partition_active_processors);
 
index a88a707..835163f 100644 (file)
@@ -785,7 +785,8 @@ static int papr_scm_ndctl(struct nvdimm_bus_descriptor *nd_desc,
 static ssize_t perf_stats_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
-       int index, rc;
+       int index;
+       ssize_t rc;
        struct seq_buf s;
        struct papr_scm_perf_stat *stat;
        struct papr_scm_perf_stats *stats;
@@ -820,9 +821,9 @@ static ssize_t perf_stats_show(struct device *dev,
 
 free_stats:
        kfree(stats);
-       return rc ? rc : seq_buf_used(&s);
+       return rc ? rc : (ssize_t)seq_buf_used(&s);
 }
-DEVICE_ATTR_ADMIN_RO(perf_stats);
+static DEVICE_ATTR_ADMIN_RO(perf_stats);
 
 static ssize_t flags_show(struct device *dev,
                          struct device_attribute *attr, char *buf)
@@ -897,6 +898,9 @@ static int papr_scm_nvdimm_init(struct papr_scm_priv *p)
        p->bus_desc.of_node = p->pdev->dev.of_node;
        p->bus_desc.provider_name = kstrdup(p->pdev->name, GFP_KERNEL);
 
+       /* Set the dimm command family mask to accept PDSMs */
+       set_bit(NVDIMM_FAMILY_PAPR, &p->bus_desc.dimm_family_mask);
+
        if (!p->bus_desc.provider_name)
                return -ENOMEM;
 
index bbb9716..6268545 100644 (file)
@@ -36,6 +36,7 @@ static __init int rng_init(void)
 
        ppc_md.get_random_seed = pseries_get_random_long;
 
+       of_node_put(dn);
        return 0;
 }
 machine_subsys_initcall(pseries, rng_init);
index 2f4ee0a..633c45e 100644 (file)
@@ -519,9 +519,15 @@ static void init_cpu_char_feature_flags(struct h_cpu_char_result *result)
        if (result->character & H_CPU_CHAR_BCCTR_FLUSH_ASSIST)
                security_ftr_set(SEC_FTR_BCCTR_FLUSH_ASSIST);
 
+       if (result->character & H_CPU_CHAR_BCCTR_LINK_FLUSH_ASSIST)
+               security_ftr_set(SEC_FTR_BCCTR_LINK_FLUSH_ASSIST);
+
        if (result->behaviour & H_CPU_BEHAV_FLUSH_COUNT_CACHE)
                security_ftr_set(SEC_FTR_FLUSH_COUNT_CACHE);
 
+       if (result->behaviour & H_CPU_BEHAV_FLUSH_LINK_STACK)
+               security_ftr_set(SEC_FTR_FLUSH_LINK_STACK);
+
        /*
         * The features below are enabled by default, so we instead look to see
         * if firmware has *disabled* them, and clear them if so.
index e6d7a34..7b739cc 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/memblock.h>
 #include <asm/machdep.h>
 #include <asm/svm.h>
 #include <asm/swiotlb.h>
@@ -35,6 +36,31 @@ static int __init init_svm(void)
 }
 machine_early_initcall(pseries, init_svm);
 
+/*
+ * Initialize SWIOTLB. Essentially the same as swiotlb_init(), except that it
+ * can allocate the buffer anywhere in memory. Since the hypervisor doesn't have
+ * any addressing limitation, we don't need to allocate it in low addresses.
+ */
+void __init svm_swiotlb_init(void)
+{
+       unsigned char *vstart;
+       unsigned long bytes, io_tlb_nslabs;
+
+       io_tlb_nslabs = (swiotlb_size_or_default() >> IO_TLB_SHIFT);
+       io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       vstart = memblock_alloc(PAGE_ALIGN(bytes), PAGE_SIZE);
+       if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, false))
+               return;
+
+       if (io_tlb_start)
+               memblock_free_early(io_tlb_start,
+                                   PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
+       panic("SVM: Cannot allocate SWIOTLB buffer");
+}
+
 int set_memory_encrypted(unsigned long addr, int numpages)
 {
        if (!PAGE_ALIGNED(addr))
index ad81171..21b9d1b 100644 (file)
@@ -174,6 +174,7 @@ int icp_hv_init(void)
 
        icp_ops = &icp_hv_ops;
 
+       of_node_put(np);
        return 0;
 }
 
index f591be9..a80440a 100644 (file)
@@ -1565,7 +1565,7 @@ static int __init xive_off(char *arg)
 }
 __setup("xive=off", xive_off);
 
-void xive_debug_show_cpu(struct seq_file *m, int cpu)
+static void xive_debug_show_cpu(struct seq_file *m, int cpu)
 {
        struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
 
@@ -1599,7 +1599,7 @@ void xive_debug_show_cpu(struct seq_file *m, int cpu)
        seq_puts(m, "\n");
 }
 
-void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data *d)
+static void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data *d)
 {
        struct irq_chip *chip = irq_data_get_irq_chip(d);
        int rc;
index 3ce5c09..91c0480 100755 (executable)
@@ -9,7 +9,6 @@ script_base=$(realpath $(dirname $0))
 exec $script_base/../../../scripts/checkpatch.pl \
        --subjective \
        --no-summary \
-       --max-line-length=90 \
        --show-types \
        --ignore ARCH_INCLUDE_LINUX \
        --ignore BIT_MACRO \
index 6e6a30a..8301efe 100755 (executable)
@@ -1,60 +1,79 @@
-# Copyright © 2016 IBM Corporation
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright © 2016,2020 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 script checks the relocations of a vmlinux for "suspicious"
-# branches from unrelocated code (head_64.S code).
-
-# Turn this on if you want more debug output:
-# set -x
+# This script checks the unrelocated code of a vmlinux for "suspicious"
+# branches to relocated code (head_64.S code).
 
-# Have Kbuild supply the path to objdump so we handle cross compilation.
+# Have Kbuild supply the path to objdump and nm so we handle cross compilation.
 objdump="$1"
-vmlinux="$2"
-
-#__end_interrupts should be located within the first 64K
-
-end_intr=0x$(
-$objdump -R "$vmlinux" -d --start-address=0xc000000000000000           \
-                --stop-address=0xc000000000010000 |
-grep '\<__end_interrupts>:' |
-awk '{print $1}'
-)
-
-BRANCHES=$(
-$objdump -R "$vmlinux" -D --start-address=0xc000000000000000           \
-               --stop-address=${end_intr} |
-grep -e "^c[0-9a-f]*:[[:space:]]*\([0-9a-f][0-9a-f][[:space:]]\)\{4\}[[:space:]]*b" |
-grep -v '\<__start_initialization_multiplatform>' |
-grep -v -e 'b.\?.\?ctr' |
-grep -v -e 'b.\?.\?lr' |
-sed -e 's/\bbt.\?[[:space:]]*[[:digit:]][[:digit:]]*,/beq/' \
-       -e 's/\bbf.\?[[:space:]]*[[:digit:]][[:digit:]]*,/bne/' \
-       -e 's/[[:space:]]0x/ /' \
-       -e 's/://' |
-awk '{ print $1 ":" $6 ":0x" $7 ":" $8 " "}'
-)
-
-for tuple in $BRANCHES
-do
-       from=`echo $tuple | cut -d':' -f1`
-       branch=`echo $tuple | cut -d':' -f2`
-       to=`echo $tuple | cut -d':' -f3 | sed 's/cr[0-7],//'`
-       sym=`echo $tuple | cut -d':' -f4`
-
-       if (( $to > $end_intr ))
-       then
-               if [ -z "$bad_branches" ]; then
-                       echo "WARNING: Unrelocated relative branches"
-                       bad_branches="yes"
+nm="$2"
+vmlinux="$3"
+
+kstart=0xc000000000000000
+
+end_intr=0x$($nm -p "$vmlinux" |
+       sed -E -n '/\s+[[:alpha:]]\s+__end_interrupts\s*$/{s///p;q}')
+if [ "$end_intr" = "0x" ]; then
+       exit 0
+fi
+
+# we know that there is a correct branch to
+# __start_initialization_multiplatform, so find its address
+# so we can exclude it.
+sim=0x$($nm -p "$vmlinux" |
+       sed -E -n '/\s+[[:alpha:]]\s+__start_initialization_multiplatform\s*$/{s///p;q}')
+
+$objdump -D --no-show-raw-insn --start-address="$kstart" --stop-address="$end_intr" "$vmlinux" |
+sed -E -n '
+# match lines that start with a kernel address
+/^c[0-9a-f]*:\s*b/ {
+       # drop branches via ctr or lr
+       /\<b.?.?(ct|l)r/d
+       # cope with some differences between Clang and GNU objdumps
+       s/\<bt.?\s*[[:digit:]]+,/beq/
+       s/\<bf.?\s*[[:digit:]]+,/bne/
+       # tidy up
+       s/\s0x/ /
+       s/://
+       # format for the loop below
+       s/^(\S+)\s+(\S+)\s+(\S+)\s*(\S*).*$/\1:\2:\3:\4/
+       # strip out condition registers
+       s/:cr[0-7],/:/
+       p
+}' | {
+
+all_good=true
+while IFS=: read -r from branch to sym; do
+       case "$to" in
+       c*)     to="0x$to"
+               ;;
+       .+*)
+               to=${to#.+}
+               if [ "$branch" = 'b' ]; then
+                       if (( to >= 0x2000000 )); then
+                               to=$(( to - 0x4000000 ))
+                       fi
+               elif (( to >= 0x8000 )); then
+                       to=$(( to - 0x10000 ))
+               fi
+               printf -v to '0x%x' $(( "0x$from" + to ))
+               ;;
+       *)      printf 'Unkown branch format\n'
+               ;;
+       esac
+       if [ "$to" = "$sim" ]; then
+               continue
+       fi
+       if (( to > end_intr )); then
+               if $all_good; then
+                       printf '%s\n' 'WARNING: Unrelocated relative branches'
+                       all_good=false
                fi
-               echo "$from $branch-> $to $sym"
+               printf '%s %s-> %s %s\n' "$from" "$branch" "$to" "$sym"
        fi
 done
 
-if [ -z "$bad_branches" ]; then
-       exit 0
-fi
+$all_good
+
+}
index df7bca0..55c43a6 100644 (file)
@@ -969,6 +969,7 @@ static void insert_cpu_bpts(void)
                        brk.address = dabr[i].address;
                        brk.type = (dabr[i].enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
                        brk.len = 8;
+                       brk.hw_len = 8;
                        __set_breakpoint(i, &brk);
                }
        }
index e286e2b..e38d8bf 100644 (file)
@@ -1039,38 +1039,9 @@ void smp_fetch_global_pmu(void)
  * are flush_tlb_*() routines, and these run after flush_cache_*()
  * which performs the flushw.
  *
- * The SMP TLB coherency scheme we use works as follows:
- *
- * 1) mm->cpu_vm_mask is a bit mask of which cpus an address
- *    space has (potentially) executed on, this is the heuristic
- *    we use to avoid doing cross calls.
- *
- *    Also, for flushing from kswapd and also for clones, we
- *    use cpu_vm_mask as the list of cpus to make run the TLB.
- *
- * 2) TLB context numbers are shared globally across all processors
- *    in the system, this allows us to play several games to avoid
- *    cross calls.
- *
- *    One invariant is that when a cpu switches to a process, and
- *    that processes tsk->active_mm->cpu_vm_mask does not have the
- *    current cpu's bit set, that tlb context is flushed locally.
- *
- *    If the address space is non-shared (ie. mm->count == 1) we avoid
- *    cross calls when we want to flush the currently running process's
- *    tlb state.  This is done by clearing all cpu bits except the current
- *    processor's in current->mm->cpu_vm_mask and performing the
- *    flush locally only.  This will force any subsequent cpus which run
- *    this task to flush the context from the local tlb if the process
- *    migrates to another cpu (again).
- *
- * 3) For shared address spaces (threads) and swapping we bite the
- *    bullet for most cases and perform the cross call (but only to
- *    the cpus listed in cpu_vm_mask).
- *
- *    The performance gain from "optimizing" away the cross call for threads is
- *    questionable (in theory the big win for threads is the massive sharing of
- *    address space state across processors).
+ * mm->cpu_vm_mask is a bit mask of which cpus an address
+ * space has (potentially) executed on, this is the heuristic
+ * we use to limit cross calls.
  */
 
 /* This currently is only used by the hugetlb arch pre-fault
@@ -1080,18 +1051,13 @@ void smp_fetch_global_pmu(void)
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        u32 ctx = CTX_HWBITS(mm->context);
-       int cpu = get_cpu();
 
-       if (atomic_read(&mm->mm_users) == 1) {
-               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-               goto local_flush_and_out;
-       }
+       get_cpu();
 
        smp_cross_call_masked(&xcall_flush_tlb_mm,
                              ctx, 0, 0,
                              mm_cpumask(mm));
 
-local_flush_and_out:
        __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
 
        put_cpu();
@@ -1114,17 +1080,15 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
 {
        u32 ctx = CTX_HWBITS(mm->context);
        struct tlb_pending_info info;
-       int cpu = get_cpu();
+
+       get_cpu();
 
        info.ctx = ctx;
        info.nr = nr;
        info.vaddrs = vaddrs;
 
-       if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-       else
-               smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
-                                      &info, 1);
+       smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
+                              &info, 1);
 
        __flush_tlb_pending(ctx, nr, vaddrs);
 
@@ -1134,14 +1098,13 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long
 void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
 {
        unsigned long context = CTX_HWBITS(mm->context);
-       int cpu = get_cpu();
 
-       if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
-       else
-               smp_cross_call_masked(&xcall_flush_tlb_page,
-                                     context, vaddr, 0,
-                                     mm_cpumask(mm));
+       get_cpu();
+
+       smp_cross_call_masked(&xcall_flush_tlb_page,
+                             context, vaddr, 0,
+                             mm_cpumask(mm));
+
        __flush_tlb_page(context, vaddr);
 
        put_cpu();
index a9af15e..e439b43 100644 (file)
@@ -885,12 +885,15 @@ static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
                                unsigned long action, void *unused)
 {
        int cpu;
-       struct cpufreq_policy cpu_policy;
+       struct cpufreq_policy *cpu_policy;
 
        rebooting = true;
        for_each_online_cpu(cpu) {
-               cpufreq_get_policy(&cpu_policy, cpu);
-               powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
+               cpu_policy = cpufreq_cpu_get(cpu);
+               if (!cpu_policy)
+                       continue;
+               powernv_cpufreq_target_index(cpu_policy, get_nominal_index());
+               cpufreq_cpu_put(cpu_policy);
        }
 
        return NOTIFY_DONE;
index addaa6e..c32c600 100644 (file)
@@ -141,7 +141,7 @@ static int stop_loop(struct cpuidle_device *dev,
                     struct cpuidle_driver *drv,
                     int index)
 {
-       power9_idle_type(stop_psscr_table[index].val,
+       arch300_idle_type(stop_psscr_table[index].val,
                         stop_psscr_table[index].mask);
        return index;
 }
index 9668458..94fb63a 100644 (file)
@@ -638,7 +638,7 @@ static void smu_expose_childs(struct work_struct *unused)
 {
        struct device_node *np;
 
-       for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
+       for_each_child_of_node(smu->of_node, np)
                if (of_device_is_compatible(np, "smu-sensors"))
                        of_platform_device_create(np, "smu-sensors",
                                                  &smu->of_dev->dev);
@@ -1015,7 +1015,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
 /* Note: Only allowed to return error code in pointers (using ERR_PTR)
  * when interruptible is 1
  */
-const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
+static const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
                unsigned int *size, int interruptible)
 {
        char pname[32];
index 1e5fa09..29f48c2 100644 (file)
@@ -152,8 +152,6 @@ static int wf_lm75_remove(struct i2c_client *client)
 {
        struct wf_lm75_sensor *lm = i2c_get_clientdata(client);
 
-       DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name);
-
        /* Mark client detached */
        lm->i2c = NULL;
 
index d011899..9fab0b4 100644 (file)
@@ -149,8 +149,6 @@ static int wf_lm87_remove(struct i2c_client *client)
 {
        struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
 
-       DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
-
        /* Mark client detached */
        lm->i2c = NULL;
 
index cb75dc0..e46e115 100644 (file)
@@ -216,8 +216,7 @@ static int wf_sat_probe(struct i2c_client *client,
 
        vsens[0] = vsens[1] = -1;
        isens[0] = isens[1] = -1;
-       child = NULL;
-       while ((child = of_get_next_child(dev, child)) != NULL) {
+       for_each_child_of_node(dev, child) {
                reg = of_get_property(child, "reg", NULL);
                loc = of_get_property(child, "location", NULL);
                if (reg == NULL || loc == NULL)
index 3e6059e..c8706cf 100644 (file)
@@ -421,8 +421,7 @@ static int __init smu_sensors_init(void)
                return -ENODEV;
 
        /* Look for sensors subdir */
-       for (sensors = NULL;
-            (sensors = of_get_next_child(smu, sensors)) != NULL;)
+       for_each_child_of_node(smu, sensors)
                if (of_node_name_eq(sensors, "sensors"))
                        break;
 
index 25a9dd9..2ba899f 100644 (file)
@@ -393,8 +393,8 @@ int cxl_calc_capp_routing(struct pci_dev *dev, u64 *chipid,
        *capp_unit_id = get_capp_unit_id(np, *phb_index);
        of_node_put(np);
        if (!*capp_unit_id) {
-               pr_err("cxl: invalid capp unit id (phb_index: %d)\n",
-                      *phb_index);
+               pr_err("cxl: No capp unit found for PHB[%lld,%d]. Make sure the adapter is on a capi-compatible slot\n",
+                      *chipid, *phb_index);
                return -ENODEV;
        }
 
index 947294f..c9b0a27 100644 (file)
@@ -9,7 +9,7 @@ config OCXL_BASE
 
 config OCXL
        tristate "OpenCAPI coherent accelerator support"
-       depends on PPC_POWERNV && PCI && EEH && HOTPLUG_PCI_POWERNV
+       depends on HOTPLUG_PCI_POWERNV
        select OCXL_BASE
        default m
        help
index 70f8f1c..ecdcfae 100644 (file)
@@ -2,6 +2,7 @@
 // Copyright 2017 IBM Corp.
 #include <linux/interrupt.h>
 #include <asm/pnv-ocxl.h>
+#include <asm/xive.h>
 #include "ocxl_internal.h"
 #include "trace.h"
 
@@ -10,7 +11,6 @@ struct afu_irq {
        int hw_irq;
        unsigned int virq;
        char *name;
-       u64 trigger_page;
        irqreturn_t (*handler)(void *private);
        void (*free_private)(void *private);
        void *private;
@@ -124,8 +124,7 @@ int ocxl_afu_irq_alloc(struct ocxl_context *ctx, int *irq_id)
                goto err_unlock;
        }
 
-       rc = ocxl_link_irq_alloc(ctx->afu->fn->link, &irq->hw_irq,
-                               &irq->trigger_page);
+       rc = ocxl_link_irq_alloc(ctx->afu->fn->link, &irq->hw_irq);
        if (rc)
                goto err_idr;
 
@@ -196,13 +195,16 @@ void ocxl_afu_irq_free_all(struct ocxl_context *ctx)
 
 u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, int irq_id)
 {
+       struct xive_irq_data *xd;
        struct afu_irq *irq;
        u64 addr = 0;
 
        mutex_lock(&ctx->irq_lock);
        irq = idr_find(&ctx->irq_idr, irq_id);
-       if (irq)
-               addr = irq->trigger_page;
+       if (irq) {
+               xd = irq_get_handler_data(irq->virq);
+               addr = xd ? xd->trig_page : 0;
+       }
        mutex_unlock(&ctx->irq_lock);
        return addr;
 }
index 58d111a..fd73d3b 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mmu_context.h>
 #include <asm/copro.h>
 #include <asm/pnv-ocxl.h>
+#include <asm/xive.h>
 #include <misc/ocxl.h>
 #include "ocxl_internal.h"
 #include "trace.h"
@@ -682,23 +683,21 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(ocxl_link_remove_pe);
 
-int ocxl_link_irq_alloc(void *link_handle, int *hw_irq, u64 *trigger_addr)
+int ocxl_link_irq_alloc(void *link_handle, int *hw_irq)
 {
        struct ocxl_link *link = (struct ocxl_link *) link_handle;
-       int rc, irq;
-       u64 addr;
+       int irq;
 
        if (atomic_dec_if_positive(&link->irq_available) < 0)
                return -ENOSPC;
 
-       rc = pnv_ocxl_alloc_xive_irq(&irq, &addr);
-       if (rc) {
+       irq = xive_native_alloc_irq();
+       if (!irq) {
                atomic_inc(&link->irq_available);
-               return rc;
+               return -ENXIO;
        }
 
        *hw_irq = irq;
-       *trigger_addr = addr;
        return 0;
 }
 EXPORT_SYMBOL_GPL(ocxl_link_irq_alloc);
@@ -707,7 +706,7 @@ void ocxl_link_free_irq(void *link_handle, int hw_irq)
 {
        struct ocxl_link *link = (struct ocxl_link *) link_handle;
 
-       pnv_ocxl_free_xive_irq(hw_irq);
+       xive_native_free_irq(hw_irq);
        atomic_inc(&link->irq_available);
 }
 EXPORT_SYMBOL_GPL(ocxl_link_free_irq);
index 7018cd8..e4e0d76 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/pseudo_fs.h>
 #include <linux/poll.h>
 #include <linux/sched/signal.h>
-
+#include <linux/interrupt.h>
+#include <asm/xive.h>
 #include <misc/ocxl.h>
 
 #include <uapi/misc/cxl.h>
@@ -180,7 +181,7 @@ static int afu_map_irq(u64 flags, struct ocxlflash_context *ctx, int num,
        struct ocxl_hw_afu *afu = ctx->hw_afu;
        struct device *dev = afu->dev;
        struct ocxlflash_irqs *irq;
-       void __iomem *vtrig;
+       struct xive_irq_data *xd;
        u32 virq;
        int rc = 0;
 
@@ -204,15 +205,15 @@ static int afu_map_irq(u64 flags, struct ocxlflash_context *ctx, int num,
                goto err1;
        }
 
-       vtrig = ioremap(irq->ptrig, PAGE_SIZE);
-       if (unlikely(!vtrig)) {
-               dev_err(dev, "%s: Trigger page mapping failed\n", __func__);
-               rc = -ENOMEM;
+       xd = irq_get_handler_data(virq);
+       if (unlikely(!xd)) {
+               dev_err(dev, "%s: Can't get interrupt data\n", __func__);
+               rc = -ENXIO;
                goto err2;
        }
 
        irq->virq = virq;
-       irq->vtrig = vtrig;
+       irq->vtrig = xd->trig_mmio;
 out:
        return rc;
 err2:
@@ -259,8 +260,6 @@ static void afu_unmap_irq(u64 flags, struct ocxlflash_context *ctx, int num,
        }
 
        irq = &ctx->irqs[num];
-       if (irq->vtrig)
-               iounmap(irq->vtrig);
 
        if (irq_find_mapping(NULL, irq->hwirq)) {
                free_irq(irq->virq, cookie);
@@ -615,7 +614,6 @@ static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num)
        struct ocxl_hw_afu *afu = ctx->hw_afu;
        struct device *dev = afu->dev;
        struct ocxlflash_irqs *irqs;
-       u64 addr;
        int rc = 0;
        int hwirq;
        int i;
@@ -640,7 +638,7 @@ static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num)
        }
 
        for (i = 0; i < num; i++) {
-               rc = ocxl_link_irq_alloc(afu->link_token, &hwirq, &addr);
+               rc = ocxl_link_irq_alloc(afu->link_token, &hwirq);
                if (unlikely(rc)) {
                        dev_err(dev, "%s: ocxl_link_irq_alloc failed rc=%d\n",
                                __func__, rc);
@@ -648,7 +646,6 @@ static int alloc_afu_irqs(struct ocxlflash_context *ctx, int num)
                }
 
                irqs[i].hwirq = hwirq;
-               irqs[i].ptrig = addr;
        }
 
        ctx->irqs = irqs;
index fc6ad4f..f2fe888 100644 (file)
@@ -13,7 +13,6 @@
 struct ocxlflash_irqs {
        int hwirq;
        u32 virq;
-       u64 ptrig;
        void __iomem *vtrig;
 };
 
index 3f83e94..547a239 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1001,11 +1001,24 @@ static int exec_mmap(struct mm_struct *mm)
        }
 
        task_lock(tsk);
-       active_mm = tsk->active_mm;
        membarrier_exec_mmap(mm);
-       tsk->mm = mm;
+
+       local_irq_disable();
+       active_mm = tsk->active_mm;
        tsk->active_mm = mm;
+       tsk->mm = mm;
+       /*
+        * This prevents preemption while active_mm is being loaded and
+        * it and mm are being updated, which could cause problems for
+        * lazy tlb mm refcounting when these are updated by context
+        * switches. Not all architectures can handle irqs off over
+        * activate_mm yet.
+        */
+       if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
+               local_irq_enable();
        activate_mm(active_mm, mm);
+       if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
+               local_irq_enable();
        tsk->mm->vmacache_seqnum = 0;
        vmacache_flush(tsk);
        task_unlock(tsk);
index 6f524bb..bc56287 100644 (file)
@@ -183,6 +183,7 @@ enum cpuhp_state {
        CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
        CPUHP_AP_PERF_POWERPC_TRACE_IMC_ONLINE,
        CPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE,
+       CPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE,
        CPUHP_AP_WATCHDOG_ONLINE,
        CPUHP_AP_WORKQUEUE_ONLINE,
        CPUHP_AP_RCUTREE_ONLINE,
index 608fa4a..ad03df1 100644 (file)
@@ -198,7 +198,7 @@ static inline int cpu_to_mem(int cpu)
 #define topology_die_cpumask(cpu)              cpumask_of(cpu)
 #endif
 
-#ifdef CONFIG_SCHED_SMT
+#if defined(CONFIG_SCHED_SMT) && !defined(cpu_smt_mask)
 static inline const struct cpumask *cpu_smt_mask(int cpu)
 {
        return topology_sibling_cpumask(cpu);
index 357ef1a..e013736 100644 (file)
@@ -460,14 +460,8 @@ int ocxl_link_remove_pe(void *link_handle, int pasid);
  * Allocate an AFU interrupt associated to the link.
  *
  * 'hw_irq' is the hardware interrupt number
- * 'obj_handle' is the 64-bit object handle to be passed to the AFU to
- * trigger the interrupt.
- * On P9, 'obj_handle' is an address, which, if written, triggers the
- * interrupt. It is an MMIO address which needs to be remapped (one
- * page).
- */
-int ocxl_link_irq_alloc(void *link_handle, int *hw_irq,
-                       u64 *obj_handle);
+ */
+int ocxl_link_irq_alloc(void *link_handle, int *hw_irq);
 
 /*
  * Free a previously allocated AFU interrupt
index b0f8e87..4f3d5aa 100644 (file)
@@ -20,6 +20,7 @@
 #define HUGETLB_FLAG_ENCODE_SHIFT      26
 #define HUGETLB_FLAG_ENCODE_MASK       0x3f
 
+#define HUGETLB_FLAG_ENCODE_16KB       (14 << HUGETLB_FLAG_ENCODE_SHIFT)
 #define HUGETLB_FLAG_ENCODE_64KB       (16 << HUGETLB_FLAG_ENCODE_SHIFT)
 #define HUGETLB_FLAG_ENCODE_512KB      (19 << HUGETLB_FLAG_ENCODE_SHIFT)
 #define HUGETLB_FLAG_ENCODE_1MB                (20 << HUGETLB_FLAG_ENCODE_SHIFT)
index 923cc16..f55bc68 100644 (file)
@@ -27,6 +27,7 @@
 #define MAP_HUGE_SHIFT HUGETLB_FLAG_ENCODE_SHIFT
 #define MAP_HUGE_MASK  HUGETLB_FLAG_ENCODE_MASK
 
+#define MAP_HUGE_16KB  HUGETLB_FLAG_ENCODE_16KB
 #define MAP_HUGE_64KB  HUGETLB_FLAG_ENCODE_64KB
 #define MAP_HUGE_512KB HUGETLB_FLAG_ENCODE_512KB
 #define MAP_HUGE_1MB   HUGETLB_FLAG_ENCODE_1MB
index 55ef151..2a0503b 100644 (file)
@@ -55,8 +55,6 @@
 #include <setjmp.h>
 #include <signal.h>
 
-#include <asm/cputable.h>
-
 #include "utils.h"
 #include "instructions.h"
 
@@ -64,6 +62,7 @@ int bufsize;
 int debug;
 int testing;
 volatile int gotsig;
+bool prefixes_enabled;
 char *cipath = "/dev/fb0";
 long cioffset;
 
@@ -77,7 +76,12 @@ void sighandler(int sig, siginfo_t *info, void *ctx)
        }
        gotsig = sig;
 #ifdef __powerpc64__
-       ucp->uc_mcontext.gp_regs[PT_NIP] += 4;
+       if (prefixes_enabled) {
+               u32 inst = *(u32 *)ucp->uc_mcontext.gp_regs[PT_NIP];
+               ucp->uc_mcontext.gp_regs[PT_NIP] += ((inst >> 26 == 1) ? 8 : 4);
+       } else {
+               ucp->uc_mcontext.gp_regs[PT_NIP] += 4;
+       }
 #else
        ucp->uc_mcontext.uc_regs->gregs[PT_NIP] += 4;
 #endif
@@ -648,6 +652,8 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       prefixes_enabled = have_hwcap2(PPC_FEATURE2_ARCH_3_1);
+
        rc |= test_harness(test_alignment_handler_vsx_206,
                           "test_alignment_handler_vsx_206");
        rc |= test_harness(test_alignment_handler_vsx_207,
index d50cc05..96554e2 100644 (file)
@@ -481,6 +481,12 @@ int main(int argc, char *argv[])
        else
                printf("futex");
 
+       if (!have_hwcap(PPC_FEATURE_HAS_ALTIVEC))
+               touch_altivec = 0;
+
+       if (!have_hwcap(PPC_FEATURE_HAS_VSX))
+               touch_vector = 0;
+
        printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n",
               cpu1, cpu2, touch_fp ?  "yes" : "no", touch_altivec ? "yes" : "no",
               touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no");
index cfa6eed..845db62 100644 (file)
@@ -10,4 +10,4 @@ include ../../lib.mk
 
 $(OUTPUT)/dscr_default_test: LDLIBS += -lpthread
 
-$(TEST_GEN_PROGS): ../harness.c
+$(TEST_GEN_PROGS): ../harness.c ../utils.c
index 288a4e2..e76611e 100644 (file)
@@ -63,6 +63,8 @@ int dscr_default(void)
        unsigned long i, *status[THREADS];
        unsigned long orig_dscr_default;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        orig_dscr_default = get_default_dscr();
 
        /* Initial DSCR default */
index aefcd8d..32fcf2b 100644 (file)
@@ -21,6 +21,8 @@ int dscr_explicit(void)
 {
        unsigned long i, dscr = 0;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        srand(getpid());
        set_dscr(dscr);
 
index 7c1cb46..c6a81b2 100644 (file)
@@ -44,6 +44,8 @@ int dscr_inherit_exec(void)
        unsigned long i, dscr = 0;
        pid_t pid;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        for (i = 0; i < COUNT; i++) {
                dscr++;
                if (dscr > DSCR_MAX)
index 04297a6..f9dfd3d 100644 (file)
@@ -22,6 +22,8 @@ int dscr_inherit(void)
        unsigned long i, dscr = 0;
        pid_t pid;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        srand(getpid());
        set_dscr(dscr);
 
index 02f6b4e..fbbdffd 100644 (file)
@@ -77,6 +77,8 @@ int dscr_sysfs(void)
        unsigned long orig_dscr_default;
        int i, j;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        orig_dscr_default = get_default_dscr();
        for (i = 0; i < COUNT; i++) {
                for (j = 0; j < DSCR_MAX; j++) {
index 37be2c2..191ed12 100644 (file)
@@ -56,6 +56,8 @@ int dscr_sysfs_thread(void)
        unsigned long orig_dscr_default;
        int i, j;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        orig_dscr_default = get_default_dscr();
        for (i = 0; i < COUNT; i++) {
                for (j = 0; j < DSCR_MAX; j++) {
index eaf785d..e090724 100644 (file)
@@ -36,6 +36,8 @@ int dscr_user(void)
 {
        int i;
 
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
        check_dscr("");
 
        for (i = 0; i < COUNT; i++) {
index 8a8d0f4..0d783e1 100755 (executable)
@@ -1,17 +1,19 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0-only
 
+KSELFTESTS_SKIP=4
+
 . ./eeh-functions.sh
 
 if ! eeh_supported ; then
        echo "EEH not supported on this system, skipping"
-       exit 0;
+       exit $KSELFTESTS_SKIP;
 fi
 
 if [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_check" ] && \
    [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_break" ] ; then
        echo "debugfs EEH testing files are missing. Is debugfs mounted?"
-       exit 1;
+       exit $KSELFTESTS_SKIP;
 fi
 
 pre_lspci=`mktemp`
@@ -84,4 +86,5 @@ echo "$failed devices failed to recover ($dev_count tested)"
 lspci | diff -u $pre_lspci -
 rm -f $pre_lspci
 
-exit $failed
+test "$failed" == 0
+exit $?
index 71d2924..052b5a7 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <linux/auxvec.h>
 #include <linux/perf_event.h>
+#include <asm/cputable.h>
 #include "reg.h"
 
 /* Avoid headaches with PRI?64 - just use %ll? always */
@@ -35,7 +36,6 @@ int pick_online_cpu(void);
 int read_debugfs_file(char *debugfs_file, int *result);
 int write_debugfs_file(char *debugfs_file, int result);
 int read_sysfs_file(char *debugfs_file, char *result, size_t result_size);
-void set_dscr(unsigned long val);
 int perf_event_open_counter(unsigned int type,
                            unsigned long config, int group_fd);
 int perf_event_enable(int fd);
index a864ed7..fd747b2 100644 (file)
@@ -139,5 +139,6 @@ static int test(void)
 
 int main(void)
 {
+       test_harness_set_timeout(300);
        return test_harness(test, "bad_accesses");
 }
index 2980abc..2070a1e 100644 (file)
@@ -9,7 +9,6 @@
 #include <stdbool.h>
 #include <string.h>
 #include <sys/prctl.h>
-#include <asm/cputable.h>
 
 #include "event.h"
 #include "utils.h"
index a96d512..a5dfa9b 100644 (file)
@@ -20,6 +20,9 @@ static int l3_bank_test(void)
        char *p;
        int i;
 
+       // The L3 bank logic is only used on Power8 or later
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
+
        p = malloc(MALLOC_SIZE);
        FAIL_IF(!p);
 
index 2d37942..ad32a09 100644 (file)
@@ -12,8 +12,6 @@
 #include <string.h>
 #include <sys/prctl.h>
 
-#include <asm/cputable.h>
-
 #include "event.h"
 #include "lib.h"
 #include "utils.h"
index fc477df..2e0d86e 100644 (file)
@@ -20,6 +20,8 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/syscall.h>
+#include <linux/limits.h>
 #include "ptrace.h"
 
 #define SPRN_PVR       0x11F
@@ -44,6 +46,7 @@ struct gstruct {
 };
 static volatile struct gstruct gstruct __attribute__((aligned(512)));
 
+static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
 
 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
 {
@@ -138,6 +141,9 @@ static void test_workload(void)
                        write_var(len);
        }
 
+       /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
+       syscall(__NR_getcwd, &cwd, PATH_MAX);
+
        /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
        write_var(1);
 
@@ -150,6 +156,9 @@ static void test_workload(void)
        else
                read_var(1);
 
+       /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
+       syscall(__NR_getcwd, &cwd, PATH_MAX);
+
        /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
        gstruct.a[rand() % A_LEN] = 'a';
 
@@ -293,6 +302,24 @@ static int test_set_debugreg(pid_t child_pid)
        return 0;
 }
 
+static int test_set_debugreg_kernel_userspace(pid_t child_pid)
+{
+       unsigned long wp_addr = (unsigned long)cwd;
+       char *name = "PTRACE_SET_DEBUGREG";
+
+       /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
+       wp_addr &= ~0x7UL;
+       wp_addr |= (1Ul << DABR_READ_SHIFT);
+       wp_addr |= (1UL << DABR_WRITE_SHIFT);
+       wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
+       ptrace_set_debugreg(child_pid, wp_addr);
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
+
+       ptrace_set_debugreg(child_pid, 0);
+       return 0;
+}
+
 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
                                  unsigned long addr, int len)
 {
@@ -338,6 +365,22 @@ static void test_sethwdebug_exact(pid_t child_pid)
        ptrace_delhwdebug(child_pid, wh);
 }
 
+static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
+{
+       struct ppc_hw_breakpoint info;
+       unsigned long wp_addr = (unsigned long)&cwd;
+       char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
+       int len = 1; /* hardcoded in kernel */
+       int wh;
+
+       /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
+       get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
+       wh = ptrace_sethwdebug(child_pid, &info);
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
+       ptrace_delhwdebug(child_pid, wh);
+}
+
 static void test_sethwdebug_range_aligned(pid_t child_pid)
 {
        struct ppc_hw_breakpoint info;
@@ -452,9 +495,10 @@ static void
 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
 {
        test_set_debugreg(child_pid);
+       test_set_debugreg_kernel_userspace(child_pid);
+       test_sethwdebug_exact(child_pid);
+       test_sethwdebug_exact_kernel_userspace(child_pid);
        if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
-               test_sethwdebug_exact(child_pid);
-
                test_sethwdebug_range_aligned(child_pid);
                if (dawr || is_8xx) {
                        test_sethwdebug_range_unaligned(child_pid);
index 0a7d0af..93a65bd 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdint.h>
 #include <malloc.h>
 #include <unistd.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -41,6 +42,40 @@ static void syscall_loop(char *p, unsigned long iterations,
        }
 }
 
+static void sigill_handler(int signr, siginfo_t *info, void *unused)
+{
+       static int warned = 0;
+       ucontext_t *ctx = (ucontext_t *)unused;
+       unsigned long *pc = &UCONTEXT_NIA(ctx);
+
+       /* mtspr 3,RS to check for move to DSCR below */
+       if ((*((unsigned int *)*pc) & 0xfc1fffff) == 0x7c0303a6) {
+               if (!warned++)
+                       printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
+               *pc += 4;
+       } else {
+               printf("SIGILL at %p\n", pc);
+               abort();
+       }
+}
+
+static void set_dscr(unsigned long val)
+{
+       static int init = 0;
+       struct sigaction sa;
+
+       if (!init) {
+               memset(&sa, 0, sizeof(sa));
+               sa.sa_sigaction = sigill_handler;
+               sa.sa_flags = SA_SIGINFO;
+               if (sigaction(SIGILL, &sa, NULL))
+                       perror("sigill_handler");
+               init = 1;
+       }
+
+       asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
+}
+
 int rfi_flush_test(void)
 {
        char *p;
@@ -54,6 +89,9 @@ int rfi_flush_test(void)
 
        SKIP_IF(geteuid() != 0);
 
+       // The PMU event we use only works on Power7 or later
+       SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
+
        if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_org)) {
                perror("Unable to read powerpc/rfi_flush debugfs file");
                SKIP_IF(1);
index c8d82b7..adc2b72 100644 (file)
@@ -134,6 +134,9 @@ int spectre_v2_test(void)
        s64 miss_percent;
        bool is_p9;
 
+       // The PMU events we use only work on Power8 or later
+       SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07));
+
        state = get_sysfs_state();
        if (state == UNKNOWN) {
                printf("Error: couldn't determine spectre_v2 mitigation state?\n");
index 979df3d..cb2f188 100644 (file)
@@ -4,7 +4,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <time.h>
-#include <asm/cputable.h>
+
 #include "utils.h"
 
 #define SIZE 256
index cc49304..7887f78 100644 (file)
@@ -3,9 +3,13 @@
 
        .data
        .balign 8
-message:
+success_message:
        .ascii "success: switch_endian_test\n\0"
 
+       .balign 8
+failure_message:
+       .ascii "failure: switch_endian_test\n\0"
+
        .section ".toc"
        .balign 8
 pattern:
@@ -64,6 +68,9 @@ FUNC_START(_start)
        li r0, __NR_switch_endian
        sc
 
+       tdi   0, 0, 0x48        // b +8 if the endian was switched
+       b     .Lfail            // exit if endian didn't switch
+
 #include "check-reversed.S"
 
        /* Flip back, r0 already has the switch syscall number */
@@ -71,12 +78,20 @@ FUNC_START(_start)
 
 #include "check.S"
 
+       ld      r4, success_message@got(%r2)
+       li      r5, 28  // strlen(success_message)
+       li      r14, 0  // exit status
+.Lout:
        li      r0, __NR_write
        li      r3, 1   /* stdout */
-       ld      r4, message@got(%r2)
-       li      r5, 28  /* strlen(message3) */
        sc
        li      r0, __NR_exit
-       li      r3, 0
+       mr      r3, r14
        sc
        b       .
+
+.Lfail:
+       ld      r4, failure_message@got(%r2)
+       li      r5, 28  // strlen(failure_message)
+       li      r14, 1
+       b       .Lout
index 01b2277..b63f845 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-TEST_GEN_PROGS := ipc_unmuxed
+TEST_GEN_PROGS := ipc_unmuxed rtas_filter
 
 CFLAGS += -I../../../../../usr/include
 
diff --git a/tools/testing/selftests/powerpc/syscalls/rtas_filter.c b/tools/testing/selftests/powerpc/syscalls/rtas_filter.c
new file mode 100644 (file)
index 0000000..03b487f
--- /dev/null
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2005-2020 IBM Corporation.
+ *
+ * Includes code from librtas (https://github.com/ibm-power-utilities/librtas/)
+ */
+
+#include <byteswap.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "utils.h"
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define cpu_to_be32(x)         bswap_32(x)
+#define be32_to_cpu(x)         bswap_32(x)
+#else
+#define cpu_to_be32(x)         (x)
+#define be32_to_cpu(x)         (x)
+#endif
+
+#define RTAS_IO_ASSERT -1098   /* Unexpected I/O Error */
+#define RTAS_UNKNOWN_OP -1099  /* No Firmware Implementation of Function */
+#define BLOCK_SIZE 4096
+#define PAGE_SIZE 4096
+#define MAX_PAGES 64
+
+static const char *ofdt_rtas_path = "/proc/device-tree/rtas";
+
+typedef __be32 uint32_t;
+struct rtas_args {
+       __be32 token;
+       __be32 nargs;
+       __be32 nret;
+       __be32 args[16];
+       __be32 *rets;     /* Pointer to return values in args[]. */
+};
+
+struct region {
+       uint64_t addr;
+       uint32_t size;
+       struct region *next;
+};
+
+int read_entire_file(int fd, char **buf, size_t *len)
+{
+       size_t buf_size = 0;
+       size_t off = 0;
+       int rc;
+
+       *buf = NULL;
+       do {
+               buf_size += BLOCK_SIZE;
+               if (*buf == NULL)
+                       *buf = malloc(buf_size);
+               else
+                       *buf = realloc(*buf, buf_size);
+
+               if (*buf == NULL)
+                       return -ENOMEM;
+
+               rc = read(fd, *buf + off, BLOCK_SIZE);
+               if (rc < 0)
+                       return -EIO;
+
+               off += rc;
+       } while (rc == BLOCK_SIZE);
+
+       if (len)
+               *len = off;
+
+       return 0;
+}
+
+static int open_prop_file(const char *prop_path, const char *prop_name, int *fd)
+{
+       char *path;
+       int len;
+
+       /* allocate enough for two string, a slash and trailing NULL */
+       len = strlen(prop_path) + strlen(prop_name) + 1 + 1;
+       path = malloc(len);
+       if (path == NULL)
+               return -ENOMEM;
+
+       snprintf(path, len, "%s/%s", prop_path, prop_name);
+
+       *fd = open(path, O_RDONLY);
+       free(path);
+       if (*fd < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int get_property(const char *prop_path, const char *prop_name,
+                       char **prop_val, size_t *prop_len)
+{
+       int rc, fd;
+
+       rc = open_prop_file(prop_path, prop_name, &fd);
+       if (rc)
+               return rc;
+
+       rc = read_entire_file(fd, prop_val, prop_len);
+       close(fd);
+
+       return rc;
+}
+
+int rtas_token(const char *call_name)
+{
+       char *prop_buf = NULL;
+       size_t len;
+       int rc;
+
+       rc = get_property(ofdt_rtas_path, call_name, &prop_buf, &len);
+       if (rc < 0) {
+               rc = RTAS_UNKNOWN_OP;
+               goto err;
+       }
+
+       rc = be32_to_cpu(*(int *)prop_buf);
+
+err:
+       free(prop_buf);
+       return rc;
+}
+
+static int read_kregion_bounds(struct region *kregion)
+{
+       char *buf;
+       int fd;
+       int rc;
+
+       fd = open("/proc/ppc64/rtas/rmo_buffer", O_RDONLY);
+       if (fd < 0) {
+               printf("Could not open rmo_buffer file\n");
+               return RTAS_IO_ASSERT;
+       }
+
+       rc = read_entire_file(fd, &buf, NULL);
+       close(fd);
+       if (rc) {
+               free(buf);
+               return rc;
+       }
+
+       sscanf(buf, "%" SCNx64 " %x", &kregion->addr, &kregion->size);
+       free(buf);
+
+       if (!(kregion->size && kregion->addr) ||
+           (kregion->size > (PAGE_SIZE * MAX_PAGES))) {
+               printf("Unexpected kregion bounds\n");
+               return RTAS_IO_ASSERT;
+       }
+
+       return 0;
+}
+
+static int rtas_call(const char *name, int nargs,
+                    int nrets, ...)
+{
+       struct rtas_args args;
+       __be32 *rets[16];
+       int i, rc, token;
+       va_list ap;
+
+       va_start(ap, nrets);
+
+       token = rtas_token(name);
+       if (token == RTAS_UNKNOWN_OP) {
+               // We don't care if the call doesn't exist
+               printf("call '%s' not available, skipping...", name);
+               rc = RTAS_UNKNOWN_OP;
+               goto err;
+       }
+
+       args.token = cpu_to_be32(token);
+       args.nargs = cpu_to_be32(nargs);
+       args.nret = cpu_to_be32(nrets);
+
+       for (i = 0; i < nargs; i++)
+               args.args[i] = (__be32) va_arg(ap, unsigned long);
+
+       for (i = 0; i < nrets; i++)
+               rets[i] = (__be32 *) va_arg(ap, unsigned long);
+
+       rc = syscall(__NR_rtas, &args);
+       if (rc) {
+               rc = -errno;
+               goto err;
+       }
+
+       if (nrets) {
+               *(rets[0]) = be32_to_cpu(args.args[nargs]);
+
+               for (i = 1; i < nrets; i++) {
+                       *(rets[i]) = args.args[nargs + i];
+               }
+       }
+
+err:
+       va_end(ap);
+       return rc;
+}
+
+static int test(void)
+{
+       struct region rmo_region;
+       uint32_t rmo_start;
+       uint32_t rmo_end;
+       __be32 rets[1];
+       int rc;
+
+       // Test a legitimate harmless call
+       // Expected: call succeeds
+       printf("Test a permitted call, no parameters... ");
+       rc = rtas_call("get-time-of-day", 0, 1, rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != 0 && rc != RTAS_UNKNOWN_OP);
+
+       // Test a prohibited call
+       // Expected: call returns -EINVAL
+       printf("Test a prohibited call... ");
+       rc = rtas_call("nvram-fetch", 0, 1, rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != -EINVAL && rc != RTAS_UNKNOWN_OP);
+
+       // Get RMO
+       rc = read_kregion_bounds(&rmo_region);
+       if (rc) {
+               printf("Couldn't read RMO region bounds, skipping remaining cases\n");
+               return 0;
+       }
+       rmo_start = rmo_region.addr;
+       rmo_end = rmo_start + rmo_region.size - 1;
+       printf("RMO range: %08x - %08x\n", rmo_start, rmo_end);
+
+       // Test a permitted call, user-supplied size, buffer inside RMO
+       // Expected: call succeeds
+       printf("Test a permitted call, user-supplied size, buffer inside RMO... ");
+       rc = rtas_call("ibm,get-system-parameter", 3, 1, 0, cpu_to_be32(rmo_start),
+                      cpu_to_be32(rmo_end - rmo_start + 1), rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != 0 && rc != RTAS_UNKNOWN_OP);
+
+       // Test a permitted call, user-supplied size, buffer start outside RMO
+       // Expected: call returns -EINVAL
+       printf("Test a permitted call, user-supplied size, buffer start outside RMO... ");
+       rc = rtas_call("ibm,get-system-parameter", 3, 1, 0, cpu_to_be32(rmo_end + 1),
+                      cpu_to_be32(4000), rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != -EINVAL && rc != RTAS_UNKNOWN_OP);
+
+       // Test a permitted call, user-supplied size, buffer end outside RMO
+       // Expected: call returns -EINVAL
+       printf("Test a permitted call, user-supplied size, buffer end outside RMO... ");
+       rc = rtas_call("ibm,get-system-parameter", 3, 1, 0, cpu_to_be32(rmo_start),
+                      cpu_to_be32(rmo_end - rmo_start + 2), rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != -EINVAL && rc != RTAS_UNKNOWN_OP);
+
+       // Test a permitted call, fixed size, buffer end outside RMO
+       // Expected: call returns -EINVAL
+       printf("Test a permitted call, fixed size, buffer end outside RMO... ");
+       rc = rtas_call("ibm,configure-connector", 2, 1, cpu_to_be32(rmo_end - 4000), 0, rets);
+       printf("rc: %d\n", rc);
+       FAIL_IF(rc != -EINVAL && rc != RTAS_UNKNOWN_OP);
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       return test_harness(test, "rtas_filter");
+}
index 9775584..29e5f26 100644 (file)
@@ -26,7 +26,7 @@
 
 int tm_poison_test(void)
 {
-       int pid;
+       int cpu, pid;
        cpu_set_t cpuset;
        uint64_t poison = 0xdeadbeefc0dec0fe;
        uint64_t unknown = 0;
@@ -35,10 +35,13 @@ int tm_poison_test(void)
 
        SKIP_IF(!have_htm());
 
-       /* Attach both Child and Parent to CPU 0 */
+       cpu = pick_online_cpu();
+       FAIL_IF(cpu < 0);
+
+       // Attach both Child and Parent to the same CPU
        CPU_ZERO(&cpuset);
-       CPU_SET(0, &cpuset);
-       sched_setaffinity(0, sizeof(cpuset), &cpuset);
+       CPU_SET(cpu, &cpuset);
+       FAIL_IF(sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0);
 
        pid = fork();
        if (!pid) {
index 17becf3..794d574 100644 (file)
 #include "utils.h"
 #include "tm.h"
 
-int    num_loops       = 10000;
+int    num_loops       = 1000000;
 int    passed = 1;
 
 void tfiar_tfhar(void *in)
 {
-       int i, cpu;
        unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd;
-       cpu_set_t cpuset;
-
-       CPU_ZERO(&cpuset);
-       cpu = (unsigned long)in >> 1;
-       CPU_SET(cpu, &cpuset);
-       sched_setaffinity(0, sizeof(cpuset), &cpuset);
+       int i;
 
        /* TFIAR: Last bit has to be high so userspace can read register */
        tfiar = ((unsigned long)in) + 1;
index 601f0c1..c75960a 100644 (file)
@@ -247,8 +247,7 @@ void *pong(void *not_used)
 int tm_trap_test(void)
 {
        uint16_t k = 1;
-
-       int rc;
+       int cpu, rc;
 
        pthread_attr_t attr;
        cpu_set_t cpuset;
@@ -267,9 +266,12 @@ int tm_trap_test(void)
        usr1_sa.sa_sigaction = usr1_signal_handler;
        sigaction(SIGUSR1, &usr1_sa, NULL);
 
-       /* Set only CPU 0 in the mask. Both threads will be bound to cpu 0. */
+       cpu = pick_online_cpu();
+       FAIL_IF(cpu < 0);
+
+       // Set only one CPU in the mask. Both threads will be bound to that CPU.
        CPU_ZERO(&cpuset);
-       CPU_SET(0, &cpuset);
+       CPU_SET(cpu, &cpuset);
 
        /* Init pthread attribute */
        rc = pthread_attr_init(&attr);
index 2ca2fcc..a1348a5 100644 (file)
@@ -338,16 +338,19 @@ void test_fp_vec(int fp, int vec, pthread_attr_t *attr)
 
 int tm_unavailable_test(void)
 {
-       int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
+       int cpu, rc, exception; /* FP = 0, VEC = 1, VSX = 2 */
        pthread_t t1;
        pthread_attr_t attr;
        cpu_set_t cpuset;
 
        SKIP_IF(!have_htm());
 
-       /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */
+       cpu = pick_online_cpu();
+       FAIL_IF(cpu < 0);
+
+       // Set only one CPU in the mask. Both threads will be bound to that CPU.
        CPU_ZERO(&cpuset);
-       CPU_SET(0, &cpuset);
+       CPU_SET(cpu, &cpuset);
 
        /* Init pthread attribute. */
        rc = pthread_attr_init(&attr);
index c402464..c5a1e5c 100644 (file)
@@ -6,9 +6,8 @@
 #ifndef _SELFTESTS_POWERPC_TM_TM_H
 #define _SELFTESTS_POWERPC_TM_TM_H
 
-#include <asm/tm.h>
-#include <asm/cputable.h>
 #include <stdbool.h>
+#include <asm/tm.h>
 
 #include "utils.h"
 
index 18b6a77..1f36ee1 100644 (file)
@@ -10,7 +10,6 @@
 #include <fcntl.h>
 #include <link.h>
 #include <sched.h>
-#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -273,40 +272,6 @@ int perf_event_reset(int fd)
        return 0;
 }
 
-static void sigill_handler(int signr, siginfo_t *info, void *unused)
-{
-       static int warned = 0;
-       ucontext_t *ctx = (ucontext_t *)unused;
-       unsigned long *pc = &UCONTEXT_NIA(ctx);
-
-       /* mtspr 3,RS to check for move to DSCR below */
-       if ((*((unsigned int *)*pc) & 0xfc1fffff) == 0x7c0303a6) {
-               if (!warned++)
-                       printf("WARNING: Skipping over dscr setup. Consider running 'ppc64_cpu --dscr=1' manually.\n");
-               *pc += 4;
-       } else {
-               printf("SIGILL at %p\n", pc);
-               abort();
-       }
-}
-
-void set_dscr(unsigned long val)
-{
-       static int init = 0;
-       struct sigaction sa;
-
-       if (!init) {
-               memset(&sa, 0, sizeof(sa));
-               sa.sa_sigaction = sigill_handler;
-               sa.sa_flags = SA_SIGINFO;
-               if (sigaction(SIGILL, &sa, NULL))
-                       perror("sigill_handler");
-               init = 1;
-       }
-
-       asm volatile("mtspr %1,%0" : : "r" (val), "i" (SPRN_DSCR));
-}
-
 int using_hash_mmu(bool *using_hash)
 {
        char line[128];
@@ -318,7 +283,9 @@ int using_hash_mmu(bool *using_hash)
 
        rc = 0;
        while (fgets(line, sizeof(line), f) != NULL) {
-               if (strcmp(line, "MMU           : Hash\n") == 0) {
+               if (!strcmp(line, "MMU          : Hash\n") ||
+                   !strcmp(line, "platform     : Cell\n") ||
+                   !strcmp(line, "platform     : PowerMac\n")) {
                        *using_hash = true;
                        goto out;
                }