powerpc updates for 7.3

- powerpc: Enable Rust for ppc64le
 
  - ppc4xx gpio driver updates
 
  - Add power12 base enablement support
 
  - Validate arch_compat against host compatibility mode
 
  - Simplify bootx_scan_dt_build_struct() in powermac platform
 
  - powerpc: implement get_direction() in cpm2
 
  - Use cpu_relax() in ps3_create_spu()
 
  - Add NULL guard for cause_ipi in smp_muxed_ipi_message_pass
 
  - fixes to handle pseries watchdogs in kdump path
 
  - powerpc/irq: Fix missing r2 clobber in PCREL inline assembly
 
  - ppc44x: Set GPIO chip parent
 
  - KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl BY: Amit Machhiwal
 
  - KVM: powerpc: Use generic xfer to guest work function
 
  - Enable to run posix cpu timers in task context
 
  - misc fixes and cleanups
 
 Thanks to:
 Aditya Gupta, Alice Ryhl, Amit Machhiwal, Andrew Morton, Anushree Mathur,
 Athira Rajeev, Bartosz Golaszewski, Cédric Le Goater, Christian König,
 Christophe Leroy (CS GROUP), Gary Guo, Gaurav Batra, Gautam Menghani, Gou Hao,
 Hari Bathini, Harsh Prateek Bora, jiazhenyuan, Jinjie Ruan, Link Mauve, Linus
 Walleij, Mahesh Kumar G Mahesh Salgaonkar, Michael Walle, Michal Suchánek,
 Mukesh Kumar Chaurasiya (IBM), Nicholas Piggin, Nikhil Kumar Singh, Praveen K
 Pandey, Ritesh Harjani (IBM), Rosen Penev, Saket Kumar Bhaskar, Shrikanth
 Hegde, Sourabh Jain, Thorsten Blum, Vaibhav Jain, Venkat Rao Bagalkote, Vishal
 Chourasia, Wentao Guan, Yanfei Xu
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqX2DNAOgU8sBX3pRpnEsdPSHZJQFAmqCj/4ACgkQpnEsdPSH
 ZJSKNg//VNpbzMKVPrdljgLn3P8/flWUUMvbjT0j2s5OExeFPjM9tvJQucMficJz
 eQWaEZbaczRPdtBDt96NXXDIoXGpfapS1Tj18OjVjCRtQdKV4DGfNdE5wC2tKwvA
 1R6x5FT6pGxCRuNY9o3aAo/qcEJLCWCtOvrgdlT8C9ZV8Zh/GRl5TXBYqB4LFYAd
 WI1Jc4s97VFNtPSh7HtImd5n8T8vNWqQzi1rUAWTYQPduV8eHKFhnyu9vIh2ISv8
 p6dZzE6mLrgn7zU8HW2z5nRyRZFRXtWt3i7/0IGSsJYtBoREsFw2d3LJfwMZXwdU
 hXNbw9OlwDmPUF8+qFIEVu3czfiFW1naNEXP00NJfM+67acXIpFEiJ/LvuLENzC4
 gtX1VKUCQthWxJESnX1WrKnP7BAjUGe691CronRoYIJNctLnrCA7SOfJ2El4i40v
 v0+oz8KceGE3AU/1SpcKC8WlrHGb7qDBHS1HD8wpdcMsL1LTUWlghAptc/CrpRSb
 vDbiQAK7RHAEVSx6CsW1pVdFGOk5k7QQgeX6ptyK2aliQhuS4UA5b7zMmE+agPY4
 Pro2bQLZYPfIW92OB1Zf+h69bUn4aVyp5ov1U1kTJuFHSEH+9+ZVemZg/f2fN8LV
 bwgErs0YPL/N5099qolj9mmNvn8RcVwub6nIGrVryGbBLprlV3o=
 =4Mg5
 -----END PGP SIGNATURE-----

Merge tag 'powerpc-7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc updates from Madhavan Srinivasan:

 - Enable Rust for ppc64le

 - ppc4xx gpio driver updates

 - Add power12 base enablement support

 - Validate arch_compat against host compatibility mode

 - Simplify bootx_scan_dt_build_struct() in powermac platform

 - Implement get_direction() in cpm2

 - Use cpu_relax() in ps3_create_spu()

 - Add NULL guard for cause_ipi in smp_muxed_ipi_message_pass

 - Fixes to handle pseries watchdogs in kdump path

 - Fix missing r2 clobber in PCREL inline assembly

 - Set GPIO chip parent on ppc44x

 - KVM: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl

 - KVM: Use generic xfer to guest work function

 - Enable to run posix cpu timers in task context

 - Misc fixes and cleanups

Thanks to Aditya Gupta, Alice Ryhl, Amit Machhiwal, Andrew Morton,
Anushree Mathur, Athira Rajeev, Bartosz Golaszewski, Cédric Le Goater,
Christian König, Christophe Leroy (CS GROUP), Gary Guo, Gaurav Batra,
Gautam Menghani, Gou Hao, Hari Bathini, Harsh Prateek Bora, jiazhenyuan,
Jinjie Ruan, Link Mauve, Linus Walleij, Mahesh Kumar G Mahesh
Salgaonkar, Michael Walle, Michal Suchánek, Mukesh Kumar Chaurasiya
(IBM), Nicholas Piggin, Nikhil Kumar Singh, Praveen K Pandey, Ritesh
Harjani (IBM), Rosen Penev, Saket Kumar Bhaskar, Shrikanth Hegde,
Sourabh Jain, Thorsten Blum, Vaibhav Jain, Venkat Rao Bagalkote, Vishal
Chourasia, Wentao Guan, and Yanfei Xu.

* tag 'powerpc-7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (62 commits)
  powerpc/pseries/iommu: switch to Default DMA window during kdump
  powerpc/configs: enable CONFIG_RAS to fix EDAC support
  KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
  KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
  KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
  KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
  gpio: ppc44x: use dev_name() for chip label
  gpio: ppc44x: fix undefined behavior in GPIO_MASK2 macro
  gpio: ppc44x: drop PPC-specific IO helpers
  gpio: ppc44x: Convert GPIO to generic MMIO
  gpio: ppc44x: Use platform resource helper for GPIO MMIO
  gpio: ppc44x: Use module platform driver helper for GPIO
  gpio: ppc44x: update all 4xx to 44x
  gpio: move ppc4xx gpio driver from arch/powerpc to drivers/gpio
  KVM: PPC: Use min() in kvm_vm_ioctl_check_extension()
  KVM: PPC: booke: Use min() in watchdog_next_timeout()
  powerpc/perf: Add power12 Base Performance Monitoring support
  powerpc: Add Power12 architected mode
  powerpc: Add Power12 raw mode
  powerpc/pseries: Limit PVR list to 16 entries for CAS negotiation
  ...
This commit is contained in:
Linus Torvalds 2026-08-18 12:08:13 -07:00
commit 1200d84f4c
77 changed files with 1616 additions and 495 deletions

View File

@ -6566,6 +6566,83 @@ KVM_S390_KEYOP_SSKE
Sets the storage key for the guest address ``guest_addr`` to the key
specified in ``key``, returning the previous value in ``key``.
4.145 KVM_PPC_GET_COMPAT_CAPS
-----------------------------
:Capability: KVM_CAP_PPC_COMPAT_CAPS
:Architectures: powerpc
:Type: vm ioctl
:Parameters: struct kvm_ppc_compat_caps (in/out)
:Returns: 0 on success, negative value on failure
Errors include:
======== ============================================================
EFAULT if ``struct kvm_ppc_compat_caps`` cannot be read from or
written to userspace
EINVAL if the ``size`` field is smaller than
``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
is non-zero, or if the backend fails to retrieve or map
CPU compatibility capabilities
E2BIG if ``size`` exceeds ``PAGE_SIZE`` (pathological input guard),
or if ``size`` is larger than the kernel's struct size and
the unknown trailing bytes are non-zero (new userspace on
old kernel with non-default fields set); in the latter case
the kernel writes back its own struct size into the ``size``
field so userspace can retry with the correct size
ENOTTY if the backend does not implement the ``get_compat_caps``
operation (e.g., on non-HV KVM implementations where the
required KVM operations are not available)
======== ============================================================
IBM POWER system server-based processors provide a compatibility mode feature
where an Nth generation processor can operate in modes consistent with earlier
generations such as (N-1) and (N-2).
This ioctl provides userspace with information about the CPU compatibility modes
supported by the current host processor for booting the nested KVM guests on
KVM on PowerNV (nested API v1) and KVM on PowerVM (nested API v2) platforms.
::
struct kvm_ppc_compat_caps {
__u64 size; /* Size of this structure */
__u64 flags; /* Reserved for future use, must be 0 */
__u64 compat_capabilities; /* Capabilities supported by the host */
};
Before calling this ioctl, userspace must set the ``size`` field to
``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
uninitialized stack values from being silently accepted, keeping the
field available for future use without ABI ambiguity.
The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
to support extensible versioning.
``KVM_PPC_COMPAT_CAPS_SIZE_VER0`` (24) is a frozen constant marking the
size of the initial struct version.
The ``compat_capabilities`` bit field describes the processor compatibility
modes supported by the host. The following bits indicate support for specific
processor modes (using IBM's MSB-0 convention where bit 0 is the most
significant bit):
- ``KVM_PPC_COMPAT_CAP_POWER9`` (bit 1) -- KVM guests can run in Power9 processor mode
- ``KVM_PPC_COMPAT_CAP_POWER10`` (bit 2) -- KVM guests can run in Power10 processor mode
- ``KVM_PPC_COMPAT_CAP_POWER11`` (bit 3) -- KVM guests can run in Power11 processor mode
.. note::
The bit numbering above uses IBM's MSB-0 convention (bit 0 is the most
significant bit). In the actual implementation, these are defined as:
- ``KVM_PPC_COMPAT_CAP_POWER9`` = ``(1ULL << 62)``
- ``KVM_PPC_COMPAT_CAP_POWER10`` = ``(1ULL << 61)``
- ``KVM_PPC_COMPAT_CAP_POWER11`` = ``(1ULL << 60)``
Userspace should use the defined constants from ``<linux/kvm.h>`` rather
than hardcoding bit positions.
.. _kvm_run:
5. The kvm_run structure

View File

@ -281,10 +281,13 @@ config PPC
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select HAVE_PREEMPT_DYNAMIC_KEY
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_RETHOOK if KPROBES
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RELIABLE_STACKTRACE
select HAVE_RSEQ
select HAVE_RUST if PPC32
select HAVE_RUST if PPC64 && CPU_LITTLE_ENDIAN
select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_SETUP_PER_CPU_AREA if PPC64

View File

@ -61,6 +61,13 @@ else
KBUILD_LDFLAGS_MODULE += $(objtree)/arch/powerpc/lib/crtsavres.o
endif
ifdef CONFIG_PPC64
KBUILD_RUSTFLAGS += --target=powerpc64le-unknown-linux-gnu
KBUILD_RUSTFLAGS += -Ctarget-feature=-mma,-vsx,-hard-float,-altivec
else
KBUILD_RUSTFLAGS += --target=powerpc-unknown-linux-gnu
endif
ifdef CONFIG_CPU_LITTLE_ENDIAN
KBUILD_CPPFLAGS += -mlittle-endian
KBUILD_LDFLAGS += -EL

View File

@ -37,7 +37,6 @@ static void serial_edit_cmdline(char *buf, int len, unsigned int timeout)
char ch, *cp;
struct serial_console_data *scdp = console_ops.data;
cp = buf;
count = strlen(buf);
cp = &buf[count];
count++;

View File

@ -326,17 +326,6 @@ int vsprintf(char *buf, const char *fmt, va_list args)
return str-buf;
}
int sprintf(char * buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
return i;
}
static char sprint_buf[1024];
int

View File

@ -12,9 +12,6 @@ extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define fprintf(fmt, args...) printf(args)
extern int sprintf(char *buf, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
extern int vsprintf(char *buf, const char *fmt, va_list args);
#endif /* _PPC_BOOT_STDIO_H_ */

View File

@ -12,7 +12,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_EBONY is not set
CONFIG_WARP=y
CONFIG_PPC4xx_GPIO=y
CONFIG_GPIO_PPC44X=y
CONFIG_HZ_1000=y
CONFIG_CMDLINE="ip=on"
# CONFIG_PCI is not set

View File

@ -90,6 +90,7 @@ CONFIG_PPC_EPAPR_HV_BYTECHAN=y
CONFIG_QE_GPIO=y
CONFIG_QUICC_ENGINE=y
CONFIG_RAPIDIO=y
CONFIG_RAS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_RTC_DRV_DS1307=y

View File

@ -22,7 +22,7 @@ CONFIG_GLACIER=y
CONFIG_REDWOOD=y
CONFIG_EIGER=y
CONFIG_YOSEMITE=y
CONFIG_PPC4xx_GPIO=y
CONFIG_GPIO_PPC44X=y
CONFIG_MATH_EMULATION=y
CONFIG_NET=y
CONFIG_PACKET=y

View File

@ -9,10 +9,12 @@ void __setup_cpu_power7(unsigned long offset, struct cpu_spec *spec);
void __setup_cpu_power8(unsigned long offset, struct cpu_spec *spec);
void __setup_cpu_power9(unsigned long offset, struct cpu_spec *spec);
void __setup_cpu_power10(unsigned long offset, struct cpu_spec *spec);
void __setup_cpu_power12(unsigned long offset, struct cpu_spec *spec);
void __restore_cpu_power7(void);
void __restore_cpu_power8(void);
void __restore_cpu_power9(void);
void __restore_cpu_power10(void);
void __restore_cpu_power12(void);
void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec *spec);
void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec *spec);

