From abc524caa1382a56f82d07d0621b7fa80f33e207 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:40 +0100 Subject: [PATCH 01/23] s390/pai_crypto: Rename variable cfm_dbg The global variable cfm_dbg points to the s390dbf debug buffer. Rename it to paidbg to better reflect its purpose. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 9b06b8a83342..ff0be76e4441 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -19,7 +19,7 @@ #include #include -static debug_info_t *cfm_dbg; +static debug_info_t *paidbg; static unsigned int paicrypt_cnt; /* Size of the mapped counter sets */ /* extracted with QPACI instruction */ @@ -55,7 +55,7 @@ static void paicrypt_root_free(void) free_percpu(paicrypt_root.mapptr); paicrypt_root.mapptr = NULL; } - debug_sprintf_event(cfm_dbg, 5, "%s root.refcount %d\n", __func__, + debug_sprintf_event(paidbg, 5, "%s root.refcount %d\n", __func__, refcount_read(&paicrypt_root.refcnt)); } @@ -98,7 +98,7 @@ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) struct paicrypt_map *cpump = mp->mapptr; mutex_lock(&pai_reserve_mutex); - debug_sprintf_event(cfm_dbg, 5, "%s event %#llx cpu %d users %d " + debug_sprintf_event(paidbg, 5, "%s event %#llx cpu %d users %d " "refcnt %u\n", __func__, event->attr.config, event->cpu, cpump->active_events, refcount_read(&cpump->refcnt)); @@ -822,19 +822,19 @@ static int __init paicrypt_init(void) } /* Setup s390dbf facility */ - cfm_dbg = debug_register(KMSG_COMPONENT, 2, 256, 128); - if (!cfm_dbg) { + paidbg = debug_register(KMSG_COMPONENT, 2, 256, 128); + if (!paidbg) { pr_err("Registration of s390dbf pai_crypto failed\n"); return -ENOMEM; } - debug_register_view(cfm_dbg, &debug_sprintf_view); + debug_register_view(paidbg, &debug_sprintf_view); rc = perf_pmu_register(&paicrypt, "pai_crypto", -1); if (rc) { pr_err("Registering the pai_crypto PMU failed with rc=%i\n", rc); - debug_unregister_view(cfm_dbg, &debug_sprintf_view); - debug_unregister(cfm_dbg); + debug_unregister_view(paidbg, &debug_sprintf_view); + debug_unregister(paidbg); return rc; } return 0; From c124208b74a66713d2743089ae1c55a1661e8cd9 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:41 +0100 Subject: [PATCH 02/23] s390/pai_crypto: Rename member paicrypt_map::page Rename member page in struct paicrypt_map to area. This rename creates consistent naming for both PMU drivers paicrypto and PMU paiext. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index ff0be76e4441..dd5b32c4dd44 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -31,7 +31,7 @@ struct pai_userdata { } __packed; struct paicrypt_map { - unsigned long *page; /* Page for CPU to store counters */ + unsigned long *area; /* Area for CPU to store counters */ struct pai_userdata *save; /* Page to store no-zero counters */ unsigned int active_events; /* # of PAI crypto users */ refcount_t refcnt; /* Reference count mapped buffers */ @@ -83,7 +83,7 @@ static DEFINE_MUTEX(pai_reserve_mutex); /* Free all memory allocated for event counting/sampling setup */ static void paicrypt_free(struct paicrypt_mapptr *mp) { - free_page((unsigned long)mp->mapptr->page); + free_page((unsigned long)mp->mapptr->area); kvfree(mp->mapptr->save); kfree(mp->mapptr); mp->mapptr = NULL; @@ -143,13 +143,13 @@ static u64 paicrypt_getdata(struct perf_event *event, bool kernel) int i; if (event->attr.config != PAI_CRYPTO_BASE) { - return paicrypt_getctr(cpump->page, + return paicrypt_getctr(cpump->area, event->attr.config - PAI_CRYPTO_BASE, kernel); } for (i = 1; i <= paicrypt_cnt; i++) { - u64 val = paicrypt_getctr(cpump->page, i, kernel); + u64 val = paicrypt_getctr(cpump->area, i, kernel); if (!val) continue; @@ -201,11 +201,11 @@ static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) * Only the first counting event has to allocate a page. */ mp->mapptr = cpump; - cpump->page = (unsigned long *)get_zeroed_page(GFP_KERNEL); + cpump->area = (unsigned long *)get_zeroed_page(GFP_KERNEL); cpump->save = kvmalloc_array(paicrypt_cnt + 1, sizeof(struct pai_userdata), GFP_KERNEL); - if (!cpump->page || !cpump->save) { + if (!cpump->area || !cpump->save) { paicrypt_free(mp); goto undo; } @@ -334,7 +334,7 @@ static void paicrypt_start(struct perf_event *event, int flags) sum = paicrypt_getall(event); /* Get current value */ local64_set(&event->hw.prev_count, sum); } else { /* Sampling */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->page, PAGE_SIZE); + memcpy((void *)PAI_SAVE_AREA(event), cpump->area, PAGE_SIZE); /* Enable context switch callback for system-wide sampling */ if (!(event->attach_state & PERF_ATTACH_TASK)) { list_add_tail(PAI_SWLIST(event), &cpump->syswide_list); @@ -352,7 +352,7 @@ static int paicrypt_add(struct perf_event *event, int flags) unsigned long ccd; if (++cpump->active_events == 1) { - ccd = virt_to_phys(cpump->page) | PAI_CRYPTO_KERNEL_OFFSET; + ccd = virt_to_phys(cpump->area) | PAI_CRYPTO_KERNEL_OFFSET; WRITE_ONCE(get_lowcore()->ccd, ccd); local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); } @@ -465,7 +465,7 @@ static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump, overflow = perf_event_overflow(event, &data, ®s); perf_event_update_userpage(event); /* Save crypto counter lowcore page after reading event data. */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->page, PAGE_SIZE); + memcpy((void *)PAI_SAVE_AREA(event), cpump->area, PAGE_SIZE); return overflow; } @@ -477,7 +477,7 @@ static void paicrypt_have_sample(struct perf_event *event, if (!event) /* No event active */ return; - rawsize = paicrypt_copy(cpump->save, cpump->page, + rawsize = paicrypt_copy(cpump->save, cpump->area, (unsigned long *)PAI_SAVE_AREA(event), event->attr.exclude_user, event->attr.exclude_kernel); From 2706ea193af5c7d727eda2d24c9c9833e2c47ddb Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:42 +0100 Subject: [PATCH 03/23] s390/pai_crypto: Rename structure paicrypt_mapptr to pai_mapptr To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename structure paicrypt_mapptr to pai_mapptr. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index dd5b32c4dd44..1c855391ac8e 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -39,13 +39,13 @@ struct paicrypt_map { struct list_head syswide_list; /* List system-wide sampling events */ }; -struct paicrypt_mapptr { +struct pai_mapptr { struct paicrypt_map *mapptr; }; static struct paicrypt_root { /* Anchor to per CPU data */ refcount_t refcnt; /* Overall active events */ - struct paicrypt_mapptr __percpu *mapptr; + struct pai_mapptr __percpu *mapptr; } paicrypt_root; /* Free per CPU data when the last event is removed. */ @@ -69,7 +69,7 @@ static int paicrypt_root_alloc(void) { if (!refcount_inc_not_zero(&paicrypt_root.refcnt)) { /* The memory is already zeroed. */ - paicrypt_root.mapptr = alloc_percpu(struct paicrypt_mapptr); + paicrypt_root.mapptr = alloc_percpu(struct pai_mapptr); if (!paicrypt_root.mapptr) return -ENOMEM; refcount_set(&paicrypt_root.refcnt, 1); @@ -81,7 +81,7 @@ static int paicrypt_root_alloc(void) static DEFINE_MUTEX(pai_reserve_mutex); /* Free all memory allocated for event counting/sampling setup */ -static void paicrypt_free(struct paicrypt_mapptr *mp) +static void paicrypt_free(struct pai_mapptr *mp) { free_page((unsigned long)mp->mapptr->area); kvfree(mp->mapptr->save); @@ -94,7 +94,7 @@ static void paicrypt_free(struct paicrypt_mapptr *mp) */ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) { - struct paicrypt_mapptr *mp = per_cpu_ptr(paicrypt_root.mapptr, cpu); + struct pai_mapptr *mp = per_cpu_ptr(paicrypt_root.mapptr, cpu); struct paicrypt_map *cpump = mp->mapptr; mutex_lock(&pai_reserve_mutex); @@ -137,7 +137,7 @@ static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) */ static u64 paicrypt_getdata(struct perf_event *event, bool kernel) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; u64 sum = 0; int i; @@ -180,7 +180,7 @@ static u64 paicrypt_getall(struct perf_event *event) static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) { struct paicrypt_map *cpump = NULL; - struct paicrypt_mapptr *mp; + struct pai_mapptr *mp; int rc; mutex_lock(&pai_reserve_mutex); @@ -326,7 +326,7 @@ static void paicrypt_read(struct perf_event *event) static void paicrypt_start(struct perf_event *event, int flags) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; u64 sum; @@ -347,7 +347,7 @@ static void paicrypt_start(struct perf_event *event, int flags) static int paicrypt_add(struct perf_event *event, int flags) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; unsigned long ccd; @@ -365,7 +365,7 @@ static int paicrypt_add(struct perf_event *event, int flags) static void paicrypt_have_sample(struct perf_event *, struct paicrypt_map *); static void paicrypt_stop(struct perf_event *event, int flags) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; if (!event->attr.sample_period) { /* Counting */ @@ -384,7 +384,7 @@ static void paicrypt_stop(struct perf_event *event, int flags) static void paicrypt_del(struct perf_event *event, int flags) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; paicrypt_stop(event, PERF_EF_UPDATE); @@ -488,7 +488,7 @@ static void paicrypt_have_sample(struct perf_event *event, /* Check if there is data to be saved on schedule out of a task. */ static void paicrypt_have_samples(void) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; struct perf_event *event; From a626e0d46acb84acb07534c672b19690d5363315 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:43 +0100 Subject: [PATCH 04/23] s390/pai_crypto: Rename structure paicrypt_map to pai_map To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename structure paicrypt_map to pai_map. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 1c855391ac8e..47b950629766 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -30,7 +30,7 @@ struct pai_userdata { u64 value; } __packed; -struct paicrypt_map { +struct pai_map { unsigned long *area; /* Area for CPU to store counters */ struct pai_userdata *save; /* Page to store no-zero counters */ unsigned int active_events; /* # of PAI crypto users */ @@ -40,7 +40,7 @@ struct paicrypt_map { }; struct pai_mapptr { - struct paicrypt_map *mapptr; + struct pai_map *mapptr; }; static struct paicrypt_root { /* Anchor to per CPU data */ @@ -95,7 +95,7 @@ static void paicrypt_free(struct pai_mapptr *mp) static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) { struct pai_mapptr *mp = per_cpu_ptr(paicrypt_root.mapptr, cpu); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; mutex_lock(&pai_reserve_mutex); debug_sprintf_event(paidbg, 5, "%s event %#llx cpu %d users %d " @@ -138,7 +138,7 @@ static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) static u64 paicrypt_getdata(struct perf_event *event, bool kernel) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; u64 sum = 0; int i; @@ -179,7 +179,7 @@ static u64 paicrypt_getall(struct perf_event *event) */ static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) { - struct paicrypt_map *cpump = NULL; + struct pai_map *cpump = NULL; struct pai_mapptr *mp; int rc; @@ -327,7 +327,7 @@ static void paicrypt_read(struct perf_event *event) static void paicrypt_start(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; u64 sum; if (!event->attr.sample_period) { /* Counting */ @@ -348,7 +348,7 @@ static void paicrypt_start(struct perf_event *event, int flags) static int paicrypt_add(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; unsigned long ccd; if (++cpump->active_events == 1) { @@ -362,11 +362,11 @@ static int paicrypt_add(struct perf_event *event, int flags) return 0; } -static void paicrypt_have_sample(struct perf_event *, struct paicrypt_map *); +static void paicrypt_have_sample(struct perf_event *, struct pai_map *); static void paicrypt_stop(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; if (!event->attr.sample_period) { /* Counting */ paicrypt_read(event); @@ -385,7 +385,7 @@ static void paicrypt_stop(struct perf_event *event, int flags) static void paicrypt_del(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; paicrypt_stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { @@ -431,7 +431,7 @@ static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page, return outidx * sizeof(*userdata); } -static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump, +static int paicrypt_push_sample(size_t rawsize, struct pai_map *cpump, struct perf_event *event) { struct perf_sample_data data; @@ -471,7 +471,7 @@ static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump, /* Check if there is data to be saved on schedule out of a task. */ static void paicrypt_have_sample(struct perf_event *event, - struct paicrypt_map *cpump) + struct pai_map *cpump) { size_t rawsize; @@ -489,7 +489,7 @@ static void paicrypt_have_sample(struct perf_event *event, static void paicrypt_have_samples(void) { struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; + struct pai_map *cpump = mp->mapptr; struct perf_event *event; list_for_each_entry(event, &cpump->syswide_list, hw.tp_list) From 3f082c2e479b02e553bf1ed0b47f0a315179585c Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:44 +0100 Subject: [PATCH 05/23] s390/pai_crypto: Rename structure paicrypt_root To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename structure paicrypt_root to pai_root. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 47b950629766..5807365145c3 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -43,20 +43,20 @@ struct pai_mapptr { struct pai_map *mapptr; }; -static struct paicrypt_root { /* Anchor to per CPU data */ +static struct pai_root { /* Anchor to per CPU data */ refcount_t refcnt; /* Overall active events */ struct pai_mapptr __percpu *mapptr; -} paicrypt_root; +} pai_root; /* Free per CPU data when the last event is removed. */ static void paicrypt_root_free(void) { - if (refcount_dec_and_test(&paicrypt_root.refcnt)) { - free_percpu(paicrypt_root.mapptr); - paicrypt_root.mapptr = NULL; + if (refcount_dec_and_test(&pai_root.refcnt)) { + free_percpu(pai_root.mapptr); + pai_root.mapptr = NULL; } debug_sprintf_event(paidbg, 5, "%s root.refcount %d\n", __func__, - refcount_read(&paicrypt_root.refcnt)); + refcount_read(&pai_root.refcnt)); } /* @@ -67,12 +67,12 @@ static void paicrypt_root_free(void) */ static int paicrypt_root_alloc(void) { - if (!refcount_inc_not_zero(&paicrypt_root.refcnt)) { + if (!refcount_inc_not_zero(&pai_root.refcnt)) { /* The memory is already zeroed. */ - paicrypt_root.mapptr = alloc_percpu(struct pai_mapptr); - if (!paicrypt_root.mapptr) + pai_root.mapptr = alloc_percpu(struct pai_mapptr); + if (!pai_root.mapptr) return -ENOMEM; - refcount_set(&paicrypt_root.refcnt, 1); + refcount_set(&pai_root.refcnt, 1); } return 0; } @@ -94,7 +94,7 @@ static void paicrypt_free(struct pai_mapptr *mp) */ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) { - struct pai_mapptr *mp = per_cpu_ptr(paicrypt_root.mapptr, cpu); + struct pai_mapptr *mp = per_cpu_ptr(pai_root.mapptr, cpu); struct pai_map *cpump = mp->mapptr; mutex_lock(&pai_reserve_mutex); @@ -137,7 +137,7 @@ static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) */ static u64 paicrypt_getdata(struct perf_event *event, bool kernel) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; u64 sum = 0; int i; @@ -190,7 +190,7 @@ static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) goto unlock; /* Allocate node for this event */ - mp = per_cpu_ptr(paicrypt_root.mapptr, cpu); + mp = per_cpu_ptr(pai_root.mapptr, cpu); cpump = mp->mapptr; if (!cpump) { /* Paicrypt_map allocated? */ rc = -ENOMEM; @@ -326,7 +326,7 @@ static void paicrypt_read(struct perf_event *event) static void paicrypt_start(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; u64 sum; @@ -347,7 +347,7 @@ static void paicrypt_start(struct perf_event *event, int flags) static int paicrypt_add(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; unsigned long ccd; @@ -365,7 +365,7 @@ static int paicrypt_add(struct perf_event *event, int flags) static void paicrypt_have_sample(struct perf_event *, struct pai_map *); static void paicrypt_stop(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; if (!event->attr.sample_period) { /* Counting */ @@ -384,7 +384,7 @@ static void paicrypt_stop(struct perf_event *event, int flags) static void paicrypt_del(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; paicrypt_stop(event, PERF_EF_UPDATE); @@ -488,7 +488,7 @@ static void paicrypt_have_sample(struct perf_event *event, /* Check if there is data to be saved on schedule out of a task. */ static void paicrypt_have_samples(void) { - struct pai_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; struct perf_event *event; From 387c7b5f04eff53f5bd7990b9909f7cc3a4e2e8c Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:45 +0100 Subject: [PATCH 06/23] s390/pai_crypto: Rename paicrypt_root_alloc() and paicrypt_root_free() To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename functions paicrypt_root_alloc() and paicrypt_root_free() to pai_root_alloc() and pai_root_free(). No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 5807365145c3..12f99028d5b8 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -49,7 +49,7 @@ static struct pai_root { /* Anchor to per CPU data */ } pai_root; /* Free per CPU data when the last event is removed. */ -static void paicrypt_root_free(void) +static void pai_root_free(void) { if (refcount_dec_and_test(&pai_root.refcnt)) { free_percpu(pai_root.mapptr); @@ -65,7 +65,7 @@ static void paicrypt_root_free(void) * CPUs possible, which might be larger than the number of CPUs currently * online. */ -static int paicrypt_root_alloc(void) +static int pai_root_alloc(void) { if (!refcount_inc_not_zero(&pai_root.refcnt)) { /* The memory is already zeroed. */ @@ -104,7 +104,7 @@ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) refcount_read(&cpump->refcnt)); if (refcount_dec_and_test(&cpump->refcnt)) paicrypt_free(mp); - paicrypt_root_free(); + pai_root_free(); mutex_unlock(&pai_reserve_mutex); } @@ -185,7 +185,7 @@ static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) mutex_lock(&pai_reserve_mutex); /* Allocate root node */ - rc = paicrypt_root_alloc(); + rc = pai_root_alloc(); if (rc) goto unlock; @@ -222,7 +222,7 @@ undo: * the event in not created, its destroy() function is never * invoked. Adjust the reference counter for the anchor. */ - paicrypt_root_free(); + pai_root_free(); } unlock: mutex_unlock(&pai_reserve_mutex); From a3f8423622ef34cca050816c49be4291f9f41b1d Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:46 +0100 Subject: [PATCH 07/23] s390/pai_crypto: Add PAI crypto characteristics table for parameters Create and add a PMU characteristics table to store the parameters of the PAI crypto PMU. This table contains PMU details such as - number of available counters - name of these counters to export to /sysfs - Size of the memory mapped counter area - base number of first counter - etc Also define a PMU specific initialization function to be called when a PAI PMU feature is supported. At device driver initialization test these features and if available use instruction qpaci to retrieve the number of available counters. Also export these counter names to /sysfs and register this PMU. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 198 +++++++++++++++++++++-------- 1 file changed, 143 insertions(+), 55 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 12f99028d5b8..36a99cdc3d37 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -25,6 +25,11 @@ static unsigned int paicrypt_cnt; /* Size of the mapped counter sets */ DEFINE_STATIC_KEY_FALSE(pai_key); +enum { + PAI_PMU_CRYPTO, /* Index of PMU pai_crypto */ + PAI_PMU_MAX /* # of PAI PMUs */ +}; + struct pai_userdata { u16 num; u64 value; @@ -48,6 +53,28 @@ static struct pai_root { /* Anchor to per CPU data */ struct pai_mapptr __percpu *mapptr; } pai_root; +/* This table defines the different parameters of the PAI PMUs. During + * initialization the machine dependent values are extracted and saved. + * However most of the values are static and do not change. + * There is one table entry per PAI PMU. + */ +struct pai_pmu { /* Define PAI PMU characteristics */ + const char *pmuname; /* Name of PMU */ + const int facility_nr; /* Facility number to check for support */ + unsigned int num_avail; /* # Counters defined by hardware */ + unsigned int num_named; /* # Counters known by name */ + unsigned long base; /* Counter set base number */ + unsigned long kernel_offset; /* Offset to kernel part in counter page */ + unsigned long area_size; /* Size of counter area */ + const char * const *names; /* List of counter names */ + struct pmu *pmu; /* Ptr to supporting PMU */ + int (*init)(struct pai_pmu *p); /* PMU support init function */ + void (*exit)(struct pai_pmu *p); /* PMU support exit function */ + struct attribute_group *event_group; /* Ptr to attribute of events */ +}; + +static struct pai_pmu pai_pmu[]; /* Forward declaration */ + /* Free per CPU data when the last event is removed. */ static void pai_root_free(void) { @@ -738,12 +765,12 @@ static const char * const paicrypt_ctrnames[] = { [172] = "PCKMO_ENCRYPT_AES_XTS_256", }; -static void __init attr_event_free(struct attribute **attrs, int num) +static void __init attr_event_free(struct attribute **attrs) { struct perf_pmu_events_attr *pa; - int i; + unsigned int i; - for (i = 0; i < num; i++) { + for (i = 0; attrs[i]; i++) { struct device_attribute *dap; dap = container_of(attrs[i], struct device_attribute, attr); @@ -753,89 +780,150 @@ static void __init attr_event_free(struct attribute **attrs, int num) kfree(attrs); } -static int __init attr_event_init_one(struct attribute **attrs, int num) +static struct attribute * __init attr_event_init_one(int num, + unsigned long base, + const char *name) { struct perf_pmu_events_attr *pa; - /* Index larger than array_size, no counter name available */ - if (num >= ARRAY_SIZE(paicrypt_ctrnames)) { - attrs[num] = NULL; - return 0; - } - pa = kzalloc(sizeof(*pa), GFP_KERNEL); if (!pa) - return -ENOMEM; + return NULL; sysfs_attr_init(&pa->attr.attr); - pa->id = PAI_CRYPTO_BASE + num; - pa->attr.attr.name = paicrypt_ctrnames[num]; + pa->id = base + num; + pa->attr.attr.name = name; pa->attr.attr.mode = 0444; pa->attr.show = cpumf_events_sysfs_show; pa->attr.store = NULL; - attrs[num] = &pa->attr.attr; - return 0; + return &pa->attr.attr; } -/* Create PMU sysfs event attributes on the fly. */ -static int __init attr_event_init(void) +static struct attribute ** __init attr_event_init(struct pai_pmu *p) { + unsigned int min_attr = min_t(unsigned int, p->num_named, p->num_avail); struct attribute **attrs; - int ret, i; + unsigned int i; - attrs = kmalloc_array(paicrypt_cnt + 2, sizeof(*attrs), GFP_KERNEL); + attrs = kmalloc_array(min_attr + 1, sizeof(*attrs), GFP_KERNEL | __GFP_ZERO); if (!attrs) - return -ENOMEM; - for (i = 0; i <= paicrypt_cnt; i++) { - ret = attr_event_init_one(attrs, i); - if (ret) { - attr_event_free(attrs, i); - return ret; + goto out; + for (i = 0; i < min_attr; i++) { + attrs[i] = attr_event_init_one(i, p->base, p->names[i]); + if (!attrs[i]) { + attr_event_free(attrs); + attrs = NULL; + goto out; } } attrs[i] = NULL; - paicrypt_events_group.attrs = attrs; - return 0; +out: + return attrs; +} + +static void __init pai_pmu_exit(struct pai_pmu *p) +{ + attr_event_free(p->event_group->attrs); + p->event_group->attrs = NULL; +} + +/* Add a PMU. Install its events and register the PMU device driver + * call back functions. + */ +static int __init pai_pmu_init(struct pai_pmu *p) +{ + int rc = -ENOMEM; + + + /* Export known PAI events */ + p->event_group->attrs = attr_event_init(p); + if (!p->event_group->attrs) { + pr_err("Creation of PMU %s /sysfs failed\n", p->pmuname); + goto out; + } + + rc = perf_pmu_register(p->pmu, p->pmuname, -1); + if (rc) { + pai_pmu_exit(p); + pr_err("Registering PMU %s failed with rc=%i\n", p->pmuname, + rc); + } +out: + return rc; +} + +/* PAI PMU characteristics table */ +static struct pai_pmu pai_pmu[] __refdata = { + [PAI_PMU_CRYPTO] = { + .pmuname = "pai_crypto", + .facility_nr = 196, + .num_named = ARRAY_SIZE(paicrypt_ctrnames), + .names = paicrypt_ctrnames, + .base = PAI_CRYPTO_BASE, + .kernel_offset = PAI_CRYPTO_KERNEL_OFFSET, + .area_size = PAGE_SIZE, + .init = pai_pmu_init, + .exit = pai_pmu_exit, + .pmu = &paicrypt, + .event_group = &paicrypt_events_group + } +}; + +/* + * Check if the PMU (via facility) is supported by machine. Try all of the + * supported PAI PMUs. + * Return number of successfully installed PMUs. + */ +static int __init paipmu_setup(void) +{ + struct qpaci_info_block ib; + int install_ok = 0, rc; + struct pai_pmu *p; + size_t i; + + for (i = 0; i < ARRAY_SIZE(pai_pmu); ++i) { + p = &pai_pmu[i]; + + if (!test_facility(p->facility_nr)) + continue; + + qpaci(&ib); + switch (i) { + case PAI_PMU_CRYPTO: + p->num_avail = ib.num_cc; + paicrypt_cnt = ib.num_cc; + if (p->num_avail >= PAI_CRYPTO_MAXCTR) { + pr_err("Too many PMU %s counters %d\n", + p->pmuname, p->num_avail); + continue; + } + break; + } + p->num_avail += 1; /* Add xxx_ALL event */ + if (p->init) { + rc = p->init(p); + if (!rc) + ++install_ok; + } + } + return install_ok; } static int __init paicrypt_init(void) { - struct qpaci_info_block ib; - int rc; - - if (!test_facility(196)) - return 0; - - qpaci(&ib); - paicrypt_cnt = ib.num_cc; - if (paicrypt_cnt == 0) - return 0; - if (paicrypt_cnt >= PAI_CRYPTO_MAXCTR) { - pr_err("Too many PMU pai_crypto counters %d\n", paicrypt_cnt); - return -E2BIG; - } - - rc = attr_event_init(); /* Export known PAI crypto events */ - if (rc) { - pr_err("Creation of PMU pai_crypto /sysfs failed\n"); - return rc; - } - /* Setup s390dbf facility */ - paidbg = debug_register(KMSG_COMPONENT, 2, 256, 128); + paidbg = debug_register(KMSG_COMPONENT, 32, 256, 128); if (!paidbg) { - pr_err("Registration of s390dbf pai_crypto failed\n"); + pr_err("Registration of s390dbf " KMSG_COMPONENT " failed\n"); return -ENOMEM; } debug_register_view(paidbg, &debug_sprintf_view); - rc = perf_pmu_register(&paicrypt, "pai_crypto", -1); - if (rc) { - pr_err("Registering the pai_crypto PMU failed with rc=%i\n", - rc); + if (!paipmu_setup()) { + /* No PMU registration, no need for debug buffer */ debug_unregister_view(paidbg, &debug_sprintf_view); debug_unregister(paidbg); - return rc; + return -ENODEV; } return 0; } From 413957980ac86d04afa6a634eaab1182dcd8c6c3 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:47 +0100 Subject: [PATCH 08/23] s390/pai_crypto: Introduce generic event init using pai_pmu[] To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rework PAI crypto event initialization. Add a common function for event initialization. It uses the PAI characteristics stored in the pai_pmu table instead of hardcoded values. Enlarge pai_event_valid() to check all event validation aspects. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/include/asm/pai.h | 1 + arch/s390/kernel/perf_pai_crypto.c | 63 +++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/arch/s390/include/asm/pai.h b/arch/s390/include/asm/pai.h index ebeabd0aaa51..534d0320e2aa 100644 --- a/arch/s390/include/asm/pai.h +++ b/arch/s390/include/asm/pai.h @@ -77,6 +77,7 @@ static __always_inline void pai_kernel_exit(struct pt_regs *regs) #define PAI_SAVE_AREA(x) ((x)->hw.event_base) #define PAI_CPU_MASK(x) ((x)->hw.addr_filters) +#define PAI_PMU_IDX(x) ((x)->hw.last_tag) #define PAI_SWLIST(x) (&(x)->hw.tp_list) #endif diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 36a99cdc3d37..163053cb61a6 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -204,11 +204,11 @@ static u64 paicrypt_getall(struct perf_event *event) * * Allocate the memory for the event. */ -static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) +static int pai_alloc_cpu(struct perf_event *event, int cpu) { + int rc, idx = PAI_PMU_IDX(event); struct pai_map *cpump = NULL; struct pai_mapptr *mp; - int rc; mutex_lock(&pai_reserve_mutex); /* Allocate root node */ @@ -229,7 +229,7 @@ static int paicrypt_alloc_cpu(struct perf_event *event, int cpu) */ mp->mapptr = cpump; cpump->area = (unsigned long *)get_zeroed_page(GFP_KERNEL); - cpump->save = kvmalloc_array(paicrypt_cnt + 1, + cpump->save = kvmalloc_array(pai_pmu[idx].num_avail + 1, sizeof(struct pai_userdata), GFP_KERNEL); if (!cpump->area || !cpump->save) { @@ -253,10 +253,11 @@ undo: } unlock: mutex_unlock(&pai_reserve_mutex); + /* If rc is non-zero, no increment of counter/sampler was done. */ return rc; } -static int paicrypt_alloc(struct perf_event *event) +static int pai_alloc(struct perf_event *event) { struct cpumask *maskptr; int cpu, rc = -ENOMEM; @@ -266,7 +267,7 @@ static int paicrypt_alloc(struct perf_event *event) goto out; for_each_online_cpu(cpu) { - rc = paicrypt_alloc_cpu(event, cpu); + rc = pai_alloc_cpu(event, cpu); if (rc) { for_each_cpu(cpu, maskptr) paicrypt_event_destroy_cpu(event, cpu); @@ -288,22 +289,38 @@ out: return rc; } -/* Might be called on different CPU than the one the event is intended for. */ -static int paicrypt_event_init(struct perf_event *event) +/* Validate event number and return error if event is not supported. + * On successful return, PAI_PMU_IDX(event) is set to the index of + * the supporting paing_support[] array element. + */ +static int pai_event_valid(struct perf_event *event, int idx) { struct perf_event_attr *a = &event->attr; - int rc = 0; + struct pai_pmu *pp = &pai_pmu[idx]; /* PAI crypto PMU registered as PERF_TYPE_RAW, check event type */ if (a->type != PERF_TYPE_RAW && event->pmu->type != a->type) return -ENOENT; - /* PAI crypto event must be in valid range, try others if not */ - if (a->config < PAI_CRYPTO_BASE || - a->config > PAI_CRYPTO_BASE + paicrypt_cnt) - return -ENOENT; - /* Allow only CRYPTO_ALL for sampling */ - if (a->sample_period && a->config != PAI_CRYPTO_BASE) + /* Allow only CRYPTO_ALL/NNPA_ALL for sampling */ + if (a->sample_period && a->config != pp->base) return -EINVAL; + /* PAI crypto event must be in valid range, try others if not */ + if (a->config < pp->base || a->config > pp->base + pp->num_avail) + return -ENOENT; + PAI_PMU_IDX(event) = idx; + return 0; +} + +/* Might be called on different CPU than the one the event is intended for. */ +static int pai_event_init(struct perf_event *event, int idx) +{ + struct perf_event_attr *a = &event->attr; + int rc; + + /* PAI event must be valid and in supported range */ + rc = pai_event_valid(event, idx); + if (rc) + goto out; /* Get a page to store last counter values for sampling */ if (a->sample_period) { PAI_SAVE_AREA(event) = get_zeroed_page(GFP_KERNEL); @@ -314,14 +331,13 @@ static int paicrypt_event_init(struct perf_event *event) } if (event->cpu >= 0) - rc = paicrypt_alloc_cpu(event, event->cpu); + rc = pai_alloc_cpu(event, event->cpu); else - rc = paicrypt_alloc(event); + rc = pai_alloc(event); if (rc) { free_page(PAI_SAVE_AREA(event)); goto out; } - event->destroy = paicrypt_event_destroy; if (a->sample_period) { a->sample_period = 1; @@ -333,12 +349,21 @@ static int paicrypt_event_init(struct perf_event *event) /* Turn off inheritance */ a->inherit = 0; } - - static_branch_inc(&pai_key); out: return rc; } +static int paicrypt_event_init(struct perf_event *event) +{ + int rc = pai_event_init(event, PAI_PMU_CRYPTO); + + if (!rc) { + event->destroy = paicrypt_event_destroy; + static_branch_inc(&pai_key); + } + return rc; +} + static void paicrypt_read(struct perf_event *event) { u64 prev, new, delta; From 65b9831bd3ced5acb0d4a0fad66f7585a3ad3db8 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:48 +0100 Subject: [PATCH 09/23] s390/pai_crypto: Rename some function for common usage. To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename functions - paicrypt_free() -> pai_free() - paicrypt_destroy_event() -> pai_destroy_event() - paicrypt_destroy_event_cpu() -> pai_destroy_event_cpu() to reflect their future common usage. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 163053cb61a6..4b4c22bf6171 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -108,7 +108,7 @@ static int pai_root_alloc(void) static DEFINE_MUTEX(pai_reserve_mutex); /* Free all memory allocated for event counting/sampling setup */ -static void paicrypt_free(struct pai_mapptr *mp) +static void pai_free(struct pai_mapptr *mp) { free_page((unsigned long)mp->mapptr->area); kvfree(mp->mapptr->save); @@ -119,7 +119,7 @@ static void paicrypt_free(struct pai_mapptr *mp) /* Adjust usage counters and remove allocated memory when all users are * gone. */ -static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) +static void pai_event_destroy_cpu(struct perf_event *event, int cpu) { struct pai_mapptr *mp = per_cpu_ptr(pai_root.mapptr, cpu); struct pai_map *cpump = mp->mapptr; @@ -130,12 +130,12 @@ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu) event->cpu, cpump->active_events, refcount_read(&cpump->refcnt)); if (refcount_dec_and_test(&cpump->refcnt)) - paicrypt_free(mp); + pai_free(mp); pai_root_free(); mutex_unlock(&pai_reserve_mutex); } -static void paicrypt_event_destroy(struct perf_event *event) +static void pai_event_destroy(struct perf_event *event) { int cpu; @@ -145,10 +145,10 @@ static void paicrypt_event_destroy(struct perf_event *event) struct cpumask *mask = PAI_CPU_MASK(event); for_each_cpu(cpu, mask) - paicrypt_event_destroy_cpu(event, cpu); + pai_event_destroy_cpu(event, cpu); kfree(mask); } else { - paicrypt_event_destroy_cpu(event, event->cpu); + pai_event_destroy_cpu(event, event->cpu); } } @@ -233,7 +233,7 @@ static int pai_alloc_cpu(struct perf_event *event, int cpu) sizeof(struct pai_userdata), GFP_KERNEL); if (!cpump->area || !cpump->save) { - paicrypt_free(mp); + pai_free(mp); goto undo; } INIT_LIST_HEAD(&cpump->syswide_list); @@ -270,7 +270,7 @@ static int pai_alloc(struct perf_event *event) rc = pai_alloc_cpu(event, cpu); if (rc) { for_each_cpu(cpu, maskptr) - paicrypt_event_destroy_cpu(event, cpu); + pai_event_destroy_cpu(event, cpu); kfree(maskptr); goto out; } @@ -280,7 +280,7 @@ static int pai_alloc(struct perf_event *event) /* * On error all cpumask are freed and all events have been destroyed. * Save of which CPUs data structures have been allocated for. - * Release them in paicrypt_event_destroy call back function + * Release them in pai_event_destroy call back function * for this event. */ PAI_CPU_MASK(event) = maskptr; @@ -358,7 +358,7 @@ static int paicrypt_event_init(struct perf_event *event) int rc = pai_event_init(event, PAI_PMU_CRYPTO); if (!rc) { - event->destroy = paicrypt_event_destroy; + event->destroy = pai_event_destroy; static_branch_inc(&pai_key); } return rc; From 42cd0c82422775e34528b9d0df438e51150a4db9 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:49 +0100 Subject: [PATCH 10/23] s390/pai_crypto: Rename paicrypt_getdata() to pai_getdata() To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename paicrypt_getdata() to pai_getdata(). Use the PAI PMU characteristics in the pai_pmu table to determine the number of counters to be extracted. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 4b4c22bf6171..8b3f6c624e81 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -159,23 +159,25 @@ static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) return page[nr]; } -/* Read the counter values. Return value from location in CMP. For event - * CRYPTO_ALL sum up all events. +/* Read the counter values. Return value from location in CMP. For base + * event xxx_ALL sum up all events. Returns counter value. */ -static u64 paicrypt_getdata(struct perf_event *event, bool kernel) +static u64 pai_getdata(struct perf_event *event, bool kernel) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; + int idx = PAI_PMU_IDX(event); + struct pai_pmu *pp = &pai_pmu[idx]; + unsigned int i; u64 sum = 0; - int i; - if (event->attr.config != PAI_CRYPTO_BASE) { + if (event->attr.config != pp->base) { return paicrypt_getctr(cpump->area, - event->attr.config - PAI_CRYPTO_BASE, + event->attr.config - pp->base, kernel); } - for (i = 1; i <= paicrypt_cnt; i++) { + for (i = 1; i <= pp->num_avail; i++) { u64 val = paicrypt_getctr(cpump->area, i, kernel); if (!val) @@ -190,9 +192,9 @@ static u64 paicrypt_getall(struct perf_event *event) u64 sum = 0; if (!event->attr.exclude_kernel) - sum += paicrypt_getdata(event, true); + sum += pai_getdata(event, true); if (!event->attr.exclude_user) - sum += paicrypt_getdata(event, false); + sum += pai_getdata(event, false); return sum; } From 360e180d8b5d448429079d2c541c1968f3b82790 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:50 +0100 Subject: [PATCH 11/23] s390/pai_crypto: Rename paicrypt_getctr() to pai_getctr() To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename paicrypt_getctr() to pai_getctr() to reflect is common purpose. pai_getctr() now uses pai_pmu table to extract PAI PMU characteristics such as kernel_offset inside the counter area page. Also rename paicrypt_have_sample() to pai_have_sample(). Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 8b3f6c624e81..33af05b91874 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -152,10 +152,10 @@ static void pai_event_destroy(struct perf_event *event) } } -static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) +static u64 pai_getctr(unsigned long *page, int nr, unsigned long offset) { - if (kernel) - nr += PAI_CRYPTO_MAXCTR; + if (offset) + nr += offset / sizeof(*page); return page[nr]; } @@ -172,13 +172,14 @@ static u64 pai_getdata(struct perf_event *event, bool kernel) u64 sum = 0; if (event->attr.config != pp->base) { - return paicrypt_getctr(cpump->area, + return pai_getctr(cpump->area, event->attr.config - pp->base, - kernel); + kernel ? pp->kernel_offset : 0); } for (i = 1; i <= pp->num_avail; i++) { - u64 val = paicrypt_getctr(cpump->area, i, kernel); + u64 val = pai_getctr(cpump->area, i, + kernel ? pp->kernel_offset : 0); if (!val) continue; @@ -416,7 +417,7 @@ static int paicrypt_add(struct perf_event *event, int flags) return 0; } -static void paicrypt_have_sample(struct perf_event *, struct pai_map *); +static void pai_have_sample(struct perf_event *, struct pai_map *); static void paicrypt_stop(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); @@ -429,7 +430,7 @@ static void paicrypt_stop(struct perf_event *event, int flags) perf_sched_cb_dec(event->pmu); list_del(PAI_SWLIST(event)); } else { - paicrypt_have_sample(event, cpump); + pai_have_sample(event, cpump); cpump->event = NULL; } } @@ -456,21 +457,21 @@ static void paicrypt_del(struct perf_event *event, int flags) * 8 bytes: Value of counter */ static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page, - unsigned long *page_old, bool exclude_user, - bool exclude_kernel) + struct pai_pmu *pp, unsigned long *page_old, + bool exclude_user, bool exclude_kernel) { int i, outidx = 0; - for (i = 1; i <= paicrypt_cnt; i++) { + for (i = 1; i <= pp->num_avail; i++) { u64 val = 0, val_old = 0; if (!exclude_kernel) { - val += paicrypt_getctr(page, i, true); - val_old += paicrypt_getctr(page_old, i, true); + val += pai_getctr(page, i, pp->kernel_offset); + val_old += pai_getctr(page_old, i, pp->kernel_offset); } if (!exclude_user) { - val += paicrypt_getctr(page, i, false); - val_old += paicrypt_getctr(page_old, i, false); + val += pai_getctr(page, i, 0); + val_old += pai_getctr(page_old, i, 0); } if (val >= val_old) val -= val_old; @@ -524,14 +525,15 @@ static int paicrypt_push_sample(size_t rawsize, struct pai_map *cpump, } /* Check if there is data to be saved on schedule out of a task. */ -static void paicrypt_have_sample(struct perf_event *event, - struct pai_map *cpump) +static void pai_have_sample(struct perf_event *event, struct pai_map *cpump) { + struct pai_pmu *pp; size_t rawsize; if (!event) /* No event active */ return; - rawsize = paicrypt_copy(cpump->save, cpump->area, + pp = &pai_pmu[PAI_PMU_IDX(event)]; + rawsize = paicrypt_copy(cpump->save, cpump->area, pp, (unsigned long *)PAI_SAVE_AREA(event), event->attr.exclude_user, event->attr.exclude_kernel); @@ -547,7 +549,7 @@ static void paicrypt_have_samples(void) struct perf_event *event; list_for_each_entry(event, &cpump->syswide_list, hw.tp_list) - paicrypt_have_sample(event, cpump); + pai_have_sample(event, cpump); } /* Called on schedule-in and schedule-out. No access to event structure, From 0f1c0d754ac9c27cfb21e2e10c95261b1459e212 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:51 +0100 Subject: [PATCH 12/23] s390/pai_crypto: Rename paicrypt_have_samples() to pai_have_samples() To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename paicrypt_have_samples() to pai_have_samples() to reflect its common usage. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 33af05b91874..f7d846262a5b 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -542,7 +542,7 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump) } /* Check if there is data to be saved on schedule out of a task. */ -static void paicrypt_have_samples(void) +static void pai_have_samples(void) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; @@ -562,7 +562,7 @@ static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, * results on schedule_out and if page was dirty, save old values. */ if (!sched_in) - paicrypt_have_samples(); + pai_have_samples(); } /* Attribute definitions for paicrypt interface. As with other CPU From 74466e87e7fae1e5d746037a3d0484fd0afb03b2 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:52 +0100 Subject: [PATCH 13/23] s390/pai_crypto: Unify sample push logic and update context handling Unify naming and logic for PAI PMU drivers to support both PMUs pai_crypto and pai_ext. Rename paicrypt_push_sample() to pai_push_sample() to reflect its common usage. Add detailed comments about invocation context and scheduler callbacks. Use struct pai_pmu to determine area_size instead of PAGE_SIZE for counter backup. Remove obsolete variable paicrypt_cnt. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index f7d846262a5b..59b18f86b8ae 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -20,8 +20,6 @@ #include static debug_info_t *paidbg; -static unsigned int paicrypt_cnt; /* Size of the mapped counter sets */ - /* extracted with QPACI instruction */ DEFINE_STATIC_KEY_FALSE(pai_key); @@ -486,9 +484,25 @@ static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page, return outidx * sizeof(*userdata); } -static int paicrypt_push_sample(size_t rawsize, struct pai_map *cpump, - struct perf_event *event) +/* Write sample when one or more counters values are nonzero. + * + * Note: The function paicrypt_sched_task() and pai_push_sample() are not + * invoked after function paicrypt_del() has been called because of function + * perf_sched_cb_dec(). Both functions are only + * called when sampling is active. Function perf_sched_cb_inc() + * has been invoked to install function paicrypt_sched_task() as call back + * to run at context switch time. + * + * This causes function perf_event_context_sched_out() and + * perf_event_context_sched_in() to check whether the PMU has installed an + * sched_task() callback. That callback is not active after paicrypt_del() + * returns and has deleted the event on that CPU. + */ +static int pai_push_sample(size_t rawsize, struct pai_map *cpump, + struct perf_event *event) { + int idx = PAI_PMU_IDX(event); + struct pai_pmu *pp = &pai_pmu[idx]; struct perf_sample_data data; struct perf_raw_record raw; struct pt_regs regs; @@ -520,7 +534,7 @@ static int paicrypt_push_sample(size_t rawsize, struct pai_map *cpump, overflow = perf_event_overflow(event, &data, ®s); perf_event_update_userpage(event); /* Save crypto counter lowcore page after reading event data. */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->area, PAGE_SIZE); + memcpy((void *)PAI_SAVE_AREA(event), cpump->area, pp->area_size); return overflow; } @@ -538,7 +552,7 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump) event->attr.exclude_user, event->attr.exclude_kernel); if (rawsize) /* No incremented counters */ - paicrypt_push_sample(rawsize, cpump, event); + pai_push_sample(rawsize, cpump, event); } /* Check if there is data to be saved on schedule out of a task. */ @@ -920,7 +934,6 @@ static int __init paipmu_setup(void) switch (i) { case PAI_PMU_CRYPTO: p->num_avail = ib.num_cc; - paicrypt_cnt = ib.num_cc; if (p->num_avail >= PAI_CRYPTO_MAXCTR) { pr_err("Too many PMU %s counters %d\n", p->pmuname, p->num_avail); From 8f6116fd4940ad60adbfaca3525567b087054b5b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:53 +0100 Subject: [PATCH 14/23] s390/pai_crypto: Add common pai_read() function To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Add a common usable function pai_read() to read counter values. The function expects a PAI PMU specific read function as second parameter. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 59b18f86b8ae..4eb1a09c36bd 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -365,18 +365,23 @@ static int paicrypt_event_init(struct perf_event *event) return rc; } -static void paicrypt_read(struct perf_event *event) +static void pai_read(struct perf_event *event, + u64 (*fct)(struct perf_event *event)) { u64 prev, new, delta; prev = local64_read(&event->hw.prev_count); - new = paicrypt_getall(event); + new = fct(event); local64_set(&event->hw.prev_count, new); - delta = (prev <= new) ? new - prev - : (-1ULL - prev) + new + 1; /* overflow */ + delta = (prev <= new) ? new - prev : (-1ULL - prev) + new + 1; local64_add(delta, &event->count); } +static void paicrypt_read(struct perf_event *event) +{ + pai_read(event, paicrypt_getall); +} + static void paicrypt_start(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); From 6fe66b21570f138017ee493b72cd4f724c8f1df1 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:54 +0100 Subject: [PATCH 15/23] s390/pai_crypto: Add common pai_start() function To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Add a common usable function pai_start() to the event on a CPU. The function expects a PAI PMU specific read function as second parameter to read out the start value for an event. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 4eb1a09c36bd..e7f225764126 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -382,17 +382,20 @@ static void paicrypt_read(struct perf_event *event) pai_read(event, paicrypt_getall); } -static void paicrypt_start(struct perf_event *event, int flags) +static void pai_start(struct perf_event *event, int flags, + u64 (*fct)(struct perf_event *event)) { + int idx = PAI_PMU_IDX(event); + struct pai_pmu *pp = &pai_pmu[idx]; struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; u64 sum; if (!event->attr.sample_period) { /* Counting */ - sum = paicrypt_getall(event); /* Get current value */ + sum = fct(event); /* Get current value */ local64_set(&event->hw.prev_count, sum); } else { /* Sampling */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->area, PAGE_SIZE); + memcpy((void *)PAI_SAVE_AREA(event), cpump->area, pp->area_size); /* Enable context switch callback for system-wide sampling */ if (!(event->attach_state & PERF_ATTACH_TASK)) { list_add_tail(PAI_SWLIST(event), &cpump->syswide_list); @@ -403,6 +406,11 @@ static void paicrypt_start(struct perf_event *event, int flags) } } +static void paicrypt_start(struct perf_event *event, int flags) +{ + pai_start(event, flags, paicrypt_getall); +} + static int paicrypt_add(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); From a65a4d7e806402e394b1ef0323aafec23903888b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:55 +0100 Subject: [PATCH 16/23] s390/pai_crypto: Add common pai_add() function To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Add a common usable function pai_add() for the event on a CPU. Call this common pai_add() from paicrypt_add(). Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index e7f225764126..73a55ddedc80 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -411,10 +411,11 @@ static void paicrypt_start(struct perf_event *event, int flags) pai_start(event, flags, paicrypt_getall); } -static int paicrypt_add(struct perf_event *event, int flags) +static int pai_add(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; + int idx = PAI_PMU_IDX(event); unsigned long ccd; if (++cpump->active_events == 1) { @@ -423,11 +424,16 @@ static int paicrypt_add(struct perf_event *event, int flags) local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); } if (flags & PERF_EF_START) - paicrypt_start(event, PERF_EF_RELOAD); + pai_pmu[idx].pmu->start(event, PERF_EF_RELOAD); event->hw.state = 0; return 0; } +static int paicrypt_add(struct perf_event *event, int flags) +{ + return pai_add(event, flags); +} + static void pai_have_sample(struct perf_event *, struct pai_map *); static void paicrypt_stop(struct perf_event *event, int flags) { From ac03223f0723cf7ee11171be963f19958a91f7b3 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:56 +0100 Subject: [PATCH 17/23] s390/pai_crypto: Add common pai_stop() function To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Add a common usable function pai_stop() for the event on a CPU. Call this common pai_stop() from paicrypt_del(). Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 73a55ddedc80..5d4b9ffe3cb1 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -435,13 +435,14 @@ static int paicrypt_add(struct perf_event *event, int flags) } static void pai_have_sample(struct perf_event *, struct pai_map *); -static void paicrypt_stop(struct perf_event *event, int flags) +static void pai_stop(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; + int idx = PAI_PMU_IDX(event); if (!event->attr.sample_period) { /* Counting */ - paicrypt_read(event); + pai_pmu[idx].pmu->read(event); } else { /* Sampling */ if (!(event->attach_state & PERF_ATTACH_TASK)) { perf_sched_cb_dec(event->pmu); @@ -454,6 +455,11 @@ static void paicrypt_stop(struct perf_event *event, int flags) event->hw.state = PERF_HES_STOPPED; } +static void paicrypt_stop(struct perf_event *event, int flags) +{ + pai_stop(event, flags); +} + static void paicrypt_del(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); From 42e6a0f6d2f0e9ac96d0d6045624a1fa44ab6871 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:57 +0100 Subject: [PATCH 18/23] s390/pai_crypto: Add common pai_del() function To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Add a common usable function pai_stop() for the event on a CPU. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 5d4b9ffe3cb1..a014f4a1b443 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -460,18 +460,24 @@ static void paicrypt_stop(struct perf_event *event, int flags) pai_stop(event, flags); } -static void paicrypt_del(struct perf_event *event, int flags) +static void pai_del(struct perf_event *event, int flags) { struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); struct pai_map *cpump = mp->mapptr; + int idx = PAI_PMU_IDX(event); - paicrypt_stop(event, PERF_EF_UPDATE); + pai_pmu[idx].pmu->stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { local_ctl_clear_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); WRITE_ONCE(get_lowcore()->ccd, 0); } } +static void paicrypt_del(struct perf_event *event, int flags) +{ + pai_del(event, flags); +} + /* Create raw data and save it in buffer. Calculate the delta for each * counter between this invocation and the last invocation. * Returns number of bytes copied. From f12473541356f5765e4130a7b5af77862a872a51 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:58 +0100 Subject: [PATCH 19/23] s390/pai_crypto: Rename paicrypt_copy() to pai_copy() To support one common PAI PMU device driver which handles both PMUs pai_crypto and pai_ext, use a common naming scheme for structures and variables suitable for both device drivers. Rename paicrypt_copy() to pai_copy() to indicate its common usage. No functional change. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index a014f4a1b443..870b84b0ce5f 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -485,9 +485,9 @@ static void paicrypt_del(struct perf_event *event, int flags) * 2 bytes: Number of counter * 8 bytes: Value of counter */ -static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page, - struct pai_pmu *pp, unsigned long *page_old, - bool exclude_user, bool exclude_kernel) +static size_t pai_copy(struct pai_userdata *userdata, unsigned long *page, + struct pai_pmu *pp, unsigned long *page_old, + bool exclude_user, bool exclude_kernel) { int i, outidx = 0; @@ -578,10 +578,10 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump) if (!event) /* No event active */ return; pp = &pai_pmu[PAI_PMU_IDX(event)]; - rawsize = paicrypt_copy(cpump->save, cpump->area, pp, - (unsigned long *)PAI_SAVE_AREA(event), - event->attr.exclude_user, - event->attr.exclude_kernel); + rawsize = pai_copy(cpump->save, cpump->area, pp, + (unsigned long *)PAI_SAVE_AREA(event), + event->attr.exclude_user, + event->attr.exclude_kernel); if (rawsize) /* No incremented counters */ pai_push_sample(rawsize, cpump, event); } From 35a27bad075d594ebaabc62f94b665fa2a135433 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:38:59 +0100 Subject: [PATCH 20/23] s390/pai_crypto: Make pai_root per-PMU and unify naming Prepare the common PAI PMU driver to handle multiple PMUs. Convert pai_root into an array indexed by PAI_PMU_IDX(event) so that per-CPU state becomes per-PMU. Adjust all call sites accordingly. Rename KMSG_COMPONENT and the s390dbf buffer from "pai_crypto" to "pai" for consistent naming. No functional change intended beyond log identifiers. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 71 +++++++++++++++--------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 870b84b0ce5f..94551b3d09f3 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -2,10 +2,10 @@ /* * Performance event support - Processor Activity Instrumentation Facility * - * Copyright IBM Corp. 2022 + * Copyright IBM Corp. 2026 * Author(s): Thomas Richter */ -#define KMSG_COMPONENT "pai_crypto" +#define KMSG_COMPONENT "pai" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include @@ -49,7 +49,7 @@ struct pai_mapptr { static struct pai_root { /* Anchor to per CPU data */ refcount_t refcnt; /* Overall active events */ struct pai_mapptr __percpu *mapptr; -} pai_root; +} pai_root[PAI_PMU_MAX]; /* This table defines the different parameters of the PAI PMUs. During * initialization the machine dependent values are extracted and saved. @@ -74,14 +74,14 @@ struct pai_pmu { /* Define PAI PMU characteristics */ static struct pai_pmu pai_pmu[]; /* Forward declaration */ /* Free per CPU data when the last event is removed. */ -static void pai_root_free(void) +static void pai_root_free(int idx) { - if (refcount_dec_and_test(&pai_root.refcnt)) { - free_percpu(pai_root.mapptr); - pai_root.mapptr = NULL; + if (refcount_dec_and_test(&pai_root[idx].refcnt)) { + free_percpu(pai_root[idx].mapptr); + pai_root[idx].mapptr = NULL; } - debug_sprintf_event(paidbg, 5, "%s root.refcount %d\n", __func__, - refcount_read(&pai_root.refcnt)); + debug_sprintf_event(paidbg, 5, "%s root[%d].refcount %d\n", __func__, + idx, refcount_read(&pai_root[idx].refcnt)); } /* @@ -90,14 +90,14 @@ static void pai_root_free(void) * CPUs possible, which might be larger than the number of CPUs currently * online. */ -static int pai_root_alloc(void) +static int pai_root_alloc(int idx) { - if (!refcount_inc_not_zero(&pai_root.refcnt)) { + if (!refcount_inc_not_zero(&pai_root[idx].refcnt)) { /* The memory is already zeroed. */ - pai_root.mapptr = alloc_percpu(struct pai_mapptr); - if (!pai_root.mapptr) + pai_root[idx].mapptr = alloc_percpu(struct pai_mapptr); + if (!pai_root[idx].mapptr) return -ENOMEM; - refcount_set(&pai_root.refcnt, 1); + refcount_set(&pai_root[idx].refcnt, 1); } return 0; } @@ -119,17 +119,18 @@ static void pai_free(struct pai_mapptr *mp) */ static void pai_event_destroy_cpu(struct perf_event *event, int cpu) { - struct pai_mapptr *mp = per_cpu_ptr(pai_root.mapptr, cpu); + int idx = PAI_PMU_IDX(event); + struct pai_mapptr *mp = per_cpu_ptr(pai_root[idx].mapptr, cpu); struct pai_map *cpump = mp->mapptr; mutex_lock(&pai_reserve_mutex); - debug_sprintf_event(paidbg, 5, "%s event %#llx cpu %d users %d " - "refcnt %u\n", __func__, event->attr.config, + debug_sprintf_event(paidbg, 5, "%s event %#llx idx %d cpu %d users %d " + "refcnt %u\n", __func__, event->attr.config, idx, event->cpu, cpump->active_events, refcount_read(&cpump->refcnt)); if (refcount_dec_and_test(&cpump->refcnt)) pai_free(mp); - pai_root_free(); + pai_root_free(idx); mutex_unlock(&pai_reserve_mutex); } @@ -162,10 +163,10 @@ static u64 pai_getctr(unsigned long *page, int nr, unsigned long offset) */ static u64 pai_getdata(struct perf_event *event, bool kernel) { - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); - struct pai_map *cpump = mp->mapptr; int idx = PAI_PMU_IDX(event); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); struct pai_pmu *pp = &pai_pmu[idx]; + struct pai_map *cpump = mp->mapptr; unsigned int i; u64 sum = 0; @@ -213,12 +214,12 @@ static int pai_alloc_cpu(struct perf_event *event, int cpu) mutex_lock(&pai_reserve_mutex); /* Allocate root node */ - rc = pai_root_alloc(); + rc = pai_root_alloc(idx); if (rc) goto unlock; /* Allocate node for this event */ - mp = per_cpu_ptr(pai_root.mapptr, cpu); + mp = per_cpu_ptr(pai_root[idx].mapptr, cpu); cpump = mp->mapptr; if (!cpump) { /* Paicrypt_map allocated? */ rc = -ENOMEM; @@ -250,7 +251,7 @@ undo: * the event in not created, its destroy() function is never * invoked. Adjust the reference counter for the anchor. */ - pai_root_free(); + pai_root_free(idx); } unlock: mutex_unlock(&pai_reserve_mutex); @@ -387,7 +388,7 @@ static void pai_start(struct perf_event *event, int flags, { int idx = PAI_PMU_IDX(event); struct pai_pmu *pp = &pai_pmu[idx]; - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); struct pai_map *cpump = mp->mapptr; u64 sum; @@ -413,9 +414,9 @@ static void paicrypt_start(struct perf_event *event, int flags) static int pai_add(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); - struct pai_map *cpump = mp->mapptr; int idx = PAI_PMU_IDX(event); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); + struct pai_map *cpump = mp->mapptr; unsigned long ccd; if (++cpump->active_events == 1) { @@ -437,9 +438,9 @@ static int paicrypt_add(struct perf_event *event, int flags) static void pai_have_sample(struct perf_event *, struct pai_map *); static void pai_stop(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); - struct pai_map *cpump = mp->mapptr; int idx = PAI_PMU_IDX(event); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); + struct pai_map *cpump = mp->mapptr; if (!event->attr.sample_period) { /* Counting */ pai_pmu[idx].pmu->read(event); @@ -462,9 +463,9 @@ static void paicrypt_stop(struct perf_event *event, int flags) static void pai_del(struct perf_event *event, int flags) { - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); - struct pai_map *cpump = mp->mapptr; int idx = PAI_PMU_IDX(event); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); + struct pai_map *cpump = mp->mapptr; pai_pmu[idx].pmu->stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { @@ -587,9 +588,9 @@ static void pai_have_sample(struct perf_event *event, struct pai_map *cpump) } /* Check if there is data to be saved on schedule out of a task. */ -static void pai_have_samples(void) +static void pai_have_samples(int idx) { - struct pai_mapptr *mp = this_cpu_ptr(pai_root.mapptr); + struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); struct pai_map *cpump = mp->mapptr; struct perf_event *event; @@ -607,7 +608,7 @@ static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, * results on schedule_out and if page was dirty, save old values. */ if (!sched_in) - pai_have_samples(); + pai_have_samples(PAI_PMU_CRYPTO); } /* Attribute definitions for paicrypt interface. As with other CPU @@ -982,7 +983,7 @@ static int __init paipmu_setup(void) return install_ok; } -static int __init paicrypt_init(void) +static int __init pai_init(void) { /* Setup s390dbf facility */ paidbg = debug_register(KMSG_COMPONENT, 32, 256, 128); @@ -1001,4 +1002,4 @@ static int __init paicrypt_init(void) return 0; } -device_initcall(paicrypt_init); +device_initcall(pai_init); From 3abb6b16758045b44d5fdf50915befa6744eaaca Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:39:00 +0100 Subject: [PATCH 21/23] s390/pai_crypto: Introduce PAI crypto specific event delete function Introduce PAI crypto specific event delete function to handle additional actions to be done at event removal. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/perf_pai_crypto.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 94551b3d09f3..f2d7f8bc0319 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -138,7 +138,6 @@ static void pai_event_destroy(struct perf_event *event) { int cpu; - static_branch_dec(&pai_key); free_page(PAI_SAVE_AREA(event)); if (event->cpu == -1) { struct cpumask *mask = PAI_CPU_MASK(event); @@ -151,6 +150,12 @@ static void pai_event_destroy(struct perf_event *event) } } +static void paicrypt_event_destroy(struct perf_event *event) +{ + static_branch_dec(&pai_key); + pai_event_destroy(event); +} + static u64 pai_getctr(unsigned long *page, int nr, unsigned long offset) { if (offset) @@ -360,7 +365,7 @@ static int paicrypt_event_init(struct perf_event *event) int rc = pai_event_init(event, PAI_PMU_CRYPTO); if (!rc) { - event->destroy = pai_event_destroy; + event->destroy = paicrypt_event_destroy; static_branch_inc(&pai_key); } return rc; From 8b65b0ba3541c738af671377872270af6ee6a8ac Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:39:01 +0100 Subject: [PATCH 22/23] s390/pai_crypto: Merge pai_ext PMU into pai_crypto Combine PAI cryptography and PAI extension (NNPA) PMUs in one driver. Remove file perf_pai_ext.c and registration of PMU "pai_ext" from perf_pai_crypto.c. Includes: - Shared alloc/free and sched_task handling - NNPA events with exclude_kernel enforced, exclude_user rejected - Setup CR0 bits for both PMUs Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/perf_pai_crypto.c | 237 ++++++++- arch/s390/kernel/perf_pai_ext.c | 756 ----------------------------- 3 files changed, 230 insertions(+), 765 deletions(-) delete mode 100644 arch/s390/kernel/perf_pai_ext.c diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index eb06ff888314..558f7c5bfe32 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_arch.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o -obj-$(CONFIG_PERF_EVENTS) += perf_pai_crypto.o perf_pai_ext.o +obj-$(CONFIG_PERF_EVENTS) += perf_pai_crypto.o obj-$(CONFIG_TRACEPOINTS) += trace.o diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index f2d7f8bc0319..1fac41a0aa09 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -25,14 +25,32 @@ DEFINE_STATIC_KEY_FALSE(pai_key); enum { PAI_PMU_CRYPTO, /* Index of PMU pai_crypto */ + PAI_PMU_EXT, /* Index of PMU pai_ext */ PAI_PMU_MAX /* # of PAI PMUs */ }; +enum { + PAIE1_CB_SZ = 0x200, /* Size of PAIE1 control block */ + PAIE1_CTRBLOCK_SZ = 0x400 /* Size of PAIE1 counter blocks */ +}; + struct pai_userdata { u16 num; u64 value; } __packed; +/* Create the PAI extension 1 control block area. + * The PAI extension control block 1 is pointed to by lowcore + * address 0x1508 for each CPU. This control block is 512 bytes in size + * and requires a 512 byte boundary alignment. + */ +struct paiext_cb { /* PAI extension 1 control block */ + u64 header; /* Not used */ + u64 reserved1; + u64 acc; /* Addr to analytics counter control block */ + u8 reserved2[488]; +} __packed; + struct pai_map { unsigned long *area; /* Area for CPU to store counters */ struct pai_userdata *save; /* Page to store no-zero counters */ @@ -40,6 +58,8 @@ struct pai_map { refcount_t refcnt; /* Reference count mapped buffers */ struct perf_event *event; /* Perf event for sampling */ struct list_head syswide_list; /* List system-wide sampling events */ + struct paiext_cb *paiext_cb; /* PAI extension control block area */ + bool fullpage; /* True: counter area is a full page */ }; struct pai_mapptr { @@ -108,7 +128,11 @@ static DEFINE_MUTEX(pai_reserve_mutex); /* Free all memory allocated for event counting/sampling setup */ static void pai_free(struct pai_mapptr *mp) { - free_page((unsigned long)mp->mapptr->area); + if (mp->mapptr->fullpage) + free_page((unsigned long)mp->mapptr->area); + else + kfree(mp->mapptr->area); + kfree(mp->mapptr->paiext_cb); kvfree(mp->mapptr->save); kfree(mp->mapptr); mp->mapptr = NULL; @@ -215,6 +239,7 @@ static int pai_alloc_cpu(struct perf_event *event, int cpu) { int rc, idx = PAI_PMU_IDX(event); struct pai_map *cpump = NULL; + bool need_paiext_cb = false; struct pai_mapptr *mp; mutex_lock(&pai_reserve_mutex); @@ -235,11 +260,33 @@ static int pai_alloc_cpu(struct perf_event *event, int cpu) * Only the first counting event has to allocate a page. */ mp->mapptr = cpump; - cpump->area = (unsigned long *)get_zeroed_page(GFP_KERNEL); + if (idx == PAI_PMU_CRYPTO) { + cpump->area = (unsigned long *)get_zeroed_page(GFP_KERNEL); + /* free_page() can handle 0x0 address */ + cpump->fullpage = true; + } else { /* PAI_PMU_EXT */ + /* + * Allocate memory for counter area and counter extraction. + * These are + * - a 512 byte block and requires 512 byte boundary + * alignment. + * - a 1KB byte block and requires 1KB boundary + * alignment. + * Only the first counting event has to allocate the area. + * + * Note: This works with commit 59bb47985c1d by default. + * Backporting this to kernels without this commit might + * needs adjustment. + */ + cpump->area = kzalloc(pai_pmu[idx].area_size, GFP_KERNEL); + cpump->paiext_cb = kzalloc(PAIE1_CB_SZ, GFP_KERNEL); + need_paiext_cb = true; + } cpump->save = kvmalloc_array(pai_pmu[idx].num_avail + 1, sizeof(struct pai_userdata), GFP_KERNEL); - if (!cpump->area || !cpump->save) { + if (!cpump->area || !cpump->save || + (need_paiext_cb && !cpump->paiext_cb)) { pai_free(mp); goto undo; } @@ -314,6 +361,8 @@ static int pai_event_valid(struct perf_event *event, int idx) /* PAI crypto event must be in valid range, try others if not */ if (a->config < pp->base || a->config > pp->base + pp->num_avail) return -ENOENT; + if (idx == PAI_PMU_EXT && a->exclude_user) + return -EINVAL; PAI_PMU_IDX(event) = idx; return 0; } @@ -422,12 +471,21 @@ static int pai_add(struct perf_event *event, int flags) int idx = PAI_PMU_IDX(event); struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); struct pai_map *cpump = mp->mapptr; + struct paiext_cb *pcb = cpump->paiext_cb; unsigned long ccd; if (++cpump->active_events == 1) { - ccd = virt_to_phys(cpump->area) | PAI_CRYPTO_KERNEL_OFFSET; - WRITE_ONCE(get_lowcore()->ccd, ccd); - local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); + if (!pcb) { /* PAI crypto */ + ccd = virt_to_phys(cpump->area) | PAI_CRYPTO_KERNEL_OFFSET; + WRITE_ONCE(get_lowcore()->ccd, ccd); + local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); + } else { /* PAI extension 1 */ + ccd = virt_to_phys(pcb); + WRITE_ONCE(get_lowcore()->aicd, ccd); + pcb->acc = virt_to_phys(cpump->area) | 0x1; + /* Enable CPU instruction lookup for PAIE1 control block */ + local_ctl_set_bit(0, CR0_PAI_EXTENSION_BIT); + } } if (flags & PERF_EF_START) pai_pmu[idx].pmu->start(event, PERF_EF_RELOAD); @@ -471,11 +529,19 @@ static void pai_del(struct perf_event *event, int flags) int idx = PAI_PMU_IDX(event); struct pai_mapptr *mp = this_cpu_ptr(pai_root[idx].mapptr); struct pai_map *cpump = mp->mapptr; + struct paiext_cb *pcb = cpump->paiext_cb; pai_pmu[idx].pmu->stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { - local_ctl_clear_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); - WRITE_ONCE(get_lowcore()->ccd, 0); + if (!pcb) { /* PAI crypto */ + local_ctl_clear_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); + WRITE_ONCE(get_lowcore()->ccd, 0); + } else { /* PAI extension 1 */ + /* Disable CPU instruction lookup for PAIE1 control block */ + local_ctl_clear_bit(0, CR0_PAI_EXTENSION_BIT); + pcb->acc = 0; + WRITE_ONCE(get_lowcore()->aicd, 0); + } } } @@ -616,6 +682,70 @@ static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, pai_have_samples(PAI_PMU_CRYPTO); } +/* ============================= paiext ====================================*/ + +static void paiext_event_destroy(struct perf_event *event) +{ + pai_event_destroy(event); +} + +/* Might be called on different CPU than the one the event is intended for. */ +static int paiext_event_init(struct perf_event *event) +{ + int rc = pai_event_init(event, PAI_PMU_EXT); + + if (!rc) { + event->attr.exclude_kernel = true; /* No kernel space part */ + event->destroy = paiext_event_destroy; + /* Offset of NNPA in paiext_cb */ + event->hw.config_base = offsetof(struct paiext_cb, acc); + } + return rc; +} + +static u64 paiext_getall(struct perf_event *event) +{ + return pai_getdata(event, false); +} + +static void paiext_read(struct perf_event *event) +{ + pai_read(event, paiext_getall); +} + +static void paiext_start(struct perf_event *event, int flags) +{ + pai_start(event, flags, paiext_getall); +} + +static int paiext_add(struct perf_event *event, int flags) +{ + return pai_add(event, flags); +} + +static void paiext_stop(struct perf_event *event, int flags) +{ + pai_stop(event, flags); +} + +static void paiext_del(struct perf_event *event, int flags) +{ + pai_del(event, flags); +} + +/* Called on schedule-in and schedule-out. No access to event structure, + * but for sampling only event NNPA_ALL is allowed. + */ +static void paiext_sched_task(struct perf_event_pmu_context *pmu_ctx, + struct task_struct *task, bool sched_in) +{ + /* We started with a clean page on event installation. So read out + * results on schedule_out and if page was dirty, save old values. + */ + if (!sched_in) + pai_have_samples(PAI_PMU_EXT); +} + /* Attribute definitions for paicrypt interface. As with other CPU * Measurement Facilities, there is one attribute per mapped counter. * The number of mapped counters may vary per machine generation. Use @@ -845,6 +975,81 @@ static const char * const paicrypt_ctrnames[] = { [172] = "PCKMO_ENCRYPT_AES_XTS_256", }; +static struct attribute *paiext_format_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group paiext_events_group = { + .name = "events", + .attrs = NULL, /* Filled in attr_event_init() */ +}; + +static struct attribute_group paiext_format_group = { + .name = "format", + .attrs = paiext_format_attr, +}; + +static const struct attribute_group *paiext_attr_groups[] = { + &paiext_events_group, + &paiext_format_group, + NULL, +}; + +/* Performance monitoring unit for mapped counters */ +static struct pmu paiext = { + .task_ctx_nr = perf_hw_context, + .event_init = paiext_event_init, + .add = paiext_add, + .del = paiext_del, + .start = paiext_start, + .stop = paiext_stop, + .read = paiext_read, + .sched_task = paiext_sched_task, + .attr_groups = paiext_attr_groups, +}; + +/* List of symbolic PAI extension 1 NNPA counter names. */ +static const char * const paiext_ctrnames[] = { + [0] = "NNPA_ALL", + [1] = "NNPA_ADD", + [2] = "NNPA_SUB", + [3] = "NNPA_MUL", + [4] = "NNPA_DIV", + [5] = "NNPA_MIN", + [6] = "NNPA_MAX", + [7] = "NNPA_LOG", + [8] = "NNPA_EXP", + [9] = "NNPA_IBM_RESERVED_9", + [10] = "NNPA_RELU", + [11] = "NNPA_TANH", + [12] = "NNPA_SIGMOID", + [13] = "NNPA_SOFTMAX", + [14] = "NNPA_BATCHNORM", + [15] = "NNPA_MAXPOOL2D", + [16] = "NNPA_AVGPOOL2D", + [17] = "NNPA_LSTMACT", + [18] = "NNPA_GRUACT", + [19] = "NNPA_CONVOLUTION", + [20] = "NNPA_MATMUL_OP", + [21] = "NNPA_MATMUL_OP_BCAST23", + [22] = "NNPA_SMALLBATCH", + [23] = "NNPA_LARGEDIM", + [24] = "NNPA_SMALLTENSOR", + [25] = "NNPA_1MFRAME", + [26] = "NNPA_2GFRAME", + [27] = "NNPA_ACCESSEXCEPT", + [28] = "NNPA_TRANSFORM", + [29] = "NNPA_GELU", + [30] = "NNPA_MOMENTS", + [31] = "NNPA_LAYERNORM", + [32] = "NNPA_MATMUL_OP_BCAST1", + [33] = "NNPA_SQRT", + [34] = "NNPA_INVSQRT", + [35] = "NNPA_NORM", + [36] = "NNPA_REDUCE", +}; + static void __init attr_event_free(struct attribute **attrs) { struct perf_pmu_events_attr *pa; @@ -946,6 +1151,19 @@ static struct pai_pmu pai_pmu[] __refdata = { .exit = pai_pmu_exit, .pmu = &paicrypt, .event_group = &paicrypt_events_group + }, + [PAI_PMU_EXT] = { + .pmuname = "pai_ext", + .facility_nr = 197, + .num_named = ARRAY_SIZE(paiext_ctrnames), + .names = paiext_ctrnames, + .base = PAI_NNPA_BASE, + .kernel_offset = 0, + .area_size = PAIE1_CTRBLOCK_SZ, + .init = pai_pmu_init, + .exit = pai_pmu_exit, + .pmu = &paiext, + .event_group = &paiext_events_group } }; @@ -977,6 +1195,9 @@ static int __init paipmu_setup(void) continue; } break; + case PAI_PMU_EXT: + p->num_avail = ib.num_nnpa; + break; } p->num_avail += 1; /* Add xxx_ALL event */ if (p->init) { diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c deleted file mode 100644 index 7b32935273ce..000000000000 --- a/arch/s390/kernel/perf_pai_ext.c +++ /dev/null @@ -1,756 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Performance event support - Processor Activity Instrumentation Extension - * Facility - * - * Copyright IBM Corp. 2022 - * Author(s): Thomas Richter - */ -#define KMSG_COMPONENT "pai_ext" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PAIE1_CB_SZ 0x200 /* Size of PAIE1 control block */ -#define PAIE1_CTRBLOCK_SZ 0x400 /* Size of PAIE1 counter blocks */ - -static debug_info_t *paiext_dbg; -static unsigned int paiext_cnt; /* Extracted with QPACI instruction */ - -struct pai_userdata { - u16 num; - u64 value; -} __packed; - -/* Create the PAI extension 1 control block area. - * The PAI extension control block 1 is pointed to by lowcore - * address 0x1508 for each CPU. This control block is 512 bytes in size - * and requires a 512 byte boundary alignment. - */ -struct paiext_cb { /* PAI extension 1 control block */ - u64 header; /* Not used */ - u64 reserved1; - u64 acc; /* Addr to analytics counter control block */ - u8 reserved2[488]; -} __packed; - -struct paiext_map { - unsigned long *area; /* Area for CPU to store counters */ - struct pai_userdata *save; /* Area to store non-zero counters */ - unsigned int active_events; /* # of PAI Extension users */ - refcount_t refcnt; - struct perf_event *event; /* Perf event for sampling */ - struct paiext_cb *paiext_cb; /* PAI extension control block area */ - struct list_head syswide_list; /* List system-wide sampling events */ -}; - -struct paiext_mapptr { - struct paiext_map *mapptr; -}; - -static struct paiext_root { /* Anchor to per CPU data */ - refcount_t refcnt; /* Overall active events */ - struct paiext_mapptr __percpu *mapptr; -} paiext_root; - -/* Free per CPU data when the last event is removed. */ -static void paiext_root_free(void) -{ - if (refcount_dec_and_test(&paiext_root.refcnt)) { - free_percpu(paiext_root.mapptr); - paiext_root.mapptr = NULL; - } - debug_sprintf_event(paiext_dbg, 5, "%s root.refcount %d\n", __func__, - refcount_read(&paiext_root.refcnt)); -} - -/* On initialization of first event also allocate per CPU data dynamically. - * Start with an array of pointers, the array size is the maximum number of - * CPUs possible, which might be larger than the number of CPUs currently - * online. - */ -static int paiext_root_alloc(void) -{ - if (!refcount_inc_not_zero(&paiext_root.refcnt)) { - /* The memory is already zeroed. */ - paiext_root.mapptr = alloc_percpu(struct paiext_mapptr); - if (!paiext_root.mapptr) { - /* Returning without refcnt adjustment is ok. The - * error code is handled by paiext_alloc() which - * decrements refcnt when an event can not be - * created. - */ - return -ENOMEM; - } - refcount_set(&paiext_root.refcnt, 1); - } - return 0; -} - -/* Protects against concurrent increment of sampler and counter member - * increments at the same time and prohibits concurrent execution of - * counting and sampling events. - * Ensures that analytics counter block is deallocated only when the - * sampling and counting on that cpu is zero. - * For details see paiext_alloc(). - */ -static DEFINE_MUTEX(paiext_reserve_mutex); - -/* Free all memory allocated for event counting/sampling setup */ -static void paiext_free(struct paiext_mapptr *mp) -{ - kfree(mp->mapptr->area); - kfree(mp->mapptr->paiext_cb); - kvfree(mp->mapptr->save); - kfree(mp->mapptr); - mp->mapptr = NULL; -} - -/* Release the PMU if event is the last perf event */ -static void paiext_event_destroy_cpu(struct perf_event *event, int cpu) -{ - struct paiext_mapptr *mp = per_cpu_ptr(paiext_root.mapptr, cpu); - struct paiext_map *cpump = mp->mapptr; - - mutex_lock(&paiext_reserve_mutex); - if (refcount_dec_and_test(&cpump->refcnt)) /* Last reference gone */ - paiext_free(mp); - paiext_root_free(); - mutex_unlock(&paiext_reserve_mutex); -} - -static void paiext_event_destroy(struct perf_event *event) -{ - int cpu; - - free_page(PAI_SAVE_AREA(event)); - if (event->cpu == -1) { - struct cpumask *mask = PAI_CPU_MASK(event); - - for_each_cpu(cpu, mask) - paiext_event_destroy_cpu(event, cpu); - kfree(mask); - } else { - paiext_event_destroy_cpu(event, event->cpu); - } - debug_sprintf_event(paiext_dbg, 4, "%s cpu %d\n", __func__, - event->cpu); -} - -/* Used to avoid races in checking concurrent access of counting and - * sampling for pai_extension events. - * - * Only one instance of event pai_ext/NNPA_ALL/ for sampling is - * allowed and when this event is running, no counting event is allowed. - * Several counting events are allowed in parallel, but no sampling event - * is allowed while one (or more) counting events are running. - * - * This function is called in process context and it is safe to block. - * When the event initialization functions fails, no other call back will - * be invoked. - * - * Allocate the memory for the event. - */ -static int paiext_alloc_cpu(struct perf_event *event, int cpu) -{ - struct paiext_mapptr *mp; - struct paiext_map *cpump; - int rc; - - mutex_lock(&paiext_reserve_mutex); - rc = paiext_root_alloc(); - if (rc) - goto unlock; - - mp = per_cpu_ptr(paiext_root.mapptr, cpu); - cpump = mp->mapptr; - if (!cpump) { /* Paiext_map allocated? */ - rc = -ENOMEM; - cpump = kzalloc(sizeof(*cpump), GFP_KERNEL); - if (!cpump) - goto undo; - - /* Allocate memory for counter area and counter extraction. - * These are - * - a 512 byte block and requires 512 byte boundary alignment. - * - a 1KB byte block and requires 1KB boundary alignment. - * Only the first counting event has to allocate the area. - * - * Note: This works with commit 59bb47985c1d by default. - * Backporting this to kernels without this commit might - * need adjustment. - */ - mp->mapptr = cpump; - cpump->area = kzalloc(PAIE1_CTRBLOCK_SZ, GFP_KERNEL); - cpump->paiext_cb = kzalloc(PAIE1_CB_SZ, GFP_KERNEL); - cpump->save = kvmalloc_array(paiext_cnt + 1, - sizeof(struct pai_userdata), - GFP_KERNEL); - if (!cpump->save || !cpump->area || !cpump->paiext_cb) { - paiext_free(mp); - goto undo; - } - INIT_LIST_HEAD(&cpump->syswide_list); - refcount_set(&cpump->refcnt, 1); - rc = 0; - } else { - refcount_inc(&cpump->refcnt); - } - -undo: - if (rc) { - /* Error in allocation of event, decrement anchor. Since - * the event in not created, its destroy() function is never - * invoked. Adjust the reference counter for the anchor. - */ - paiext_root_free(); - } -unlock: - mutex_unlock(&paiext_reserve_mutex); - /* If rc is non-zero, no increment of counter/sampler was done. */ - return rc; -} - -static int paiext_alloc(struct perf_event *event) -{ - struct cpumask *maskptr; - int cpu, rc = -ENOMEM; - - maskptr = kzalloc(sizeof(*maskptr), GFP_KERNEL); - if (!maskptr) - goto out; - - for_each_online_cpu(cpu) { - rc = paiext_alloc_cpu(event, cpu); - if (rc) { - for_each_cpu(cpu, maskptr) - paiext_event_destroy_cpu(event, cpu); - kfree(maskptr); - goto out; - } - cpumask_set_cpu(cpu, maskptr); - } - - /* - * On error all cpumask are freed and all events have been destroyed. - * Save of which CPUs data structures have been allocated for. - * Release them in paicrypt_event_destroy call back function - * for this event. - */ - PAI_CPU_MASK(event) = maskptr; - rc = 0; -out: - return rc; -} - -/* The PAI extension 1 control block supports up to 128 entries. Return - * the index within PAIE1_CB given the event number. Also validate event - * number. - */ -static int paiext_event_valid(struct perf_event *event) -{ - u64 cfg = event->attr.config; - - if (cfg >= PAI_NNPA_BASE && cfg <= PAI_NNPA_BASE + paiext_cnt) { - /* Offset NNPA in paiext_cb */ - event->hw.config_base = offsetof(struct paiext_cb, acc); - return 0; - } - return -ENOENT; -} - -/* Might be called on different CPU than the one the event is intended for. */ -static int paiext_event_init(struct perf_event *event) -{ - struct perf_event_attr *a = &event->attr; - int rc; - - /* PMU pai_ext registered as PERF_TYPE_RAW, check event type */ - if (a->type != PERF_TYPE_RAW && event->pmu->type != a->type) - return -ENOENT; - /* PAI extension event must be valid and in supported range */ - rc = paiext_event_valid(event); - if (rc) - return rc; - /* Allow only event NNPA_ALL for sampling. */ - if (a->sample_period && a->config != PAI_NNPA_BASE) - return -EINVAL; - /* Prohibit exclude_user event selection */ - if (a->exclude_user) - return -EINVAL; - /* Get a page to store last counter values for sampling */ - if (a->sample_period) { - PAI_SAVE_AREA(event) = get_zeroed_page(GFP_KERNEL); - if (!PAI_SAVE_AREA(event)) - return -ENOMEM; - } - - if (event->cpu >= 0) - rc = paiext_alloc_cpu(event, event->cpu); - else - rc = paiext_alloc(event); - if (rc) { - free_page(PAI_SAVE_AREA(event)); - return rc; - } - event->destroy = paiext_event_destroy; - - if (a->sample_period) { - a->sample_period = 1; - a->freq = 0; - /* Register for paicrypt_sched_task() to be called */ - event->attach_state |= PERF_ATTACH_SCHED_CB; - /* Add raw data which are the memory mapped counters */ - a->sample_type |= PERF_SAMPLE_RAW; - /* Turn off inheritance */ - a->inherit = 0; - } - - return 0; -} - -static u64 paiext_getctr(unsigned long *area, int nr) -{ - return area[nr]; -} - -/* Read the counter values. Return value from location in buffer. For event - * NNPA_ALL sum up all events. - */ -static u64 paiext_getdata(struct perf_event *event) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - u64 sum = 0; - int i; - - if (event->attr.config != PAI_NNPA_BASE) - return paiext_getctr(cpump->area, - event->attr.config - PAI_NNPA_BASE); - - for (i = 1; i <= paiext_cnt; i++) - sum += paiext_getctr(cpump->area, i); - - return sum; -} - -static u64 paiext_getall(struct perf_event *event) -{ - return paiext_getdata(event); -} - -static void paiext_read(struct perf_event *event) -{ - u64 prev, new, delta; - - prev = local64_read(&event->hw.prev_count); - new = paiext_getall(event); - local64_set(&event->hw.prev_count, new); - delta = new - prev; - local64_add(delta, &event->count); -} - -static void paiext_start(struct perf_event *event, int flags) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - u64 sum; - - if (!event->attr.sample_period) { /* Counting */ - sum = paiext_getall(event); /* Get current value */ - local64_set(&event->hw.prev_count, sum); - } else { /* Sampling */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->area, - PAIE1_CTRBLOCK_SZ); - /* Enable context switch callback for system-wide sampling */ - if (!(event->attach_state & PERF_ATTACH_TASK)) { - list_add_tail(PAI_SWLIST(event), &cpump->syswide_list); - perf_sched_cb_inc(event->pmu); - } else { - cpump->event = event; - } - } -} - -static int paiext_add(struct perf_event *event, int flags) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - struct paiext_cb *pcb = cpump->paiext_cb; - - if (++cpump->active_events == 1) { - get_lowcore()->aicd = virt_to_phys(cpump->paiext_cb); - pcb->acc = virt_to_phys(cpump->area) | 0x1; - /* Enable CPU instruction lookup for PAIE1 control block */ - local_ctl_set_bit(0, CR0_PAI_EXTENSION_BIT); - } - if (flags & PERF_EF_START) - paiext_start(event, PERF_EF_RELOAD); - event->hw.state = 0; - return 0; -} - -static void paiext_have_sample(struct perf_event *, struct paiext_map *); -static void paiext_stop(struct perf_event *event, int flags) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - - if (!event->attr.sample_period) { /* Counting */ - paiext_read(event); - } else { /* Sampling */ - if (!(event->attach_state & PERF_ATTACH_TASK)) { - list_del(PAI_SWLIST(event)); - perf_sched_cb_dec(event->pmu); - } else { - paiext_have_sample(event, cpump); - cpump->event = NULL; - } - } - event->hw.state = PERF_HES_STOPPED; -} - -static void paiext_del(struct perf_event *event, int flags) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - struct paiext_cb *pcb = cpump->paiext_cb; - - paiext_stop(event, PERF_EF_UPDATE); - if (--cpump->active_events == 0) { - /* Disable CPU instruction lookup for PAIE1 control block */ - local_ctl_clear_bit(0, CR0_PAI_EXTENSION_BIT); - pcb->acc = 0; - get_lowcore()->aicd = 0; - } -} - -/* Create raw data and save it in buffer. Returns number of bytes copied. - * Saves only positive counter entries of the form - * 2 bytes: Number of counter - * 8 bytes: Value of counter - */ -static size_t paiext_copy(struct pai_userdata *userdata, unsigned long *area, - unsigned long *area_old) -{ - int i, outidx = 0; - - for (i = 1; i <= paiext_cnt; i++) { - u64 val = paiext_getctr(area, i); - u64 val_old = paiext_getctr(area_old, i); - - if (val >= val_old) - val -= val_old; - else - val = (~0ULL - val_old) + val + 1; - if (val) { - userdata[outidx].num = i; - userdata[outidx].value = val; - outidx++; - } - } - return outidx * sizeof(*userdata); -} - -/* Write sample when one or more counters values are nonzero. - * - * Note: The function paiext_sched_task() and paiext_push_sample() are not - * invoked after function paiext_del() has been called because of function - * perf_sched_cb_dec(). - * The function paiext_sched_task() and paiext_push_sample() are only - * called when sampling is active. Function perf_sched_cb_inc() - * has been invoked to install function paiext_sched_task() as call back - * to run at context switch time (see paiext_add()). - * - * This causes function perf_event_context_sched_out() and - * perf_event_context_sched_in() to check whether the PMU has installed an - * sched_task() callback. That callback is not active after paiext_del() - * returns and has deleted the event on that CPU. - */ -static int paiext_push_sample(size_t rawsize, struct paiext_map *cpump, - struct perf_event *event) -{ - struct perf_sample_data data; - struct perf_raw_record raw; - struct pt_regs regs; - int overflow; - - /* Setup perf sample */ - memset(®s, 0, sizeof(regs)); - memset(&raw, 0, sizeof(raw)); - memset(&data, 0, sizeof(data)); - perf_sample_data_init(&data, 0, event->hw.last_period); - if (event->attr.sample_type & PERF_SAMPLE_TID) { - data.tid_entry.pid = task_tgid_nr(current); - data.tid_entry.tid = task_pid_nr(current); - } - if (event->attr.sample_type & PERF_SAMPLE_TIME) - data.time = event->clock(); - if (event->attr.sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) - data.id = event->id; - if (event->attr.sample_type & PERF_SAMPLE_CPU) - data.cpu_entry.cpu = smp_processor_id(); - if (event->attr.sample_type & PERF_SAMPLE_RAW) { - raw.frag.size = rawsize; - raw.frag.data = cpump->save; - perf_sample_save_raw_data(&data, event, &raw); - } - - overflow = perf_event_overflow(event, &data, ®s); - perf_event_update_userpage(event); - /* Save NNPA lowcore area after read in event */ - memcpy((void *)PAI_SAVE_AREA(event), cpump->area, - PAIE1_CTRBLOCK_SZ); - return overflow; -} - -/* Check if there is data to be saved on schedule out of a task. */ -static void paiext_have_sample(struct perf_event *event, - struct paiext_map *cpump) -{ - size_t rawsize; - - if (!event) - return; - rawsize = paiext_copy(cpump->save, cpump->area, - (unsigned long *)PAI_SAVE_AREA(event)); - if (rawsize) /* Incremented counters */ - paiext_push_sample(rawsize, cpump, event); -} - -/* Check if there is data to be saved on schedule out of a task. */ -static void paiext_have_samples(void) -{ - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - struct perf_event *event; - - list_for_each_entry(event, &cpump->syswide_list, hw.tp_list) - paiext_have_sample(event, cpump); -} - -/* Called on schedule-in and schedule-out. No access to event structure, - * but for sampling only event NNPA_ALL is allowed. - */ -static void paiext_sched_task(struct perf_event_pmu_context *pmu_ctx, - struct task_struct *task, bool sched_in) -{ - /* We started with a clean page on event installation. So read out - * results on schedule_out and if page was dirty, save old values. - */ - if (!sched_in) - paiext_have_samples(); -} - -/* Attribute definitions for pai extension1 interface. As with other CPU - * Measurement Facilities, there is one attribute per mapped counter. - * The number of mapped counters may vary per machine generation. Use - * the QUERY PROCESSOR ACTIVITY COUNTER INFORMATION (QPACI) instruction - * to determine the number of mapped counters. The instructions returns - * a positive number, which is the highest number of supported counters. - * All counters less than this number are also supported, there are no - * holes. A returned number of zero means no support for mapped counters. - * - * The identification of the counter is a unique number. The chosen range - * is 0x1800 + offset in mapped kernel page. - * All CPU Measurement Facility counters identifiers must be unique and - * the numbers from 0 to 496 are already used for the CPU Measurement - * Counter facility. Number 0x1000 to 0x103e are used for PAI cryptography - * counters. - * Numbers 0xb0000, 0xbc000 and 0xbd000 are already - * used for the CPU Measurement Sampling facility. - */ -PMU_FORMAT_ATTR(event, "config:0-63"); - -static struct attribute *paiext_format_attr[] = { - &format_attr_event.attr, - NULL, -}; - -static struct attribute_group paiext_events_group = { - .name = "events", - .attrs = NULL, /* Filled in attr_event_init() */ -}; - -static struct attribute_group paiext_format_group = { - .name = "format", - .attrs = paiext_format_attr, -}; - -static const struct attribute_group *paiext_attr_groups[] = { - &paiext_events_group, - &paiext_format_group, - NULL, -}; - -/* Performance monitoring unit for mapped counters */ -static struct pmu paiext = { - .task_ctx_nr = perf_hw_context, - .event_init = paiext_event_init, - .add = paiext_add, - .del = paiext_del, - .start = paiext_start, - .stop = paiext_stop, - .read = paiext_read, - .sched_task = paiext_sched_task, - .attr_groups = paiext_attr_groups, -}; - -/* List of symbolic PAI extension 1 NNPA counter names. */ -static const char * const paiext_ctrnames[] = { - [0] = "NNPA_ALL", - [1] = "NNPA_ADD", - [2] = "NNPA_SUB", - [3] = "NNPA_MUL", - [4] = "NNPA_DIV", - [5] = "NNPA_MIN", - [6] = "NNPA_MAX", - [7] = "NNPA_LOG", - [8] = "NNPA_EXP", - [9] = "NNPA_IBM_RESERVED_9", - [10] = "NNPA_RELU", - [11] = "NNPA_TANH", - [12] = "NNPA_SIGMOID", - [13] = "NNPA_SOFTMAX", - [14] = "NNPA_BATCHNORM", - [15] = "NNPA_MAXPOOL2D", - [16] = "NNPA_AVGPOOL2D", - [17] = "NNPA_LSTMACT", - [18] = "NNPA_GRUACT", - [19] = "NNPA_CONVOLUTION", - [20] = "NNPA_MATMUL_OP", - [21] = "NNPA_MATMUL_OP_BCAST23", - [22] = "NNPA_SMALLBATCH", - [23] = "NNPA_LARGEDIM", - [24] = "NNPA_SMALLTENSOR", - [25] = "NNPA_1MFRAME", - [26] = "NNPA_2GFRAME", - [27] = "NNPA_ACCESSEXCEPT", - [28] = "NNPA_TRANSFORM", - [29] = "NNPA_GELU", - [30] = "NNPA_MOMENTS", - [31] = "NNPA_LAYERNORM", - [32] = "NNPA_MATMUL_OP_BCAST1", - [33] = "NNPA_SQRT", - [34] = "NNPA_INVSQRT", - [35] = "NNPA_NORM", - [36] = "NNPA_REDUCE", -}; - -static void __init attr_event_free(struct attribute **attrs, int num) -{ - struct perf_pmu_events_attr *pa; - struct device_attribute *dap; - int i; - - for (i = 0; i < num; i++) { - dap = container_of(attrs[i], struct device_attribute, attr); - pa = container_of(dap, struct perf_pmu_events_attr, attr); - kfree(pa); - } - kfree(attrs); -} - -static int __init attr_event_init_one(struct attribute **attrs, int num) -{ - struct perf_pmu_events_attr *pa; - - /* Index larger than array_size, no counter name available */ - if (num >= ARRAY_SIZE(paiext_ctrnames)) { - attrs[num] = NULL; - return 0; - } - - pa = kzalloc(sizeof(*pa), GFP_KERNEL); - if (!pa) - return -ENOMEM; - - sysfs_attr_init(&pa->attr.attr); - pa->id = PAI_NNPA_BASE + num; - pa->attr.attr.name = paiext_ctrnames[num]; - pa->attr.attr.mode = 0444; - pa->attr.show = cpumf_events_sysfs_show; - pa->attr.store = NULL; - attrs[num] = &pa->attr.attr; - return 0; -} - -/* Create PMU sysfs event attributes on the fly. */ -static int __init attr_event_init(void) -{ - struct attribute **attrs; - int ret, i; - - attrs = kmalloc_array(paiext_cnt + 2, sizeof(*attrs), GFP_KERNEL); - if (!attrs) - return -ENOMEM; - for (i = 0; i <= paiext_cnt; i++) { - ret = attr_event_init_one(attrs, i); - if (ret) { - attr_event_free(attrs, i); - return ret; - } - } - attrs[i] = NULL; - paiext_events_group.attrs = attrs; - return 0; -} - -static int __init paiext_init(void) -{ - struct qpaci_info_block ib; - int rc = -ENOMEM; - - if (!test_facility(197)) - return 0; - - qpaci(&ib); - paiext_cnt = ib.num_nnpa; - if (paiext_cnt >= PAI_NNPA_MAXCTR) - paiext_cnt = PAI_NNPA_MAXCTR; - if (!paiext_cnt) - return 0; - - rc = attr_event_init(); - if (rc) { - pr_err("Creation of PMU " KMSG_COMPONENT " /sysfs failed\n"); - return rc; - } - - /* Setup s390dbf facility */ - paiext_dbg = debug_register(KMSG_COMPONENT, 2, 256, 128); - if (!paiext_dbg) { - pr_err("Registration of s390dbf " KMSG_COMPONENT " failed\n"); - rc = -ENOMEM; - goto out_init; - } - debug_register_view(paiext_dbg, &debug_sprintf_view); - - rc = perf_pmu_register(&paiext, KMSG_COMPONENT, -1); - if (rc) { - pr_err("Registration of " KMSG_COMPONENT " PMU failed with " - "rc=%i\n", rc); - goto out_pmu; - } - - return 0; - -out_pmu: - debug_unregister_view(paiext_dbg, &debug_sprintf_view); - debug_unregister(paiext_dbg); -out_init: - attr_event_free(paiext_events_group.attrs, - ARRAY_SIZE(paiext_ctrnames) + 1); - return rc; -} - -device_initcall(paiext_init); From 492578d3a2bce24b73f24728bc244add0bdf3fee Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 5 Nov 2025 15:39:02 +0100 Subject: [PATCH 23/23] s390/pai: Rename perf_pai_crypto.c to perf_pai.c Rename perf_pai_crypto.c to perf_pai.c. The new perf_pai.c contains both PAI device drivers: - pai_crypto for PAI crypto counter set - pai_ext for PAI NNPA counter set The rename reflects this common driver supporting both PMUs. Signed-off-by: Thomas Richter Reviewed-by: Jan Polensky Signed-off-by: Heiko Carstens --- arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/{perf_pai_crypto.c => perf_pai.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename arch/s390/kernel/{perf_pai_crypto.c => perf_pai.c} (100%) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 558f7c5bfe32..c5791179b4b0 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_arch.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o -obj-$(CONFIG_PERF_EVENTS) += perf_pai_crypto.o +obj-$(CONFIG_PERF_EVENTS) += perf_pai.o obj-$(CONFIG_TRACEPOINTS) += trace.o diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai.c similarity index 100% rename from arch/s390/kernel/perf_pai_crypto.c rename to arch/s390/kernel/perf_pai.c