2018-08-06 21:56:43 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
|
|
* Counter facility support definitions for the Linux perf
|
|
|
|
*
|
|
|
|
* Copyright IBM Corp. 2019
|
|
|
|
* Author(s): Hendrik Brueckner <brueckner@linux.ibm.com>
|
|
|
|
*/
|
|
|
|
#ifndef _ASM_S390_CPU_MCF_H
|
|
|
|
#define _ASM_S390_CPU_MCF_H
|
|
|
|
|
|
|
|
#include <linux/perf_event.h>
|
|
|
|
#include <asm/cpu_mf.h>
|
|
|
|
|
|
|
|
enum cpumf_ctr_set {
|
|
|
|
CPUMF_CTR_SET_BASIC = 0, /* Basic Counter Set */
|
|
|
|
CPUMF_CTR_SET_USER = 1, /* Problem-State Counter Set */
|
|
|
|
CPUMF_CTR_SET_CRYPTO = 2, /* Crypto-Activity Counter Set */
|
|
|
|
CPUMF_CTR_SET_EXT = 3, /* Extended Counter Set */
|
|
|
|
CPUMF_CTR_SET_MT_DIAG = 4, /* MT-diagnostic Counter Set */
|
|
|
|
|
|
|
|
/* Maximum number of counter sets */
|
|
|
|
CPUMF_CTR_SET_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define CPUMF_LCCTL_ENABLE_SHIFT 16
|
|
|
|
#define CPUMF_LCCTL_ACTCTL_SHIFT 0
|
|
|
|
static const u64 cpumf_ctr_ctl[CPUMF_CTR_SET_MAX] = {
|
|
|
|
[CPUMF_CTR_SET_BASIC] = 0x02,
|
|
|
|
[CPUMF_CTR_SET_USER] = 0x04,
|
|
|
|
[CPUMF_CTR_SET_CRYPTO] = 0x08,
|
|
|
|
[CPUMF_CTR_SET_EXT] = 0x01,
|
|
|
|
[CPUMF_CTR_SET_MT_DIAG] = 0x20,
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void ctr_set_enable(u64 *state, int ctr_set)
|
|
|
|
{
|
|
|
|
*state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT;
|
|
|
|
}
|
|
|
|
static inline void ctr_set_disable(u64 *state, int ctr_set)
|
|
|
|
{
|
|
|
|
*state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT);
|
|
|
|
}
|
|
|
|
static inline void ctr_set_start(u64 *state, int ctr_set)
|
|
|
|
{
|
|
|
|
*state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT;
|
|
|
|
}
|
|
|
|
static inline void ctr_set_stop(u64 *state, int ctr_set)
|
|
|
|
{
|
|
|
|
*state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT);
|
|
|
|
}
|
|
|
|
|
2018-10-29 21:16:38 +08:00
|
|
|
static inline void ctr_set_multiple_enable(u64 *state, u64 ctrsets)
|
|
|
|
{
|
|
|
|
*state |= ctrsets << CPUMF_LCCTL_ENABLE_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ctr_set_multiple_disable(u64 *state, u64 ctrsets)
|
|
|
|
{
|
|
|
|
*state &= ~(ctrsets << CPUMF_LCCTL_ENABLE_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ctr_set_multiple_start(u64 *state, u64 ctrsets)
|
|
|
|
{
|
|
|
|
*state |= ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ctr_set_multiple_stop(u64 *state, u64 ctrsets)
|
|
|
|
{
|
|
|
|
*state &= ~(ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT);
|
|
|
|
}
|
|
|
|
|
2018-10-26 15:48:29 +08:00
|
|
|
static inline int ctr_stcctm(enum cpumf_ctr_set set, u64 range, u64 *dest)
|
|
|
|
{
|
|
|
|
switch (set) {
|
|
|
|
case CPUMF_CTR_SET_BASIC:
|
|
|
|
return stcctm(BASIC, range, dest);
|
|
|
|
case CPUMF_CTR_SET_USER:
|
|
|
|
return stcctm(PROBLEM_STATE, range, dest);
|
|
|
|
case CPUMF_CTR_SET_CRYPTO:
|
|
|
|
return stcctm(CRYPTO_ACTIVITY, range, dest);
|
|
|
|
case CPUMF_CTR_SET_EXT:
|
|
|
|
return stcctm(EXTENDED, range, dest);
|
|
|
|
case CPUMF_CTR_SET_MT_DIAG:
|
|
|
|
return stcctm(MT_DIAG_CLEARING, range, dest);
|
|
|
|
case CPUMF_CTR_SET_MAX:
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
2018-08-08 16:12:22 +08:00
|
|
|
struct cpu_cf_events {
|
|
|
|
struct cpumf_ctr_info info;
|
|
|
|
atomic_t ctr_set[CPUMF_CTR_SET_MAX];
|
2018-08-08 16:30:37 +08:00
|
|
|
atomic64_t alert;
|
2018-08-08 16:12:22 +08:00
|
|
|
u64 state, tx_state;
|
|
|
|
unsigned int flags;
|
|
|
|
unsigned int txn_flags;
|
|
|
|
};
|
|
|
|
DECLARE_PER_CPU(struct cpu_cf_events, cpu_cf_events);
|
|
|
|
|
2018-10-25 22:58:15 +08:00
|
|
|
bool kernel_cpumcf_avail(void);
|
2018-08-06 23:43:07 +08:00
|
|
|
int __kernel_cpumcf_begin(void);
|
2018-08-08 16:30:37 +08:00
|
|
|
unsigned long kernel_cpumcf_alert(int clear);
|
2018-08-06 23:43:07 +08:00
|
|
|
void __kernel_cpumcf_end(void);
|
|
|
|
|
s390/cpum_cf: Add minimal in-kernel interface for counter measurements
Introduce a minimal interface for doing counter measurements of small
units of work within the kernel. Use the kernel_cpumcf_begin() function
start a measurement session and, later, stop it with kernel_cpumcf_end().
During the measreument session, you can enable and start/stop counter sets
by using ctr_set_* functions. To make these changes effective use the
lcctl() function. You can then use the ecctr() function to extract counters
from the different counter sets.
Please note that you have to check whether the counter sets to be enabled
are authorized.
Note that when a measurement session is active, other users cannot perform
counter measurements. In such cases, kernel_cpumcf_begin() indicates this
with returning -EBUSY. If the counter facility is not available,
kernel_cpumcf_begin() returns -ENODEV.
Note that this interface is restricted to the current CPU and, thus,
preemption must be turned off.
Example:
u32 state, err;
u64 cycles, insn;
err = kernel_cpumcf_begin();
if (err)
goto out_busy;
state = 0;
ctr_set_enable(&state, CPUMF_CTR_SET_BASIC);
ctr_set_start(&state, CPUMF_CTR_SET_BASIC);
err = lcctl(state);
if (err)
goto ;
/* ... do your work ... */
ctr_set_stop(&state, CPUMF_CTR_SET_BASIC);
err = lcctl(state);
if (err)
goto out;
cycles = insn = 0;
ecctr(0, &cycles);
ecctr(1, &insn);
/* ... */
kernel_cpumcf_end();
out_busy:
Signed-off-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
2018-08-08 16:38:43 +08:00
|
|
|
static inline int kernel_cpumcf_begin(void)
|
|
|
|
{
|
|
|
|
if (!cpum_cf_avail())
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
preempt_disable();
|
|
|
|
return __kernel_cpumcf_begin();
|
|
|
|
}
|
|
|
|
static inline void kernel_cpumcf_end(void)
|
|
|
|
{
|
|
|
|
__kernel_cpumcf_end();
|
|
|
|
preempt_enable();
|
|
|
|
}
|
|
|
|
|
2018-10-29 21:16:38 +08:00
|
|
|
/* Return true if store counter set multiple instruction is available */
|
|
|
|
static inline int stccm_avail(void)
|
|
|
|
{
|
|
|
|
return test_facility(142);
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:56:43 +08:00
|
|
|
#endif /* _ASM_S390_CPU_MCF_H */
|