View File

@ -194,6 +194,7 @@ static inline void cpu_feature_keys_init(void) { }
#define CPU_FTR_DAWR1 LONG_ASM_CONST(0x0008000000000000)
#define CPU_FTR_DEXCR_NPHIE LONG_ASM_CONST(0x0010000000000000)
#define CPU_FTR_P11_PVR LONG_ASM_CONST(0x0020000000000000)
#define CPU_FTR_ARCH_32 LONG_ASM_CONST(0x0040000000000000)
#ifndef __ASSEMBLER__
@ -457,6 +458,18 @@ static inline void cpu_feature_keys_init(void) { }
#define CPU_FTRS_POWER11 (CPU_FTRS_POWER10 | CPU_FTR_P11_PVR)
#define CPU_FTRS_POWER12 (CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | \
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR | \
CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_ARCH_207S | \
CPU_FTR_ARCH_300 | CPU_FTR_ARCH_31 | CPU_FTR_ARCH_32 | \
CPU_FTR_DAWR | CPU_FTR_DAWR1)
#define CPU_FTRS_CELL (CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@ -476,7 +489,7 @@ static inline void cpu_feature_keys_init(void) { }
(CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_VSX_COMP | CPU_FTRS_POWER9 | \
CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \
CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11)
CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11 | CPU_FTRS_POWER12)
#else
#define CPU_FTRS_POSSIBLE \
(CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \
@ -484,7 +497,7 @@ static inline void cpu_feature_keys_init(void) { }
CPU_FTRS_POWER8 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \
CPU_FTR_VSX_COMP | CPU_FTR_ALTIVEC_COMP | CPU_FTRS_POWER9 | \
CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \
CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11)
CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11 | CPU_FTRS_POWER12)
#endif /* CONFIG_CPU_LITTLE_ENDIAN */
#endif
#else

View File

@ -15,14 +15,20 @@
#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
#define JUMP_LABEL_NOP_SIZE 4
#define JUMP_TABLE_ENTRY(key, label) \
".pushsection __jump_table, \"aw\" \n\t" \
".long 1b - ., " label " - . \n\t" \
JUMP_ENTRY_TYPE key " - . \n\t" \
".popsection \n\t"
#define ARCH_STATIC_BRANCH_ASM(key, label) \
"1: nop \n\t" \
JUMP_TABLE_ENTRY(key, label)
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
asm goto("1:\n\t"
"nop # arch_static_branch\n\t"
".pushsection __jump_table, \"aw\"\n\t"
".long 1b - ., %l[l_yes] - .\n\t"
JUMP_ENTRY_TYPE "%c0 - .\n\t"
".popsection \n\t"
asm goto(
ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]")
: : "i" (&((char *)key)[branch]) : : l_yes);
return false;
@ -34,10 +40,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool
{
asm goto("1:\n\t"
"b %l[l_yes] # arch_static_branch_jump\n\t"
".pushsection __jump_table, \"aw\"\n\t"
".long 1b - ., %l[l_yes] - .\n\t"
JUMP_ENTRY_TYPE "%c0 - .\n\t"
".popsection \n\t"
JUMP_TABLE_ENTRY("%c0", "%l[l_yes]")
: : "i" (&((char *)key)[branch]) : : l_yes);
return false;

View File

@ -319,6 +319,7 @@ struct kvmppc_ops {
bool (*hash_v3_possible)(void);
int (*create_vm_debugfs)(struct kvm *kvm);
int (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);
int (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps);
};
extern struct kvmppc_ops *kvmppc_hv_ops;

View File

@ -133,6 +133,7 @@
#define MMU_FTRS_POWER9 MMU_FTRS_POWER6
#define MMU_FTRS_POWER10 MMU_FTRS_POWER6
#define MMU_FTRS_POWER11 MMU_FTRS_POWER6
#define MMU_FTRS_POWER12 MMU_FTRS_POWER6
#define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
MMU_FTR_CI_LARGE_PAGE
#define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \

View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_POWERPC_PAPR_WATCHDOG_H
#define _ASM_POWERPC_PAPR_WATCHDOG_H
/*
* H_WATCHDOG Input
*
* R4: "flags":
*
* Bits 48-55: "operation"
*/
#define PSERIES_WDTF_OP_START 0x100UL /* start timer */
#define PSERIES_WDTF_OP_STOP 0x200UL /* stop timer */
#define PSERIES_WDTF_OP_QUERY 0x300UL /* query timer capabilities */
/*
* Bits 56-63: "timeoutAction" (for "Start Watchdog" only)
*/
#define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL /* poweroff */
#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL /* restart */
#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL /* dump + restart */
/*
* R5: "watchdogNumber":
* PAPR says use -1 (all ones) to stop all watchdogs.
*/
#define PSERIES_WDT_NUM_ALL ((unsigned long)-1)
/*
* H_WATCHDOG Output
*
* R3: Return code
*
* H_SUCCESS The operation completed.
*
* H_BUSY The hypervisor is too busy; retry the operation.
*
* H_PARAMETER The given "flags" are somehow invalid. Either the
* "operation" or "timeoutAction" is invalid, or a
* reserved bit is set.
*
* H_P2 The given "watchdogNumber" is zero or exceeds the
* supported maximum value.
*
* H_P3 The given "timeoutInMs" is below the supported
* minimum value.
*
* H_NOOP The given "watchdogNumber" is already stopped.
*
* H_HARDWARE The operation failed for ineffable reasons.
*
* H_FUNCTION The H_WATCHDOG hypercall is not supported by this
* hypervisor.
*
* R4:
*
* - For the "Query Watchdog Capabilities" operation, a 64-bit
* structure:
*/
#define PSERIES_WDTQ_MIN_TIMEOUT(cap) (((cap) >> 48) & 0xffff)
#define PSERIES_WDTQ_MAX_NUMBER(cap) (((cap) >> 32) & 0xffff)
#endif /* _ASM_POWERPC_PAPR_WATCHDOG_H */

View File

@ -117,7 +117,8 @@ extern unsigned int boot_cpu_node_count;
#define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */
#define OV1_PPC_3_00 0x80 /* set if we support PowerPC 3.00 */
#define OV1_PPC_3_1 0x40 /* set if we support PowerPC 3.1 */
#define OV1_PPC_3_1 0x40 /* set if we support PowerPC 3.1 */
#define OV1_PPC_3_2 0x20 /* set if we support PowerPC 3.2 */
/* Option vector 2: Open Firmware options supported */
#define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */

View File

@ -492,11 +492,12 @@
* determine both the compatibility level which we want to emulate and the
* compatibility level which the host is capable of emulating.
*/
#define PCR_ARCH_31 0x20 /* Architecture 3.1 */
#define PCR_ARCH_300 0x10 /* Architecture 3.00 */
#define PCR_ARCH_207 0x8 /* Architecture 2.07 */
#define PCR_ARCH_206 0x4 /* Architecture 2.06 */
#define PCR_ARCH_205 0x2 /* Architecture 2.05 */
#define PCR_LOW_BITS (PCR_ARCH_207 | PCR_ARCH_206 | PCR_ARCH_205 | PCR_ARCH_300)
#define PCR_LOW_BITS (PCR_ARCH_207 | PCR_ARCH_206 | PCR_ARCH_205 | PCR_ARCH_300 | PCR_ARCH_31)
#define PCR_MASK ~(PCR_HIGH_BITS | PCR_LOW_BITS) /* PCR Reserved Bits */
#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
@ -1344,6 +1345,7 @@
#define PVR_POWER9 0x004E
#define PVR_POWER10 0x0080
#define PVR_POWER11 0x0082
#define PVR_POWER12 0x0083
#define PVR_BE 0x0070
#define PVR_PA6T 0x0090
@ -1356,6 +1358,19 @@
#define PVR_ARCH_300 0x0f000005
#define PVR_ARCH_31 0x0f000006
#define PVR_ARCH_31_P11 0x0f000007
#define PVR_ARCH_32 0x0f000008
/*
* Kernel-internal sentinel for invalid processor compatibility modes.
* PAPR specifies that the first byte of a valid logical PVR value is
* 0x0f. So 0xffffffff lies permanently outside the PAPR-defined range
* and is safe to repurpose. KVM stores it in vcpu->arch.arch_compat
* when userspace requests an unsupported compatibility mode (e.g.,
* Power11 PVR on a Power11 host booted in Power10 compat).
* kvmppc_sanity_check() detects this and prevents the vCPU from
* running with an unsupported arch_compat.
*/
#define PVR_ARCH_INVALID 0xffffffff
/* Macros for setting and retrieving special purpose registers */
#ifndef __ASSEMBLER__

View File

@ -7,8 +7,8 @@
* through the device tree.
*/
/* Default baud base if not found in device-tree */
#define BASE_BAUD ( 1843200 / 16 )
/* Provides BASE_BAUD, used as fallback if not found in device tree. */
#include <asm-generic/serial.h>
#ifdef CONFIG_PPC_UDBG_16550
extern void find_legacy_serial_ports(void);

View File

@ -37,8 +37,12 @@ static inline void ppc_after_tlbiel_barrier(void)
* 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.
*
* POWER12 does not need it.
*/
asm volatile(ASM_FTR_IFSET(PPC_CP_ABORT, "", %0) : : "i" (CPU_FTR_ARCH_31) : "memory");
asm volatile(ASM_FTR_IF(PPC_CP_ABORT, "", %0, %1) :
: "i" (CPU_FTR_ARCH_31|CPU_FTR_ARCH_32), "i" (CPU_FTR_ARCH_31)
: "memory");
}
#endif /* __ASSEMBLER__ */

View File

@ -98,6 +98,12 @@ static inline void syscall_set_return_value(struct task_struct *task,
regs->gpr[3] = val;
}
}
/*
* Mark that a return value has been explicitly set by seccomp or
* ptrace so that system_call_exception() can skip the syscall
* unconditionally, even when the user requested syscall(-1).
*/
set_thread_flag(TIF_SYSCALL_RET);
}
static inline void syscall_get_arguments(struct task_struct *task,

View File

@ -120,6 +120,7 @@ void arch_setup_new_exec(void);
#endif
#define TIF_POLLING_NRFLAG 19 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_32BIT 20 /* 32 bit binary */
#define TIF_SYSCALL_RET 21 /* syscall error value set */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)

View File

@ -91,7 +91,7 @@ static inline bool xive_enabled(void) { return __xive_enabled; }
bool xive_spapr_init(void);
bool xive_native_init(void);
void xive_smp_probe(void);
int xive_smp_probe(void);
int xive_smp_prepare_cpu(unsigned int cpu);
void xive_smp_setup_cpu(void);
void xive_smp_disable_cpu(void);
@ -153,7 +153,7 @@ static inline bool xive_enabled(void) { return false; }
static inline bool xive_spapr_init(void) { return false; }
static inline bool xive_native_init(void) { return false; }
static inline void xive_smp_probe(void) { }
static inline int xive_smp_probe(void) { return -EINVAL; }
static inline int xive_smp_prepare_cpu(unsigned int cpu) { return -EINVAL; }
static inline void xive_smp_setup_cpu(void) { }
static inline void xive_smp_disable_cpu(void) { }

View File

@ -52,6 +52,8 @@
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000 /* TM w/out suspended state */
#define PPC_FEATURE2_ARCH_3_1 0x00040000 /* ISA 3.1 */
#define PPC_FEATURE2_MMA 0x00020000 /* Matrix Multiply Assist */
#define PPC_FEATURE2_ARCH_3_2 0x00010000 /* ISA 3.2 */
#define PPC_FEATURE2_DMF 0x00008000 /* Dense Math Facility */
/*
* IMPORTANT!

View File

@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char {
__u64 behaviour_mask; /* valid bits in behaviour */
};
/* For KVM_PPC_GET_COMPAT_CAPS */
struct kvm_ppc_compat_caps {
__u64 size; /* Size of this structure */
__u64 flags; /* Reserved for future use */
__u64 compat_capabilities; /* Capabilities supported by the host */
};
#define KVM_PPC_COMPAT_CAPS_SIZE_VER0 24 /* sizeof first published struct */
/*
* Capability bits for compat_capabilities field in kvm_ppc_compat_caps.
* These bits indicate which processor compatibility modes are supported.
*/
#define KVM_PPC_COMPAT_CAP_POWER9 (1ULL << 62)
#define KVM_PPC_COMPAT_CAP_POWER10 (1ULL << 61)
#define KVM_PPC_COMPAT_CAP_POWER11 (1ULL << 60)
#define KVM_PPC_COMPAT_BITMASK (KVM_PPC_COMPAT_CAP_POWER9 | \
KVM_PPC_COMPAT_CAP_POWER10 | \
KVM_PPC_COMPAT_CAP_POWER11)
/*
* Values for character and character_mask.
* These are identical to the values used by H_GET_CPU_CHARACTERISTICS.

View File

@ -286,3 +286,46 @@ void __restore_cpu_power10(void)
init_HFSCR();
init_PMU_HV();
}
void __setup_cpu_power12(unsigned long offset, struct cpu_spec *t)
{
init_FSCR_power10();
init_PMU();
init_PMU_ISA31();
if (!init_hvmode_206(t))
return;
mtspr(SPRN_PSSCR, 0);
mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
init_HFSCR();
init_PMU_HV();
}
void __restore_cpu_power12(void)
{
u64 msr;
init_FSCR_power10();
init_PMU();
init_PMU_ISA31();
msr = mfmsr();
if (!(msr & MSR_HV))
return;
mtspr(SPRN_PSSCR, 0);
mtspr(SPRN_LPID, 0);
mtspr(SPRN_PID, 0);
mtspr(SPRN_AMOR, ~0);
mtspr(SPRN_PCR, PCR_MASK);
init_LPCR_ISA300((mfspr(SPRN_LPCR) | LPCR_PECEDH | LPCR_PECE_HVEE |\
LPCR_HVICE | LPCR_HEIC) & ~(LPCR_UPRT | LPCR_HR), 0);
init_HFSCR();
init_PMU_HV();
}

View File

@ -63,6 +63,11 @@
#define COMMON_USER_POWER11 COMMON_USER_POWER10
#define COMMON_USER2_POWER11 COMMON_USER2_POWER10
#define COMMON_USER_POWER12 COMMON_USER_POWER10
#define COMMON_USER2_POWER12 (COMMON_USER2_POWER10 | \
PPC_FEATURE2_ARCH_3_2)
static struct cpu_spec cpu_specs[] __initdata = {
{ /* PPC970 */
.pvr_mask = 0xffff0000,
@ -298,6 +303,20 @@ static struct cpu_spec cpu_specs[] __initdata = {
.cpu_restore = __restore_cpu_power10,
.platform = "power11",
},
{ /* 3.2-compliant processor, i.e. Power12 "architected" mode */
.pvr_mask = 0xffffffff,
.pvr_value = 0x0f000008,
.cpu_name = "Power12 (architected)",
.cpu_features = CPU_FTRS_POWER12,
.cpu_user_features = COMMON_USER_POWER12,
.cpu_user_features2 = COMMON_USER2_POWER12,
.mmu_features = MMU_FTRS_POWER12,
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power12,
.cpu_restore = __restore_cpu_power12,
.platform = "power12",
},
{ /* Power7 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x003f0000,
@ -485,6 +504,23 @@ static struct cpu_spec cpu_specs[] __initdata = {
.machine_check_early = __machine_check_early_realmode_p10,
.platform = "power11",
},
{ /* Power12 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00830000,
.cpu_name = "Power12 (raw)",
.cpu_features = CPU_FTRS_POWER12,
.cpu_user_features = COMMON_USER_POWER12,
.cpu_user_features2 = COMMON_USER2_POWER12,
.mmu_features = MMU_FTRS_POWER12,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
.pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_power12,
.cpu_restore = __restore_cpu_power12,
.machine_check_early = __machine_check_early_realmode_p10,
.platform = "power12",
},
{ /* Cell Broadband Engine */
.pvr_mask = 0xffff0000,
.pvr_value = 0x00700000,

View File

@ -26,6 +26,7 @@
/* Device-tree visible constants follow */
#define ISA_V3_0B 3000
#define ISA_V3_1 3100
#define ISA_V3_2 3200
#define USABLE_PR (1U << 0)
#define USABLE_OS (1U << 1)
@ -90,8 +91,6 @@ static void __restore_cpu_cpufeatures(void)
init_pmu_registers();
}
static char dt_cpu_name[64];
static struct cpu_spec __initdata base_cpu_spec = {
.cpu_name = NULL,
.cpu_features = CPU_FTRS_DT_CPU_BASE,
@ -466,6 +465,35 @@ static int __init feat_enable_mce_power11(struct dt_cpu_feature *f)
return 1;
}
static void init_pmu_power12(void)
{
init_pmu_power10();
}
static int __init feat_enable_pmu_power12(struct dt_cpu_feature *f)
{
hfscr_pmu_enable();
init_pmu_power12();
init_pmu_registers = init_pmu_power12;
cur_cpu_spec->cpu_features |= CPU_FTR_MMCRA;
cur_cpu_spec->cpu_user_features |= PPC_FEATURE_PSERIES_PERFMON_COMPAT;
cur_cpu_spec->num_pmcs = 6;
cur_cpu_spec->pmc_type = PPC_PMC_IBM;
return 1;
}
static int __init feat_enable_mce_power12(struct dt_cpu_feature *f)
{
cur_cpu_spec->platform = "power12";
cur_cpu_spec->machine_check_early = __machine_check_early_realmode_p10;
return 1;
}
static int __init feat_enable_tm(struct dt_cpu_feature *f)
{
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@ -657,9 +685,11 @@ static struct dt_cpu_feature_match __initdata
{"machine-check-power9", feat_enable_mce_power9, 0},
{"machine-check-power10", feat_enable_mce_power10, 0},
{"machine-check-power11", feat_enable_mce_power11, 0},
{"machine-check-power12", feat_enable_mce_power12, 0},
{"performance-monitor-power9", feat_enable_pmu_power9, 0},
{"performance-monitor-power10", feat_enable_pmu_power10, 0},
{"performance-monitor-power11", feat_enable_pmu_power10, 0},
{"performance-monitor-power12", feat_enable_pmu_power12, 0},
{"event-based-branch-v3", feat_enable, 0},
{"random-number-generator", feat_enable, 0},
{"system-call-vectored", feat_disable, 0},
@ -714,6 +744,11 @@ static void __init cpufeatures_setup_start(u32 isa)
if (PVR_VER(mfspr(SPRN_PVR)) >= PVR_POWER11)
cur_cpu_spec->cpu_features |= CPU_FTR_P11_PVR;
}
if (isa >= ISA_V3_2) {
cur_cpu_spec->cpu_features |= CPU_FTR_ARCH_32;
cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_ARCH_3_2;
}
}
static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f)
@ -1078,6 +1113,7 @@ static int __init count_cpufeatures_subnodes(unsigned long node,
static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
*uname, int depth, void *data)
{
static char dt_cpu_name[64];
const __be32 *prop;
int count, i;
u32 isa;
@ -1115,8 +1151,8 @@ static int __init dt_cpu_ftrs_scan_callback(unsigned long node, const char
}
prop = of_get_flat_dt_prop(node, "display-name", NULL);
if (prop && strlen((char *)prop) != 0) {
strscpy(dt_cpu_name, (char *)prop, sizeof(dt_cpu_name));
if (prop && *(char *)prop != 0) {
strscpy(dt_cpu_name, (char *)prop);
cur_cpu_spec->cpu_name = dt_cpu_name;
}

View File

@ -713,14 +713,18 @@ p_end: .8byte _end - copy_to_here
_GLOBAL(copy_and_flush)
addi r5,r5,-8
addi r6,r6,-8
4: li r0,8 /* Use the smallest common */
/* denominator cache line */
/* size. This results in */
/* extra cache line flushes */
/* but operation is correct. */
/* Can't get cache line size */
/* from NACA as it is being */
/* moved too. */
4: li r0,8 /* r0 is the number of 8-byte words */
/* to copy per cache sync iteration. */
/* 8 words * 8 bytes = 64 bytes. 64B is */
/* the current default cache line size. */
/* This is a loop count, not a byte */
/* count. Increasing it may skip */
/* dcbst/icbi for lines in between and */
/* leave stale instructions in icache. */
/* This results in extra cache line */
/* flushes but operation is correct. */
/* Can't get cache line size from NACA */
/* as it is being moved too. */
mtctr r0 /* put # words/line in ctr */
3: addi r6,r6,8 /* copy a cache line */

View File

@ -217,8 +217,12 @@ static __always_inline void call_do_softirq(const void *sp)
[sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE),
[callee] "i" (__do_softirq)
: // Clobbers
"lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6",
"cr7", "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
"lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", "cr7", "r0",
/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */
#ifdef CONFIG_PPC_KERNEL_PCREL
"r2",
#endif
"r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
"r11", "r12"
);
}
@ -275,8 +279,12 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp)
[sp] "b" (sp), [offset] "i" (THREAD_SIZE - STACK_FRAME_MIN_SIZE),
[callee] "i" (__do_irq)
: // Clobbers
"lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6",
"cr7", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
"lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6", "cr7", "r0",
/* r2 may be clobbered by the callee when using PCREL mode in the ELFv2 ABI. */
#ifdef CONFIG_PPC_KERNEL_PCREL
"r2",
#endif
"r4", "r5", "r6", "r7", "r8", "r9", "r10",
"r11", "r12"
);
}

View File

@ -86,6 +86,12 @@
*/
#define ADDR(x) (u32)(unsigned long)(x)
/*
* Current Power system firmware caps the PVR list array size at 16 entries
* during CAS (Client Architecture Support) negotiation.
*/
#define CAS_MAX_PVR_ENTRIES 16
#ifdef CONFIG_PPC64
#define OF_WORKAROUNDS 0
#else
@ -947,7 +953,7 @@ struct option_vector7 {
} __packed;
struct ibm_arch_vec {
struct { __be32 mask, val; } pvrs[16];
struct { __be32 mask, val; } pvrs[18];
u8 num_vectors;
@ -979,6 +985,10 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = {
.mask = cpu_to_be32(0xfffe0000), /* POWER5/POWER5+ */
.val = cpu_to_be32(0x003a0000),
},
{
.mask = cpu_to_be32(0xffffffff), /* all 2.04-compliant and earlier */
.val = cpu_to_be32(0x0f000001),
},
{
.mask = cpu_to_be32(0xffff0000), /* POWER6 */
.val = cpu_to_be32(0x003e0000),
@ -1011,6 +1021,14 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = {
.mask = cpu_to_be32(0xffff0000), /* POWER11 */
.val = cpu_to_be32(0x00820000),
},
{
.mask = cpu_to_be32(0xffff0000), /* POWER12 */
.val = cpu_to_be32(0x00830000),
},
{
.mask = cpu_to_be32(0xffffffff), /* all 3.2-compliant */
.val = cpu_to_be32(0x0f000008),
},
{
.mask = cpu_to_be32(0xffffffff), /* P11 compliant */
.val = cpu_to_be32(0x0f000007),
@ -1032,13 +1050,9 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = {
.val = cpu_to_be32(0x0f000003),
},
{
.mask = cpu_to_be32(0xffffffff), /* all 2.05-compliant */
.mask = cpu_to_be32(0xfffffffd), /* all 2.05-compliant */
.val = cpu_to_be32(0x0f000002),
},
{
.mask = cpu_to_be32(0xfffffffe), /* all 2.04-compliant and earlier */
.val = cpu_to_be32(0x0f000001),
},
},
.num_vectors = NUM_VECTORS(6),
@ -1048,7 +1062,7 @@ static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = {
.byte1 = 0,
.arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07,
.arch_versions3 = OV1_PPC_3_00 | OV1_PPC_3_1,
.arch_versions3 = OV1_PPC_3_00 | OV1_PPC_3_1 | OV1_PPC_3_2,
},
.vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)),
@ -1403,6 +1417,22 @@ static void __init prom_send_capabilities(void)
ihandle root;
prom_arg_t ret;
u32 cores;
int start_index = 0;
/*
* Ensure that when running on Power11 or below hardware, the number
* of PVR entries passed during CAS negotiation does not exceed the
* firmware-imposed limit of 16.
*
* Compute the start_index to skip the oldest leading pvrs[] entries
* when running on Power11 or below hardware, so that the pointer
* passed to ibm,client-architecture-support points to
* ibm_architecture_vec.pvrs[start_index], presenting exactly 16
* entries to firmware.
*/
if ((ARRAY_SIZE(ibm_architecture_vec_template.pvrs) > CAS_MAX_PVR_ENTRIES) &&
(PVR_VER(mfspr(SPRN_PVR)) <= PVR_POWER11))
start_index = ARRAY_SIZE(ibm_architecture_vec_template.pvrs) - CAS_MAX_PVR_ENTRIES;
/* Check ibm,arch-vec-5-platform-support and fixup vec5 if required */
prom_check_platform_support();
@ -1427,7 +1457,7 @@ static void __init prom_send_capabilities(void)
if (call_prom_ret("call-method", 3, 2, &ret,
ADDR("ibm,client-architecture-support"),
root,
ADDR(&ibm_architecture_vec)) == 0) {
ADDR(&ibm_architecture_vec.pvrs[start_index])) == 0) {
/* the call exists... */
if (ret)
prom_printf("\nWARNING: ibm,client-architecture"

View File

@ -394,30 +394,23 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *off)
{
struct rtas_manage_flash_t *const args_buf = &rtas_manage_flash_data;
static const char reject_str[] = "0";
static const char commit_str[] = "1";
char stkbuf[10];
int op;
unsigned int op;
char cmd;
guard(mutex)(&rtas_manage_flash_mutex);
if ((args_buf->status == MANAGE_AUTH) || (count == 0))
return count;
op = -1;
if (buf) {
if (count > 9) count = 9;
if (copy_from_user (stkbuf, buf, count))
return -EFAULT;
if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0)
op = RTAS_REJECT_TMP_IMG;
else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0)
op = RTAS_COMMIT_TMP_IMG;
}
if (op == -1) { /* buf is empty, or contains invalid string */
if (get_user(cmd, buf))
return -EFAULT;
if (cmd == '0')
op = RTAS_REJECT_TMP_IMG;
else if (cmd == '1')
op = RTAS_COMMIT_TMP_IMG;
else
return -EINVAL;
}
manage_flash(args_buf, op);
return count;

View File

@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
@ -160,25 +161,17 @@ static void printk_log_rtas(char *buf, int len)
static int log_rtas_len(char * buf)
{
int len;
size_t len;
struct rtas_error_log *err;
uint32_t extended_log_length;
u32 extended_log_length;
/* rtas fixed header */
len = 8;
err = (struct rtas_error_log *)buf;
extended_log_length = rtas_error_extended_log_length(err);
if (rtas_error_extended(err) && extended_log_length) {
/* extended header */
len += extended_log_length;
}
extended_log_length = rtas_error_extended(err) ? rtas_error_extended_log_length(err) : 0;
len = struct_size(err, buffer, extended_log_length);
if (rtas_error_log_max == 0)
rtas_error_log_max = rtas_get_error_log_max();
if (len > rtas_error_log_max)
len = rtas_error_log_max;
len = min(len, rtas_error_log_max);
return len;
}

View File

@ -304,6 +304,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
break;
case 0x004e: /* POWER9 bits 12-15 give chip type */
case 0x0080: /* POWER10 bit 12 gives SMT8/4 */
case 0x0083: /* POWER12 bit 12 gives SMT8/4 */
maj = (pvr >> 8) & 0x0F;
min = pvr & 0xFF;
break;

View File

@ -289,6 +289,9 @@ void smp_muxed_ipi_set_message(int cpu, int msg)
void smp_muxed_ipi_message_pass(int cpu, int msg)
{
if (!smp_ops->cause_ipi)
return;
smp_muxed_ipi_set_message(cpu, msg);
/*

View File

@ -22,6 +22,9 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
add_random_kstack_offset();
r0 = syscall_enter_from_user_mode(regs, r0);
if (unlikely(test_and_clear_thread_flag(TIF_SYSCALL_RET)))
return syscall_get_error(current, regs);
if (unlikely(r0 >= NR_syscalls)) {
if (unlikely(trap_is_unsupported_scv(regs))) {
/* Unsupported scv vector */

View File

@ -502,7 +502,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
ret = get_crash_memory_ranges(&cmem);
if (ret) {
pr_err("Failed to get crash mem range\n");
return;
goto out;
}
/*

View File

@ -36,25 +36,19 @@
char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
unsigned long cmdline_len)
{
int elfcorehdr_strlen;
char *cmdline_ptr;
cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
cmdline_ptr = kmalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
if (!cmdline_ptr)
return NULL;
elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ",
image->elf_load_addr);
if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) {
pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");
if (snprintf(cmdline_ptr, COMMAND_LINE_SIZE, "elfcorehdr=0x%lx %s",
image->elf_load_addr, cmdline_len ? cmdline : "") >= COMMAND_LINE_SIZE) {
pr_err("Prepending elfcorehdr=<addr> exceeds cmdline size\n");
kfree(cmdline_ptr);
return NULL;
}
memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len);
// Ensure it's nul terminated
cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0';
return cmdline_ptr;
}

View File

@ -664,7 +664,7 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *
extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size();
/* Consider extra space for reserved memory ranges if any */
if (rmem->nr_ranges > 0)
if (rmem && rmem->nr_ranges > 0)
extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges;
return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes);

View File

@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/minmax.h>
#include <linux/crash_core.h>
#include <asm/sections.h>
#include <asm/kexec_ranges.h>
@ -105,19 +106,16 @@ static void __merge_memory_ranges(struct crash_mem *mem_rngs)
struct range *ranges;
int i, idx;
if (!mem_rngs)
if (!mem_rngs || mem_rngs->nr_ranges <= 1)
return;
idx = 0;
ranges = &(mem_rngs->ranges[0]);
ranges = mem_rngs->ranges;
for (i = 1; i < mem_rngs->nr_ranges; i++) {
if (ranges[i].start <= (ranges[i-1].end + 1))
ranges[idx].end = ranges[i].end;
if (ranges[i].start <= (ranges[idx].end + 1))
ranges[idx].end = max(ranges[idx].end, ranges[i].end);
else {
idx++;
if (i == idx)
continue;
ranges[idx] = ranges[i];
}
}

View File

@ -22,6 +22,7 @@ config KVM
select KVM_COMMON
select KVM_VFIO
select HAVE_KVM_IRQ_BYPASS
select VIRT_XFER_TO_GUEST_WORK
config KVM_BOOK3S_HANDLER
bool

View File

@ -388,7 +388,7 @@ static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr)
}
/* Dummy value used in computing PCR value below */
#define PCR_ARCH_31 (PCR_ARCH_300 << 1)
#define PCR_ARCH_32 (PCR_ARCH_31 << 1)
static inline unsigned long map_pcr_to_cap(unsigned long pcr)
{
@ -417,7 +417,9 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
struct kvmppc_vcore *vc = vcpu->arch.vcore;
/* We can (emulate) our own architecture version and anything older */
if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31))
if (cpu_has_feature(CPU_FTR_ARCH_32))
host_pcr_bit = PCR_ARCH_32;
else if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31))
host_pcr_bit = PCR_ARCH_31;
else if (cpu_has_feature(CPU_FTR_ARCH_300))
host_pcr_bit = PCR_ARCH_300;
@ -446,9 +448,24 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
guest_pcr_bit = PCR_ARCH_300;
break;
case PVR_ARCH_31:
case PVR_ARCH_31_P11:
guest_pcr_bit = PCR_ARCH_31;
break;
case PVR_ARCH_31_P11:
/*
* Need to check this for ISA 3.1, as Power10 and
* Power11 share the same PCR. For any subsequent ISA
* versions, this will be taken care of by the guest vs
* host PCR comparison below.
*/
if (!cpu_has_feature(CPU_FTR_P11_PVR)) {
arch_compat = PVR_ARCH_INVALID;
goto out;
}
guest_pcr_bit = PCR_ARCH_31;
break;
case PVR_ARCH_32:
guest_pcr_bit = PCR_ARCH_32;
break;
default:
return -EINVAL;
}
@ -469,6 +486,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
return -EINVAL;
}
out:
spin_lock(&vc->lock);
vc->arch_compat = arch_compat;
kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LOGICAL_PVR);
@ -479,7 +497,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
vc->pcr = (host_pcr_bit - guest_pcr_bit) | PCR_MASK;
spin_unlock(&vc->lock);
return 0;
return kvmppc_sanity_check(vcpu);
}
static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
@ -3853,7 +3871,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
*/
local_irq_disable();
hard_irq_disable();
if (lazy_irq_pending() || need_resched() ||
xfer_to_guest_mode_prepare();
if (lazy_irq_pending() || xfer_to_guest_mode_work_pending() ||
recheck_signals_and_mmu(&core_info)) {
local_irq_enable();
vc->vcore_state = VCORE_INACTIVE;
@ -4824,10 +4843,16 @@ static int kvmppc_run_vcpu(struct kvm_vcpu *vcpu)
vc->runner = vcpu;
if (n_ceded == vc->n_runnable) {
kvmppc_vcore_blocked(vc);
} else if (need_resched()) {
} else if (__xfer_to_guest_mode_work_pending()) {
kvmppc_vcore_preempt(vc);
/* Let something else run */
cond_resched_lock(&vc->lock);
/*
* Let something else run. The raw helper is used as
* signal exits are accounted by this path already;
* it may schedule(), so drop the vcore lock.
*/
spin_unlock(&vc->lock);
xfer_to_guest_mode_handle_work();
spin_lock(&vc->lock);
if (vc->vcore_state == VCORE_PREEMPT)
kvmppc_vcore_end_preempt(vc);
} else {
@ -4895,12 +4920,16 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
run->exit_reason = KVM_EXIT_FAIL_ENTRY;
run->fail_entry.hardware_entry_failure_reason = 0;
vcpu->arch.ret = r;
return r;
goto done;
}
}
if (need_resched())
cond_resched();
r = kvm_xfer_to_guest_mode_handle_work(vcpu);
if (r) {
/* -EINTR: signal pending, exit to userspace (KVM_EXIT_INTR) */
vcpu->arch.ret = r;
goto done;
}
kvmppc_update_vpas(vcpu);
@ -4914,9 +4943,13 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
vcpu->arch.state = KVMPPC_VCPU_RUNNABLE;
if (signal_pending(current))
goto sigpend;
if (need_resched() || !kvm->arch.mmu_ready)
xfer_to_guest_mode_prepare();
/*
* IRQs are disabled here, so on pending work bail to the outer loop,
* which handles it via kvm_xfer_to_guest_mode_handle_work() above.
*/
if (xfer_to_guest_mode_work_pending() || !kvm->arch.mmu_ready)
goto out;
vcpu->cpu = pcpu;
@ -5068,10 +5101,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
return vcpu->arch.ret;
sigpend:
vcpu->stat.signal_exits++;
run->exit_reason = KVM_EXIT_INTR;
vcpu->arch.ret = -EINTR;
out:
vcpu->cpu = -1;
vcpu->arch.thread_cpu = -1;
@ -6510,6 +6539,61 @@ static bool kvmppc_hash_v3_possible(void)
return true;
}
static int kvmppc_map_compat_capabilities(u32 cpu_version,
unsigned long *capabilities)
{
switch (cpu_version) {
case PVR_ARCH_31_P11:
*capabilities |= KVM_PPC_COMPAT_CAP_POWER11;
fallthrough;
case PVR_ARCH_31:
*capabilities |= KVM_PPC_COMPAT_CAP_POWER10;
fallthrough;
case PVR_ARCH_300:
*capabilities |= KVM_PPC_COMPAT_CAP_POWER9;
break;
default:
return -EINVAL;
}
return 0;
}
static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
{
struct device_node *np;
unsigned long capabilities = 0;
long rc = -EINVAL;
u32 cpu_version = 0;
if (kvmhv_on_pseries()) {
if (kvmhv_is_nestedv2()) {
WARN_ON_ONCE(!nested_capabilities);
capabilities = nested_capabilities;
rc = 0;
} else {
for_each_node_by_type(np, "cpu") {
if (!of_property_read_u32(np, "cpu-version",
&cpu_version)) {
of_node_put(np);
break;
}
}
if (!cpu_version)
return -EINVAL;
rc = kvmppc_map_compat_capabilities(cpu_version,
&capabilities);
}
}
if (rc < 0)
return rc;
host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
return rc;
}
static struct kvmppc_ops kvm_ops_hv = {
.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@ -6552,6 +6636,7 @@ static struct kvmppc_ops kvm_ops_hv = {
.hash_v3_possible = kvmppc_hash_v3_possible,
.create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv,
.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,
.get_compat_caps = kvmppc_get_compat_caps,
};
static int kvm_init_subcore_bitmap(void)

View File

@ -598,7 +598,7 @@ static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu)
if (do_div(nr_jiffies, tb_ticks_per_jiffy))
nr_jiffies++;
return min_t(unsigned long long, nr_jiffies, TIMER_NEXT_MAX_DELTA);
return min(nr_jiffies, TIMER_NEXT_MAX_DELTA);
}
static void arm_next_watchdog(struct kvm_vcpu *vcpu)
@ -722,6 +722,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
if (vcpu->arch.shared->msr & MSR_WE) {
local_irq_enable();
kvm_vcpu_halt(vcpu);
local_irq_disable();
hard_irq_disable();
kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);

View File

@ -1833,7 +1833,8 @@ int kvm_set_routing_entry(struct kvm *kvm,
e->set = mpic_set_irq;
e->irqchip.irqchip = ue->u.irqchip.irqchip;
e->irqchip.pin = ue->u.irqchip.pin;
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS ||
e->irqchip.irqchip >= KVM_NR_IRQCHIPS)
goto out;
break;
case KVM_IRQ_ROUTING_MSI:

View File

@ -81,21 +81,39 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
int r;
WARN_ON(irqs_disabled());
/*
* local_irq_disable() first: on 32-bit, hard_irq_disable() alone is a
* raw MSR[EE] clear that bypasses the lockdep/irq-tracing state, and
* the xfer_to_guest_mode helpers assert IRQs are seen as disabled.
*/
local_irq_disable();
hard_irq_disable();
while (true) {
if (need_resched()) {
local_irq_enable();
cond_resched();
hard_irq_disable();
continue;
}
xfer_to_guest_mode_prepare();
if (signal_pending(current)) {
kvmppc_account_exit(vcpu, SIGNAL_EXITS);
vcpu->run->exit_reason = KVM_EXIT_INTR;
r = -EINTR;
break;
if (xfer_to_guest_mode_work_pending()) {
/*
* The helper must run with IRQs enabled and may
* schedule(). On a pending signal it returns -EINTR
* with run->exit_reason and vcpu->stat.signal_exits
* already set, so just return to userspace.
*/
local_irq_enable();
r = kvm_xfer_to_guest_mode_handle_work(vcpu);
local_irq_disable();
hard_irq_disable();
if (r) {
/*
* The generic helper does not set the exit
* type; record it for the E500
* CONFIG_KVM_EXIT_TIMING histogram (a no-op
* otherwise).
*/
kvmppc_set_exit_type(vcpu, SIGNAL_EXITS);
break;
}
continue;
}
vcpu->mode = IN_GUEST_MODE;
@ -116,6 +134,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
local_irq_enable();
trace_kvm_check_requests(vcpu);
r = kvmppc_core_check_requests(vcpu);
local_irq_disable();
hard_irq_disable();
if (r > 0)
continue;
@ -258,6 +277,12 @@ int kvmppc_sanity_check(struct kvm_vcpu *vcpu)
if (!vcpu->arch.pvr)
goto out;
#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
if (vcpu->arch.vcore &&
vcpu->arch.vcore->arch_compat == PVR_ARCH_INVALID)
goto out;
#endif
/* PAPR only works with book3s_64 */
if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled)
goto out;
@ -635,9 +660,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
* implementations just count online CPUs.
*/
if (hv_enabled)
r = min_t(unsigned int, num_present_cpus(), KVM_MAX_VCPUS);
r = min(num_present_cpus(), KVM_MAX_VCPUS);
else
r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS);
r = min(num_online_cpus(), KVM_MAX_VCPUS);
break;
case KVM_CAP_MAX_VCPUS:
r = KVM_MAX_VCPUS;
@ -697,6 +722,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
}
}
break;
#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
case KVM_CAP_PPC_COMPAT_CAPS:
r = 0;
if (hv_enabled && kvmhv_on_pseries())
r = 1;
break;
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
default:
r = 0;
break;
@ -2463,6 +2495,77 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = kvm->arch.kvm_ops->svm_off(kvm);
break;
}
case KVM_PPC_GET_COMPAT_CAPS: {
struct kvm_ppc_compat_caps host_caps = {};
u64 usize;
/*
* Read the size field first to drive copy_struct_from_user.
* size must be the first field of the struct.
*/
r = -EFAULT;
if (get_user(usize, (__u64 __user *)argp))
goto out;
r = -E2BIG;
if (unlikely(usize > PAGE_SIZE))
goto out;
/*
* Enforce a minimum: reject buffers smaller than the initial
* struct version (VER0). This allows old userspace compiled
* against the original struct to still work on a newer kernel
* that has grown the struct with appended fields.
*/
r = -EINVAL;
if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
goto out;
/*
* copy_struct_from_user() handles forward/backward compat:
* usize == ksize: verbatim copy
* usize < ksize: zero-pad trailing (old userspace, new kernel)
* usize > ksize: succeed iff trailing bytes are zero, else -E2BIG
*/
r = copy_struct_from_user(&host_caps, sizeof(host_caps),
argp, usize);
if (r) {
/*
* New userspace with a larger struct called an older
* kernel. Write back ksize in host_caps.size so
* userspace knows which older struct to retry with,
* then fail with -E2BIG.
*/
if (r == -E2BIG)
if (put_user((__u64)sizeof(host_caps),
(__u64 __user *)argp))
r = -EFAULT;
goto out;
}
/* Reserved fields must be zero */
r = -EINVAL;
if (host_caps.flags)
goto out;
r = -ENOTTY;
if (!kvm->arch.kvm_ops->get_compat_caps)
goto out;
r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
if (r)
goto out;
/*
* Report the number of bytes actually populated by the kernel,
* not usize: if new userspace passed a larger struct with zero
* trailing bytes, we only filled sizeof(host_caps) bytes.
*/
host_caps.size = min_t(u64, usize, sizeof(host_caps));
r = copy_struct_to_user(argp, usize, &host_caps,
sizeof(host_caps), NULL);
break;
}
default: {
struct kvm *kvm = filp->private_data;
r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);

View File

@ -184,9 +184,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
va |= ssize << 8;
sllp = get_sllp_encoding(apsize);
va |= sllp << 5;
asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 0), %1)
: : "r" (va), "i" (CPU_FTR_ARCH_206)
: "memory");
if (cpu_has_feature(CPU_FTR_ARCH_32)) {
asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : : "r"(va), "r"(0) : "memory");
} else {
asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 0), %1)
: : "r" (va), "i" (CPU_FTR_ARCH_206)
: "memory");
}
break;
default:
/* We need 14 to 14 + i bits of va */
@ -203,9 +208,14 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
*/
va |= (vpn & 0xfe);
va |= 1; /* L */
asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 1), %1)
: : "r" (va), "i" (CPU_FTR_ARCH_206)
: "memory");
if (cpu_has_feature(CPU_FTR_ARCH_32)) {
asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : : "r"(va), "r"(0) : "memory");
} else {
asm volatile(ASM_FTR_IFSET("tlbiel %0", PPC_TLBIEL_v205(%0, 1), %1)
: : "r" (va), "i" (CPU_FTR_ARCH_206)
: "memory");
}
break;
}
trace_tlbie(0, 1, va, 0, 0, 0, 0);

View File

@ -628,7 +628,9 @@ void __init mmu_early_init_devtree(void)
of_scan_flat_dt(dt_scan_mmu_pid_width, NULL);
if (hvmode && !mmu_lpid_bits) {
if (early_cpu_has_feature(CPU_FTR_ARCH_207S))
if (early_cpu_has_feature(CPU_FTR_ARCH_32))
mmu_lpid_bits = 16; /* POWER12 */
else if (early_cpu_has_feature(CPU_FTR_ARCH_207S))
mmu_lpid_bits = 12; /* POWER8-10 */
else
mmu_lpid_bits = 10; /* POWER7 */

View File

@ -471,8 +471,6 @@ static int bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 f
int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func)
{
unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0;
long __maybe_unused reladdr;
int ret;
/* bpf to bpf call, func is not known in the initial pass. Emit 5 nops as a placeholder */
if (!func) {
@ -487,6 +485,8 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *
}
#ifdef CONFIG_PPC_KERNEL_PCREL
long reladdr;
reladdr = func_addr - local_paca->kernelbase;
/*
@ -525,7 +525,7 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *
EMIT(PPC_RAW_BCTRL());
#else
if (core_kernel_text(func_addr)) {
ret = bpf_jit_emit_func_call(image, ctx, func_addr, _R12);
int ret = bpf_jit_emit_func_call(image, ctx, func_addr, _R12);
if (ret)
return ret;
} else {

View File

@ -36,7 +36,7 @@ SYM_FUNC_START(arch_bpf_timed_may_goto)
* BPF_REG_FP is r31; BPF_REG_AX is r12 (stack offset in bytes).
*/
add r3, r31, r12
bl bpf_check_timed_may_goto
bl CFUNC(bpf_check_timed_may_goto)
/* Put return value back into AX */
mr r12, r3

View File

@ -7,7 +7,7 @@ obj-$(CONFIG_PPC_PERF_CTRS) += core-book3s.o
obj64-$(CONFIG_PPC_PERF_CTRS) += ppc970-pmu.o power5-pmu.o \
power5+-pmu.o power6-pmu.o power7-pmu.o \
isa207-common.o power8-pmu.o power9-pmu.o \
generic-compat-pmu.o power10-pmu.o bhrb.o
generic-compat-pmu.o power10-pmu.o bhrb.o power12-pmu.o
obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o
obj-$(CONFIG_PPC_POWERNV) += imc-pmu.o

View File

@ -2613,6 +2613,8 @@ static int __init init_ppc64_pmu(void)
return 0;
else if (!init_power11_pmu())
return 0;
else if (!init_power12_pmu())
return 0;
else if (!init_ppc970_pmu())
return 0;
else

View File

@ -11,4 +11,5 @@ int __init init_power8_pmu(void);
int __init init_power9_pmu(void);
int __init init_power10_pmu(void);
int __init init_power11_pmu(void);
int __init init_power12_pmu(void);
int __init init_generic_compat_pmu(void);

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Performance counter support for POWER12 processors.
*
* Copyright 2026 Athira Rajeev, IBM Corporation.
*/
/*
* Power12 event codes.
*/
EVENT(PM_CYC, 0x600f4);
EVENT(PM_DISP_STALL_CYC, 0x100f8);
EVENT(PM_EXEC_STALL, 0x30008);
EVENT(PM_INST_CMPL, 0x500fa);
EVENT(PM_BR_CMPL, 0x4d05e);
EVENT(PM_BR_MPRED_CMPL, 0x400f6);
EVENT(PM_BR_FIN, 0x10068);
EVENT(PM_MPRED_BR_FIN, 0x27098);
EVENT(PM_LD_DEMAND_MISS_L1_FIN, 0x400f0);
/* All L1 D cache load references counted at finish, gated by reject */
EVENT(PM_LD_REF_L1, 0x100fc);
/* Load Missed L1 */
EVENT(PM_LD_MISS_L1, 0x3e054);
/* Store Missed L1 */
EVENT(PM_ST_MISS_L1, 0x300f0);
/* L1 cache data prefetches */
EVENT(PM_LD_PREFETCH_CACHE_LINE_MISS, 0x1002c);
/* Demand iCache Miss */
EVENT(PM_L1_ICACHE_MISS, 0x200fc);
/* Instruction fetches from L1 */
EVENT(PM_INST_FROM_L1, 0x04080);
/* Instruction Demand sectors writtent into IL1 */
EVENT(PM_INST_FROM_L1MISS, 0x03F00000001C040);
/* Instruction prefetch written into IL1 */
EVENT(PM_IC_PREF_REQ, 0x040a0);
/* The data cache was reloaded from local core's L3 due to a demand load */
EVENT(PM_DATA_FROM_L3, 0x10340000003C040);
/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
EVENT(PM_DATA_FROM_L3MISS, 0x300fe);
/* All successful D-side store dispatches for this thread */
EVENT(PM_L2_ST, 0x010000046080);
/* All successful D-side store dispatches for this thread that were L2 Miss */
EVENT(PM_L2_ST_MISS, 0x26880);
/* Total HW L3 prefetches(Load+store) */
EVENT(PM_L3_PF_MISS_L3, 0x100000016080);
/* Data PTEG reload */
EVENT(PM_DTLB_MISS, 0x300fc);
/* ITLB Reloaded */
EVENT(PM_ITLB_MISS, 0x400fc);
EVENT(PM_CYC_ALT, 0x0001e);
EVENT(PM_INST_CMPL_ALT, 0x00002);
/*
* Memory Access Events
*
* Primary PMU event used here is PM_MRK_INST_CMPL (0x401e0)
* To enable capturing of memory profiling, these MMCRA bits
* needs to be programmed and corresponding raw event format
* encoding.
*
* MMCRA bits encoding needed are
* SM (Sampling Mode)
* EM (Eligibility for Random Sampling)
* TECE (Threshold Event Counter Event)
* TS (Threshold Start Event)
* TE (Threshold End Event)
*
* Corresponding Raw Encoding bits:
* sample [EM,SM]
* thresh_sel (TECE)
* thresh start (TS)
* thresh end (TE)
*/
EVENT(MEM_LOADS, 0x35340401e0);
EVENT(MEM_STORES, 0x353c0401e0);

View File

@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Performance counter support for Power12 processors.
*
* Copyright 2026 Athira Rajeev, IBM Corporation.
*/
#define pr_fmt(fmt) "power12-pmu: " fmt
#include "isa207-common.h"
/*
* Raw event encoding for Power12:
*
* 60 56 52 48 44 40 36 32
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
* | | [ ] [ src_match ] [ src_mask ] | [ ] [ l2l3_sel ] [ thresh_ctl ]
* | | | | | |
* | | *- IFM (Linux) | | thresh start/stop -*
* | *- BHRB (Linux) | src_sel
* *- EBB (Linux) *invert_bit
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
* [ ] [ sample ] [ ] [ ] [ pmc ] [unit ] [ ] | m [ pmcxsel ]
* | | | | | | |
* | | | | | | *- mark
* | | | *- L1/L2/L3 cache_sel | |*-radix_scope_qual
* | | sdar_mode |
* | *- sampling mode for marked events *- combine
* |
* *- thresh_sel
*
* Below uses IBM bit numbering.
*
* MMCR1[x:y] = unit (PMCxUNIT)
* MMCR1[24] = pmc1combine[0]
* MMCR1[25] = pmc1combine[1]
* MMCR1[26] = pmc2combine[0]
* MMCR1[27] = pmc2combine[1]
* MMCR1[28] = pmc3combine[0]
* MMCR1[29] = pmc3combine[1]
* MMCR1[30] = pmc4combine[0]
* MMCR1[31] = pmc4combine[1]
*
* if pmc == 3 and unit == 0 and pmcxsel[0:6] == 0b0101011
* MMCR1[20:27] = thresh_ctl
* else if pmc == 4 and unit == 0xf and pmcxsel[0:6] == 0b0101001
* MMCR1[20:27] = thresh_ctl
* else
* MMCRA[48:55] = thresh_ctl (THRESH START/END)
*
* if thresh_sel:
* MMCRA[45:47] = thresh_sel
*
* if l2l3_sel:
* MMCR2[56:60] = l2l3_sel[0:4]
*
* MMCR1[16] = cache_sel[0]
* MMCR1[17] = cache_sel[1]
* MMCR1[18] = radix_scope_qual
*
* if mark:
* MMCRA[63] = 1 (SAMPLE_ENABLE)
* MMCRA[57:59] = sample[0:2] (RAND_SAMP_ELIG)
* MMCRA[61:62] = sample[3:4] (RAND_SAMP_MODE)
*
* if EBB and BHRB:
* MMCRA[32:33] = IFM
*
* MMCRA[SDAR_MODE] = sdar_mode[0:1]
*/
/*
* Some power12 event codes.
*/
#define EVENT(_name, _code) enum{_name = _code}
#include "power12-events-list.h"
#undef EVENT
/* MMCRA IFM bits - POWER12 */
#define POWER12_MMCRA_IFM1 0x0000000040000000UL
#define POWER12_MMCRA_IFM2 0x0000000080000000UL
#define POWER12_MMCRA_IFM3 0x00000000C0000000UL
#define POWER12_MMCRA_BHRB_MASK 0x00000000C0000000UL
extern u64 PERF_REG_EXTENDED_MASK;
/* Table of alternatives, sorted by column 0 */
static const unsigned int power12_event_alternatives[][MAX_ALT] = {
{ PM_INST_CMPL_ALT, PM_INST_CMPL },
{ PM_CYC_ALT, PM_CYC },
};
static int power12_get_alternatives(u64 event, unsigned int flags, u64 alt[])
{
int num_alt = 0;
num_alt = isa207_get_alternatives(event, alt,
ARRAY_SIZE(power12_event_alternatives), flags,
power12_event_alternatives);
return num_alt;
}
static int power12_check_attr_config(struct perf_event *ev)
{
u64 val;
u64 event = ev->attr.config;
val = (event >> EVENT_SAMPLE_SHIFT) & EVENT_SAMPLE_MASK;
if (val == 0x10 || isa3XX_check_attr_config(ev))
return -EINVAL;
return 0;
}
GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC);
GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL);
GENERIC_EVENT_ATTR(branch-instructions, PM_BR_FIN);
GENERIC_EVENT_ATTR(branch-misses, PM_MPRED_BR_FIN);
GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, PM_LD_DEMAND_MISS_L1_FIN);
GENERIC_EVENT_ATTR(mem-loads, MEM_LOADS);
GENERIC_EVENT_ATTR(mem-stores, MEM_STORES);
CACHE_EVENT_ATTR(L1-dcache-load-misses, PM_LD_MISS_L1);
CACHE_EVENT_ATTR(L1-dcache-loads, PM_LD_REF_L1);
CACHE_EVENT_ATTR(L1-dcache-prefetches, PM_LD_PREFETCH_CACHE_LINE_MISS);
CACHE_EVENT_ATTR(L1-dcache-store-misses, PM_ST_MISS_L1);
CACHE_EVENT_ATTR(L1-icache-load-misses, PM_L1_ICACHE_MISS);
CACHE_EVENT_ATTR(L1-icache-loads, PM_INST_FROM_L1);
CACHE_EVENT_ATTR(L1-icache-prefetches, PM_IC_PREF_REQ);
CACHE_EVENT_ATTR(LLC-load-misses, PM_DATA_FROM_L3MISS);
CACHE_EVENT_ATTR(LLC-loads, PM_DATA_FROM_L3);
CACHE_EVENT_ATTR(LLC-prefetches, PM_L3_PF_MISS_L3);
CACHE_EVENT_ATTR(LLC-store-misses, PM_L2_ST_MISS);
CACHE_EVENT_ATTR(LLC-stores, PM_L2_ST);
CACHE_EVENT_ATTR(branch-load-misses, PM_BR_MPRED_CMPL);
CACHE_EVENT_ATTR(branch-loads, PM_BR_CMPL);
CACHE_EVENT_ATTR(dTLB-load-misses, PM_DTLB_MISS);
CACHE_EVENT_ATTR(iTLB-load-misses, PM_ITLB_MISS);
static struct attribute *power12_events_attr[] = {
GENERIC_EVENT_PTR(PM_CYC),
GENERIC_EVENT_PTR(PM_INST_CMPL),
GENERIC_EVENT_PTR(PM_BR_FIN),
GENERIC_EVENT_PTR(PM_MPRED_BR_FIN),
GENERIC_EVENT_PTR(PM_LD_REF_L1),
GENERIC_EVENT_PTR(PM_LD_DEMAND_MISS_L1_FIN),
GENERIC_EVENT_PTR(MEM_LOADS),
GENERIC_EVENT_PTR(MEM_STORES),
CACHE_EVENT_PTR(PM_LD_MISS_L1),
CACHE_EVENT_PTR(PM_LD_REF_L1),
CACHE_EVENT_PTR(PM_LD_PREFETCH_CACHE_LINE_MISS),
CACHE_EVENT_PTR(PM_ST_MISS_L1),
CACHE_EVENT_PTR(PM_L1_ICACHE_MISS),
CACHE_EVENT_PTR(PM_INST_FROM_L1),
CACHE_EVENT_PTR(PM_IC_PREF_REQ),
CACHE_EVENT_PTR(PM_DATA_FROM_L3MISS),
CACHE_EVENT_PTR(PM_DATA_FROM_L3),
CACHE_EVENT_PTR(PM_L3_PF_MISS_L3),
CACHE_EVENT_PTR(PM_L2_ST_MISS),
CACHE_EVENT_PTR(PM_L2_ST),
CACHE_EVENT_PTR(PM_BR_MPRED_CMPL),
CACHE_EVENT_PTR(PM_BR_CMPL),
CACHE_EVENT_PTR(PM_DTLB_MISS),
CACHE_EVENT_PTR(PM_ITLB_MISS),
NULL
};
static const struct attribute_group power12_pmu_events_group = {
.name = "events",
.attrs = power12_events_attr,
};
PMU_FORMAT_ATTR(event, "config:0-59");
PMU_FORMAT_ATTR(pmcxsel, "config:0-7");
PMU_FORMAT_ATTR(mark, "config:8");
PMU_FORMAT_ATTR(combine, "config:10-11");
PMU_FORMAT_ATTR(unit, "config:12-15");
PMU_FORMAT_ATTR(pmc, "config:16-19");
PMU_FORMAT_ATTR(cache_sel, "config:20-21");
PMU_FORMAT_ATTR(sdar_mode, "config:22-23");
PMU_FORMAT_ATTR(sample_mode, "config:24-28");
PMU_FORMAT_ATTR(thresh_sel, "config:29-31");
PMU_FORMAT_ATTR(thresh_stop, "config:32-35");
PMU_FORMAT_ATTR(thresh_start, "config:36-39");
PMU_FORMAT_ATTR(l2l3_sel, "config:40-44");
PMU_FORMAT_ATTR(src_sel, "config:45-46");
PMU_FORMAT_ATTR(invert_bit, "config:47");
PMU_FORMAT_ATTR(src_mask, "config:48-53");
PMU_FORMAT_ATTR(src_match, "config:54-59");
PMU_FORMAT_ATTR(radix_scope, "config:9");
PMU_FORMAT_ATTR(thresh_cmp, "config1:0-17");
static struct attribute *power12_pmu_format_attr[] = {
&format_attr_event.attr,
&format_attr_pmcxsel.attr,
&format_attr_mark.attr,
&format_attr_combine.attr,
&format_attr_unit.attr,
&format_attr_pmc.attr,
&format_attr_cache_sel.attr,
&format_attr_sdar_mode.attr,
&format_attr_sample_mode.attr,
&format_attr_thresh_sel.attr,
&format_attr_thresh_stop.attr,
&format_attr_thresh_start.attr,
&format_attr_l2l3_sel.attr,
&format_attr_src_sel.attr,
&format_attr_invert_bit.attr,
&format_attr_src_mask.attr,
&format_attr_src_match.attr,
&format_attr_radix_scope.attr,
&format_attr_thresh_cmp.attr,
NULL,
};
static const struct attribute_group power12_pmu_format_group = {
.name = "format",
.attrs = power12_pmu_format_attr,
};
static const struct attribute_group *power12_pmu_attr_groups[] = {
&power12_pmu_format_group,
&power12_pmu_events_group,
NULL,
};
static int power12_generic_events[] = {
[PERF_COUNT_HW_CPU_CYCLES] = PM_CYC,
[PERF_COUNT_HW_INSTRUCTIONS] = PM_INST_CMPL,
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PM_BR_FIN,
[PERF_COUNT_HW_BRANCH_MISSES] = PM_MPRED_BR_FIN,
[PERF_COUNT_HW_CACHE_REFERENCES] = PM_LD_REF_L1,
[PERF_COUNT_HW_CACHE_MISSES] = PM_LD_DEMAND_MISS_L1_FIN,
};
static u64 power12_bhrb_filter_map(u64 branch_sample_type)
{
u64 pmu_bhrb_filter = 0;
/* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a
* regular PMU event. As the privilege state filter is handled
* in the basic PMC configuration of the accompanying regular
* PMU event, we ignore any separate BHRB specific request.
*/
/* No branch filter requested */
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
return pmu_bhrb_filter;
/* Invalid branch filter options - HW does not support */
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_RETURN)
return -1;
if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) {
pmu_bhrb_filter |= POWER12_MMCRA_IFM2;
return pmu_bhrb_filter;
}
if (branch_sample_type & PERF_SAMPLE_BRANCH_COND) {
pmu_bhrb_filter |= POWER12_MMCRA_IFM3;
return pmu_bhrb_filter;
}
if (branch_sample_type & PERF_SAMPLE_BRANCH_CALL)
return -1;
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) {
pmu_bhrb_filter |= POWER12_MMCRA_IFM1;
return pmu_bhrb_filter;
}
/* Every thing else is unsupported */
return -1;
}
static void power12_config_bhrb(u64 pmu_bhrb_filter)
{
pmu_bhrb_filter &= POWER12_MMCRA_BHRB_MASK;
/* Enable BHRB filter in PMU */
mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
}
#define C(x) PERF_COUNT_HW_CACHE_##x
/*
* Table of generalized cache-related events.
* 0 means not supported, -1 means nonsensical, other values
* are event codes.
*/
static u64 power12_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
[C(L1D)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = PM_LD_REF_L1,
[C(RESULT_MISS)] = PM_LD_MISS_L1,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = 0,
[C(RESULT_MISS)] = PM_ST_MISS_L1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = PM_LD_PREFETCH_CACHE_LINE_MISS,
[C(RESULT_MISS)] = 0,
},
},
[C(L1I)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = PM_INST_FROM_L1,
[C(RESULT_MISS)] = PM_L1_ICACHE_MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = PM_INST_FROM_L1MISS,
[C(RESULT_MISS)] = -1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = PM_IC_PREF_REQ,
[C(RESULT_MISS)] = 0,
},
},
[C(LL)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = PM_DATA_FROM_L3,
[C(RESULT_MISS)] = PM_DATA_FROM_L3MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = PM_L2_ST,
[C(RESULT_MISS)] = PM_L2_ST_MISS,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = PM_L3_PF_MISS_L3,
[C(RESULT_MISS)] = 0,
},
},
[C(DTLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = 0,
[C(RESULT_MISS)] = PM_DTLB_MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
},
[C(ITLB)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = 0,
[C(RESULT_MISS)] = PM_ITLB_MISS,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
},
[C(BPU)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = PM_BR_CMPL,
[C(RESULT_MISS)] = PM_BR_MPRED_CMPL,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
},
[C(NODE)] = {
[C(OP_READ)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = -1,
[C(RESULT_MISS)] = -1,
},
},
};
#undef C
/*
* Set the MMCR0[CC56RUN] bit to enable counting for
* PMC5 and PMC6 regardless of the state of CTRL[RUN],
* so that we can use counters 5 and 6 as PM_INST_CMPL and
* PM_CYC.
*/
static int power12_compute_mmcr(u64 event[], int n_ev,
unsigned int hwc[], struct mmcr_regs *mmcr,
struct perf_event *pevents[], u32 flags)
{
int ret;
ret = isa207_compute_mmcr(event, n_ev, hwc, mmcr, pevents, flags);
if (!ret)
mmcr->mmcr0 |= MMCR0_C56RUN;
return ret;
}
static struct power_pmu power12_pmu = {
.name = "Power12",
.n_counter = MAX_PMU_COUNTERS,
.add_fields = ISA207_ADD_FIELDS,
.test_adder = ISA207_TEST_ADDER,
.group_constraint_mask = CNST_CACHE_PMC4_MASK,
.group_constraint_val = CNST_CACHE_PMC4_VAL,
.compute_mmcr = power12_compute_mmcr,
.config_bhrb = power12_config_bhrb,
.bhrb_filter_map = power12_bhrb_filter_map,
.get_constraint = isa207_get_constraint,
.get_alternatives = power12_get_alternatives,
.get_mem_data_src = isa207_get_mem_data_src,
.get_mem_weight = isa207_get_mem_weight,
.disable_pmc = isa207_disable_pmc,
.flags = PPMU_HAS_SIER | PPMU_ARCH_207S |
PPMU_ARCH_31 | PPMU_HAS_ATTR_CONFIG1 |
PPMU_P10,
.n_generic = ARRAY_SIZE(power12_generic_events),
.generic_events = power12_generic_events,
.cache_events = &power12_cache_events,
.attr_groups = power12_pmu_attr_groups,
.bhrb_nr = 32,
.capabilities = PERF_PMU_CAP_EXTENDED_REGS,
.check_attr_config = power12_check_attr_config,
};
int __init init_power12_pmu(void)
{
unsigned int pvr;
int rc;
pvr = mfspr(SPRN_PVR);
if (PVR_VER(pvr) != PVR_POWER12)
return -ENODEV;
/* Set the PERF_REG_EXTENDED_MASK here */
PERF_REG_EXTENDED_MASK = PERF_REG_PMU_MASK_31;
rc = register_power_pmu(&power12_pmu);
if (rc)
return rc;
/* Tell userspace that EBB is supported */
cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
return 0;
}

View File

@ -227,13 +227,6 @@ config PPC44x_SIMPLE
help
This option enables the simple PowerPC 44x platform support.
config PPC4xx_GPIO
bool "PPC4xx GPIO support"
depends on 44x
select GPIOLIB
help
Enable gpiolib support for ppc440 based boards
# 44x specific CPU modules, selected based on the board above.
config 440EP
bool

View File

@ -15,4 +15,4 @@ obj-$(CONFIG_FSP2) += fsp2.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PPC4xx_HSTA_MSI) += hsta_msi.o
obj-$(CONFIG_PPC4xx_CPM) += cpm.o
obj-$(CONFIG_PPC4xx_GPIO) += gpio.o

View File

@ -1,210 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* PPC4xx gpio driver
*
* Copyright (c) 2008 Harris Corporation
* Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
* Copyright (c) MontaVista Software, Inc. 2008.
*
* Author: Steve Falco <sfalco@harris.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/gpio/driver.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#define GPIO_MASK(gpio) (0x80000000 >> (gpio))
#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2))
/* Physical GPIO register layout */
struct ppc4xx_gpio {
__be32 or;
__be32 tcr;
__be32 osrl;
__be32 osrh;
__be32 tsrl;
__be32 tsrh;
__be32 odr;
__be32 ir;
__be32 rr1;
__be32 rr2;
__be32 rr3;
__be32 reserved1;
__be32 isr1l;
__be32 isr1h;
__be32 isr2l;
__be32 isr2h;
__be32 isr3l;
__be32 isr3h;
};
struct ppc4xx_gpio_chip {
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
};
/*
* GPIO LIB API implementation for GPIOs
*
* There are a maximum of 32 gpios in each gpio controller.
*/
static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
return !!(in_be32(&regs->ir) & GPIO_MASK(gpio));
}
static inline void
__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
if (val)
setbits32(&regs->or, GPIO_MASK(gpio));
else
clrbits32(&regs->or, GPIO_MASK(gpio));
}
static int ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
__ppc4xx_gpio_set(gc, gpio, val);
spin_unlock_irqrestore(&chip->lock, flags);
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
return 0;
}
static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
/* Disable open-drain function */
clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Float the pin */
clrbits32(&regs->tcr, GPIO_MASK(gpio));
/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
if (gpio < 16) {
clrbits32(&regs->osrl, GPIO_MASK2(gpio));
clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
clrbits32(&regs->osrh, GPIO_MASK2(gpio));
clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
static int
ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = chip->regs;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
/* First set initial value */
__ppc4xx_gpio_set(gc, gpio, val);
/* Disable open-drain function */
clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Drive the pin */
setbits32(&regs->tcr, GPIO_MASK(gpio));
/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
if (gpio < 16) {
clrbits32(&regs->osrl, GPIO_MASK2(gpio));
clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
clrbits32(&regs->osrh, GPIO_MASK2(gpio));
clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
spin_unlock_irqrestore(&chip->lock, flags);
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
return 0;
}
static int ppc4xx_gpio_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = dev->of_node;
struct ppc4xx_gpio_chip *chip;
struct gpio_chip *gc;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
spin_lock_init(&chip->lock);
gc = &chip->gc;
gc->base = -1;
gc->ngpio = 32;
gc->direction_input = ppc4xx_gpio_dir_in;
gc->direction_output = ppc4xx_gpio_dir_out;
gc->get = ppc4xx_gpio_get;
gc->set = ppc4xx_gpio_set;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
if (!gc->label)
return -ENOMEM;
chip->regs = devm_of_iomap(dev, np, 0, NULL);
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
return devm_gpiochip_add_data(dev, gc, chip);
}
static const struct of_device_id ppc4xx_gpio_match[] = {
{
.compatible = "ibm,ppc4xx-gpio",
},
{},
};
MODULE_DEVICE_TABLE(of, ppc4xx_gpio_match);
static struct platform_driver ppc4xx_gpio_driver = {
.probe = ppc4xx_gpio_probe,
.driver = {
.name = "ppc4xx-gpio",
.of_match_table = ppc4xx_gpio_match,
},
};
static int __init ppc4xx_gpio_init(void)
{
return platform_driver_register(&ppc4xx_gpio_driver);
}
arch_initcall(ppc4xx_gpio_init);

View File

@ -284,9 +284,7 @@ static void __init bootx_scan_dt_build_struct(unsigned long base,
dt_push_token(OF_DT_BEGIN_NODE, mem_end);
/* get the node's full name */
namep = np->full_name ? (char *)(base + np->full_name) : NULL;
if (namep == NULL)
namep = "";
namep = np->full_name ? (char *)(base + np->full_name) : "";
l = strlen(namep);
DBG("* struct: %s\n", namep);

View File

@ -312,7 +312,7 @@ static void __noreturn pnv_restart(char *cmd)
pnv_prepare_going_down();
do {
if (!cmd || !strlen(cmd))
if (!cmd || *cmd == '\0')
rc = opal_cec_reboot();
else if (strcmp(cmd, "full") == 0)
rc = opal_cec_reboot2(OPAL_REBOOT_FULL_IPL, NULL);

View File

@ -332,10 +332,12 @@ static void pnv_cause_ipi(int cpu)
static void __init pnv_smp_probe(void)
{
if (xive_enabled())
xive_smp_probe();
else
if (xive_enabled()) {
if (xive_smp_probe() < 0)
return;
} else {
xics_smp_probe();
}
if (cpu_has_feature(CPU_FTR_DBELL)) {
ic_cause_ipi = smp_ops->cause_ipi;

View File

@ -13,6 +13,7 @@
#include <linux/export.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/processor.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
@ -361,12 +362,9 @@ static int __init ps3_create_spu(struct spu *spu, void *data)
if (result)
goto fail_enable;
/* Make sure the spu is in SPE_EX_STATE_EXECUTED. */
/* need something better here!!! */
while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status)
!= SPE_EX_STATE_EXECUTED)
(void)0;
while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status) !=
SPE_EX_STATE_EXECUTED)
cpu_relax();
return result;

View File

@ -812,18 +812,11 @@ static struct device_node *pci_dma_find(struct device_node *dn,
/* parse DMA window property. During normal system boot, only default
* DMA window is passed in OF. But, for kdump, a dedicated adapter might
* have both default and DDW in FDT. In this scenario, DDW takes precedence
* over default window.
* have both default and DDW in FDT. In this scenario, default window
* takes precedence over DDW. For a dedicated adapter, default window will
* potentially have more unused TCEs.
*/
if (ddw_win) {
struct dynamic_dma_window_prop *p;
p = (struct dynamic_dma_window_prop *)ddw_prop;
prop->liobn = p->liobn;
prop->dma_base = p->dma_base;
prop->tce_shift = p->tce_shift;
prop->window_shift = p->window_shift;
} else if (default_win) {
if (default_win) {
unsigned long offset, size, liobn;
of_parse_dma_window(rdn, default_prop, &liobn, &offset, &size);
@ -832,6 +825,14 @@ static struct device_node *pci_dma_find(struct device_node *dn,
prop->dma_base = cpu_to_be64(offset);
prop->tce_shift = cpu_to_be32(IOMMU_PAGE_SHIFT_4K);
prop->window_shift = cpu_to_be32(order_base_2(size));
} else {
struct dynamic_dma_window_prop *p;
p = (struct dynamic_dma_window_prop *)ddw_prop;
prop->liobn = p->liobn;
prop->dma_base = p->dma_base;
prop->tce_shift = p->tce_shift;
prop->window_shift = p->window_shift;
}
return rdn;

View File

@ -323,12 +323,8 @@ static int __init papr_init(void)
}
for (idx = 0; idx < num_attrs; idx++) {
bool show_val_desc = true;
/* Do not add the value desc attr if it does not exist */
if (strnlen(esi_attrs[idx].value_desc,
sizeof(esi_attrs[idx].value_desc)) == 0)
show_val_desc = false;
bool show_val_desc = *esi_attrs[idx].value_desc != '\0';
if (add_attr_group(be64_to_cpu(esi_attrs[idx].id),
&papr_groups[idx],

View File

@ -7,6 +7,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/irq_work.h>
@ -440,6 +441,8 @@ static __be64 *fwnmi_get_savep(struct pt_regs *regs)
static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{
struct rtas_error_log *h;
u32 extended_log_length;
size_t len;
__be64 *savep;
savep = fwnmi_get_savep(regs);
@ -449,17 +452,12 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
h = (struct rtas_error_log *)&savep[1];
extended_log_length = rtas_error_extended(h) ? rtas_error_extended_log_length(h) : 0;
len = struct_size(h, buffer, extended_log_length);
len = min(len, RTAS_ERROR_LOG_MAX);
/* Use the per cpu buffer from paca to store rtas error log */
memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
if (!rtas_error_extended(h)) {
memcpy(local_paca->mce_data_buf, h, sizeof(__u64));
} else {
int len, error_log_length;
error_log_length = 8 + rtas_error_extended_log_length(h);
len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
memcpy(local_paca->mce_data_buf, h, len);
}
memcpy(local_paca->mce_data_buf, h, len);
return (struct rtas_error_log *)local_paca->mce_data_buf;
}

View File

@ -307,7 +307,7 @@ static int do_remove_property(char *buf, size_t bufsize)
if (tmp)
*tmp = '\0';
if (strlen(buf) == 0)
if (*buf == '\0')
return -EINVAL;
return of_remove_property(np, of_find_property(np, buf, NULL));
@ -330,7 +330,7 @@ static int do_update_property(char *buf, size_t bufsize)
if (!next_prop)
return -EINVAL;
if (!strlen(name))
if (*name == '\0')
return -ENODEV;
newprop = new_property(name, length, value, NULL);

View File

@ -77,6 +77,7 @@
#include <asm/dtl.h>
#include <asm/hvconsole.h>
#include <asm/setup.h>
#include <asm/papr-watchdog.h>
#include "pseries.h"
@ -185,14 +186,37 @@ static void __init fwnmi_init(void)
#endif
}
static void pseries_crash_stop_watchdogs(void)
{
long rc;
rc = plpar_hcall_norets_notrace(H_WATCHDOG, PSERIES_WDTF_OP_STOP,
PSERIES_WDT_NUM_ALL);
if (rc != H_SUCCESS && rc != H_NOOP)
pr_warn("Could not stop watchdogs before kdump rc=%ld\n", rc);
}
/*
* Affix a device for the first timer to the platform bus if
* we have firmware support for the H_WATCHDOG hypercall.
*/
static __init int pseries_wdt_init(void)
{
if (firmware_has_feature(FW_FEATURE_WATCHDOG))
platform_device_register_simple("pseries-wdt", 0, NULL, 0);
struct platform_device *pdev;
if (!firmware_has_feature(FW_FEATURE_WATCHDOG))
return 0;
pdev = platform_device_register_simple("pseries-wdt", 0, NULL, 0);
if (IS_ERR(pdev)) {
pr_err("Failed to register pseries-wdt platform device\n");
return PTR_ERR(pdev);
}
if (crash_shutdown_register(pseries_crash_stop_watchdogs))
pr_warn("Could not register watchdog crash shutdown handler\n");
return 0;
}
machine_subsys_initcall(pseries, pseries_wdt_init);

View File

@ -199,10 +199,12 @@ static int pseries_cause_nmi_ipi(int cpu)
static __init void pSeries_smp_probe(void)
{
if (xive_enabled())
xive_smp_probe();
else
if (xive_enabled()) {
if (xive_smp_probe() < 0)
return;
} else {
xics_smp_probe();
}
/* No doorbell facility, must use the interrupt controller for IPIs */
if (!cpu_has_feature(CPU_FTR_DBELL))

View File

@ -181,6 +181,18 @@ static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
return 0;
}
static int cpm2_gpio32_get_direction(struct gpio_chip *gc, unsigned int gpio)
{
struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
u32 pin_mask = 1 << (31 - gpio);
if (in_be32(&iop->dir) & pin_mask)
return GPIO_LINE_DIRECTION_OUT;
return GPIO_LINE_DIRECTION_IN;
}
int cpm2_gpiochip_add32(struct device *dev)
{
struct device_node *np = dev->of_node;
@ -199,6 +211,7 @@ int cpm2_gpiochip_add32(struct device *dev)
gc->ngpio = 32;
gc->direction_input = cpm2_gpio32_dir_in;
gc->direction_output = cpm2_gpio32_dir_out;
gc->get_direction = cpm2_gpio32_get_direction;
gc->get = cpm2_gpio32_get;
gc->set = cpm2_gpio32_set;
gc->parent = dev;

View File

@ -74,6 +74,8 @@ static struct xive_ipi_desc {
*/
static unsigned int xive_ipi_cpu_to_irq(unsigned int cpu)
{
if (!xive_ipis)
return XIVE_BAD_IRQ;
return xive_ipis[early_cpu_to_node(cpu)].irq;
}
#endif
@ -1132,8 +1134,7 @@ static int __init xive_init_ipis(void)
if (!ipi_domain)
goto out_free_fwnode;
xive_ipis = kzalloc_objs(*xive_ipis, nr_node_ids,
GFP_KERNEL | __GFP_NOFAIL);
xive_ipis = kzalloc_objs(*xive_ipis, nr_node_ids, GFP_KERNEL);
if (!xive_ipis)
goto out_free_domain;
@ -1158,6 +1159,7 @@ static int __init xive_init_ipis(void)
out_free_xive_ipis:
kfree(xive_ipis);
xive_ipis = NULL;
out_free_domain:
irq_domain_remove(ipi_domain);
out_free_fwnode:
@ -1190,6 +1192,9 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
pr_debug("Setting up IPI for CPU %d\n", cpu);
if (xive_ipi_irq == XIVE_BAD_IRQ)
return -EIO;
xc = per_cpu(xive_cpu, cpu);
/* Check if we are already setup */
@ -1234,6 +1239,9 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
/* Disable the IPI and free the IRQ data */
if (xive_ipi_irq == XIVE_BAD_IRQ)
return;
/* Already cleaned up ? */
if (xc->hw_ipi == XIVE_BAD_IRQ)
return;
@ -1257,15 +1265,23 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
xive_ops->put_ipi(cpu, xc);
}
void __init xive_smp_probe(void)
int __init xive_smp_probe(void)
{
smp_ops->cause_ipi = xive_cause_ipi;
int ret;
/* Register the IPI */
xive_init_ipis();
ret = xive_init_ipis();
if (ret < 0)
return ret;
/* Allocate and setup IPI for the boot CPU */
xive_setup_cpu_ipi(smp_processor_id());
ret = xive_setup_cpu_ipi(smp_processor_id());
if (ret < 0)
return ret;
smp_ops->cause_ipi = xive_cause_ipi;
return 0;
}
#endif /* CONFIG_SMP */

View File

@ -593,6 +593,13 @@ config GPIO_POLARFIRE_SOC
help
Say yes here to support the GPIO controllers on Microchip FPGAs.
config GPIO_PPC44X
tristate "PPC44x GPIO support"
depends on 44x || COMPILE_TEST
select GPIO_GENERIC
help
Enable gpiolib support for ppc440 based boards.
config GPIO_PXA
bool "PXA GPIO support"
depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST

View File

@ -147,6 +147,7 @@ obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PPC44X) += gpio-ppc44x.o
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o

208
drivers/gpio/gpio-ppc44x.c Normal file
View File

@ -0,0 +1,208 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* PPC44x gpio driver
*
* Copyright (c) 2008 Harris Corporation
* Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
* Copyright (c) MontaVista Software, Inc. 2008.
*
* Author: Steve Falco <sfalco@harris.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/gpio/generic.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#define GPIO_MASK(gpio) (0x80000000 >> (gpio))
#define GPIO_MASK2(gpio) (0xc0000000 >> (((gpio) % 16) * 2))
/* Physical GPIO register layout */
struct ppc44x_gpio {
__be32 or;
__be32 tcr;
__be32 osrl;
__be32 osrh;
__be32 tsrl;
__be32 tsrh;
__be32 odr;
__be32 ir;
__be32 rr1;
__be32 rr2;
__be32 rr3;
__be32 reserved1;
__be32 isr1l;
__be32 isr1h;
__be32 isr2l;
__be32 isr2h;
__be32 isr3l;
__be32 isr3h;
};
struct ppc44x_gpio_chip {
struct gpio_generic_chip chip;
void __iomem *regs;
};
static inline void ppc44x_clrbits32(void __iomem *addr, u32 mask)
{
u32 val = ioread32be(addr);
val &= ~mask;
iowrite32be(val, addr);
}
static inline void ppc44x_setbits32(void __iomem *addr, u32 mask)
{
u32 val = ioread32be(addr);
val |= mask;
iowrite32be(val, addr);
}
/*
* GPIO LIB API implementation for GPIOs
*
* There are a maximum of 32 gpios in each gpio controller.
*/
static inline void
__ppc44x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
struct gpio_generic_chip *gen_gc = &chip->chip;
if (val)
gen_gc->sdata |= GPIO_MASK(gpio);
else
gen_gc->sdata &= ~GPIO_MASK(gpio);
gpio_generic_write_reg(gen_gc, gen_gc->reg_set, gen_gc->sdata);
}
static int ppc44x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
struct gpio_generic_chip *gen_gc = &chip->chip;
struct ppc44x_gpio __iomem *regs = chip->regs;
guard(gpio_generic_lock_irqsave)(gen_gc);
/* Disable open-drain function */
ppc44x_clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Float the pin */
ppc44x_clrbits32(&regs->tcr, GPIO_MASK(gpio));
gen_gc->sdir &= ~GPIO_MASK(gpio);
/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
if (gpio < 16) {
ppc44x_clrbits32(&regs->osrl, GPIO_MASK2(gpio));
ppc44x_clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
ppc44x_clrbits32(&regs->osrh, GPIO_MASK2(gpio));
ppc44x_clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
return 0;
}
static int
ppc44x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
struct gpio_generic_chip *gen_gc = &chip->chip;
struct ppc44x_gpio __iomem *regs = chip->regs;
guard(gpio_generic_lock_irqsave)(gen_gc);
/* First set initial value */
__ppc44x_gpio_set(gc, gpio, val);
/* Disable open-drain function */
ppc44x_clrbits32(&regs->odr, GPIO_MASK(gpio));
/* Drive the pin */
ppc44x_setbits32(&regs->tcr, GPIO_MASK(gpio));
gen_gc->sdir |= GPIO_MASK(gpio);
/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
if (gpio < 16) {
ppc44x_clrbits32(&regs->osrl, GPIO_MASK2(gpio));
ppc44x_clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
} else {
ppc44x_clrbits32(&regs->osrh, GPIO_MASK2(gpio));
ppc44x_clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
}
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
return 0;
}
static int ppc44x_gpio_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct ppc44x_gpio __iomem *regs;
struct ppc44x_gpio_chip *chip;
struct gpio_generic_chip_config config;
struct gpio_chip *gc;
int ret;
regs = devm_platform_ioremap_resource(ofdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->regs = regs;
config = (struct gpio_generic_chip_config) {
.dev = dev,
.sz = 4,
.dat = &regs->ir,
.set = &regs->or,
.dirout = &regs->tcr,
.flags = GPIO_GENERIC_BIG_ENDIAN |
GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER,
};
ret = gpio_generic_chip_init(&chip->chip, &config);
if (ret)
return ret;
gc = &chip->chip.gc;
gc->label = dev_name(dev);
gc->parent = dev;
gc->direction_input = ppc44x_gpio_dir_in;
gc->direction_output = ppc44x_gpio_dir_out;
return devm_gpiochip_add_data(dev, gc, chip);
}
static const struct of_device_id ppc44x_gpio_match[] = {
{
.compatible = "ibm,ppc4xx-gpio",
},
{},
};
MODULE_DEVICE_TABLE(of, ppc44x_gpio_match);
static struct platform_driver ppc44x_gpio_driver = {
.probe = ppc44x_gpio_probe,
.driver = {
.name = "ppc44x-gpio",
.of_match_table = ppc44x_gpio_match,
},
};
MODULE_DESCRIPTION("PPC44x gpio driver");
MODULE_LICENSE("GPL");
module_platform_driver(ppc44x_gpio_driver);

View File

@ -12,61 +12,10 @@
#include <linux/platform_device.h>
#include <linux/time64.h>
#include <linux/watchdog.h>
#include <asm/papr-watchdog.h>
#define DRV_NAME "pseries-wdt"
/*
* H_WATCHDOG Input
*
* R4: "flags":
*
* Bits 48-55: "operation"
*/
#define PSERIES_WDTF_OP_START 0x100UL /* start timer */
#define PSERIES_WDTF_OP_STOP 0x200UL /* stop timer */
#define PSERIES_WDTF_OP_QUERY 0x300UL /* query timer capabilities */
/*
* Bits 56-63: "timeoutAction" (for "Start Watchdog" only)
*/
#define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL /* poweroff */
#define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL /* restart */
#define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL /* dump + restart */
/*
* H_WATCHDOG Output
*
* R3: Return code
*
* H_SUCCESS The operation completed.
*
* H_BUSY The hypervisor is too busy; retry the operation.
*
* H_PARAMETER The given "flags" are somehow invalid. Either the
* "operation" or "timeoutAction" is invalid, or a
* reserved bit is set.
*
* H_P2 The given "watchdogNumber" is zero or exceeds the
* supported maximum value.
*
* H_P3 The given "timeoutInMs" is below the supported
* minimum value.
*
* H_NOOP The given "watchdogNumber" is already stopped.
*
* H_HARDWARE The operation failed for ineffable reasons.
*
* H_FUNCTION The H_WATCHDOG hypercall is not supported by this
* hypervisor.
*
* R4:
*
* - For the "Query Watchdog Capabilities" operation, a 64-bit
* structure:
*/
#define PSERIES_WDTQ_MIN_TIMEOUT(cap) (((cap) >> 48) & 0xffff)
#define PSERIES_WDTQ_MAX_NUMBER(cap) (((cap) >> 32) & 0xffff)
static const unsigned long pseries_wdt_action[] = {
[0] = PSERIES_WDTF_ACTION_HARD_POWEROFF,
[1] = PSERIES_WDTF_ACTION_HARD_RESTART,

View File

@ -997,6 +997,7 @@ struct kvm_enable_cap {
#define KVM_CAP_S390_KEYOP 247
#define KVM_CAP_S390_VSIE_ESAMODE 248
#define KVM_CAP_S390_HPAGE_2G 249
#define KVM_CAP_PPC_COMPAT_CAPS 250
struct kvm_irq_routing_irqchip {
__u32 irqchip;
@ -1341,6 +1342,8 @@ struct kvm_s390_keyop {
/* Available with KVM_CAP_COUNTER_OFFSET */
#define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset)
#define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO, 0xb6, struct reg_mask_range)
/* Available with KVM_CAP_PPC_COMPAT_CAPS */
#define KVM_PPC_GET_COMPAT_CAPS _IO(KVMIO, 0xb8)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)

View File

@ -3,6 +3,9 @@
# Where to place rustdoc generated documentation
rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
# Clean generated host directory
clean-files := host/
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
@ -33,7 +36,7 @@ endif
obj-$(CONFIG_RUST) += exports.o
always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib
always-$(CONFIG_RUST) += host/libproc_macro2.rlib host/libquote.rlib host/libsyn.rlib
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
@ -171,7 +174,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
$(rustc_target_flags) -L$(objtree)/$(obj)$(if $(rustdoc_host),/host) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
--crate-name $(subst rustdoc-,,$@) \
@ -269,6 +272,7 @@ rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs \
rustdoc-pin_init: private rustdoc_host = yes
rustdoc-pin_init: private rustc_target_flags = $(pin_init-flags) \
--extern pin_init_internal=$(objtree)/$(obj)/$(libpin_init_internal_name) \
--extern alloc --cfg feature=\"alloc\"
rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \
rustdoc-macros FORCE
@ -452,7 +456,8 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
-fstrict-flex-arrays=% -fmin-function-alignment=% \
-fzero-init-padding-bits=% -mno-fdpic \
-fdiagnostics-show-context -fdiagnostics-show-context=% \
--param=% --param asan-% -fno-isolate-erroneous-paths-dereference
--param=% --param asan-% -fno-isolate-erroneous-paths-dereference \
-ffixed-r2 -mmultiple -mno-readonly-in-sdata
# Derived from `scripts/Makefile.clang`.
BINDGEN_TARGET_x86 := x86_64-linux-gnu
@ -462,6 +467,13 @@ BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf
BINDGEN_TARGET_s390 := s390x-linux-gnu
# This is only for i386 UM builds, which need the 32-bit target not -m32
BINDGEN_TARGET_i386 := i386-linux-gnu
ifdef CONFIG_PPC64
BINDGEN_TARGET_powerpc := powerpc64le-linux-gnu
else
BINDGEN_TARGET_powerpc := powerpc-linux-gnu
endif
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
@ -580,23 +592,23 @@ quiet_cmd_rustc_procmacrolibrary = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_Q
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
--emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \
--out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \
--out-dir $(objtree)/$(obj)/host -L$(objtree)/$(obj)/host \
--crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $<
$(obj)/libproc_macro2.rlib: private skip_clippy = 1
$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
$(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
$(obj)/host/libproc_macro2.rlib: private skip_clippy = 1
$(obj)/host/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
$(obj)/host/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
$(obj)/libquote.rlib: private skip_clippy = 1
$(obj)/libquote.rlib: private skip_flags = $(quote-skip_flags)
$(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags)
$(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE
$(obj)/host/libquote.rlib: private skip_clippy = 1
$(obj)/host/libquote.rlib: private skip_flags = $(quote-skip_flags)
$(obj)/host/libquote.rlib: private rustc_target_flags = $(quote-flags)
$(obj)/host/libquote.rlib: $(src)/quote/lib.rs $(obj)/host/libproc_macro2.rlib FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
$(obj)/libsyn.rlib: private skip_clippy = 1
$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags)
$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE
$(obj)/host/libsyn.rlib: private skip_clippy = 1
$(obj)/host/libsyn.rlib: private rustc_target_flags = $(syn-flags)
$(obj)/host/libsyn.rlib: $(src)/syn/lib.rs $(obj)/host/libquote.rlib FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
quiet_cmd_rustc_procmacro = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) P $@
@ -606,26 +618,26 @@ quiet_cmd_rustc_procmacro = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET))
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro -L$(objtree)/$(obj) \
--crate-type proc-macro -L$(objtree)/$(obj)/host \
--crate-name $(patsubst lib%.$(procmacro-extension),%,$(notdir $@)) \
@$(objtree)/include/generated/rustc_cfg $<
# Procedural macros can only be used with the `rustc` that compiled it.
$(obj)/$(libzerocopy_derive_name): private skip_clippy = 1
$(obj)/$(libzerocopy_derive_name): private rustc_target_flags = $(zerocopy_derive-flags)
$(obj)/$(libzerocopy_derive_name): $(src)/zerocopy-derive/lib.rs $(obj)/libproc_macro2.rlib \
$(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
$(obj)/$(libzerocopy_derive_name): $(src)/zerocopy-derive/lib.rs $(obj)/host/libproc_macro2.rlib \
$(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
$(obj)/$(libmacros_name): private rustc_target_flags = \
--extern proc_macro2 --extern quote --extern syn
$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
$(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/host/libproc_macro2.rlib \
$(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
$(obj)/$(libpin_init_internal_name): private rustc_target_flags = $(pin_init_internal-flags)
$(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs \
$(obj)/libproc_macro2.rlib $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
$(obj)/host/libproc_macro2.rlib $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
# `rustc` requires `-Zunstable-options` to use custom target specifications
@ -683,6 +695,10 @@ ifneq ($(or $(CONFIG_ARM64),$(and $(CONFIG_RISCV),$(CONFIG_64BIT))),)
__ashrti3 \
__ashlti3 __lshrti3
endif
ifdef CONFIG_PPC32
redirect-intrinsics += \
__udivdi3 __umoddi3
endif
ifdef CONFIG_MODVERSIONS
cmd_gendwarfksyms = $(if $(skip_gendwarfksyms),, \

View File

@ -97,5 +97,11 @@ pub extern "C" fn $ident() {
__aeabi_uldivmod,
});
#[cfg(target_arch = "powerpc")]
define_panicking_intrinsics!("`u64` division/modulo should not be used", {
__udivdi3,
__umoddi3,
});
// NOTE: if you are adding a new intrinsic here, you should also add it to
// `redirect-intrinsics` in `rust/Makefile`.

View File

@ -58,7 +58,9 @@
#include "cred.c"
#include "device.c"
#include "dma.c"
#ifdef CONFIG_DMA_SHARED_BUFFER
#include "dma-resv.c"
#endif
#include "drm.c"
#include "drm_gpuvm.c"
#include "err.c"

View File

@ -33,6 +33,8 @@ llvm)
rustc)
if [ "$SRCARCH" = "s390" ]; then
echo 1.96.0
elif [ "$ARCH" = powerpc ]; then
echo 1.95.0
else
echo 1.85.0
fi