Skip to content

Commit 46c4d94

Browse files
Thomas RichterVasily Gorbik
authored andcommitted
s390/cpum_cf: introduce static CPU counter facility information
The CPU measurement facility counter information instruction qctri() retrieves information about the available counter sets. The information varies between machine generations, but is constant when running on a particular machine. For example the CPU measurement facility counter first and second version numbers determine the amount of counters in a counter set. This information never changes. The counter sets are identical for all CPUs in the system. It does not matter which CPU performs the instruction. Authorization control of the CPU Measurement facility can only be changed in the activation profile while the LPAR is not running. Retrieve the CPU measurement counter information at device driver initialization time and use its constant values. Function validate_ctr_version() verifies if a user provided CPU Measurement counter facility counter is valid and defined. It now uses the newly introduced static CPU counter facility information. To avoid repeated recalculation of the counter set sizes (numbers of counters per set), which never changes on a running machine, calculate the counter set size once at device driver initialization and store the result in an array. Functions cpum_cf_make_setsize() and cpum_cf_read_setsize() are introduced. Finally remove cpu_cf_events::info member and use the static CPU counter facility information instead. Signed-off-by: Thomas Richter <tmricht@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 3b42877 commit 46c4d94

1 file changed

Lines changed: 65 additions & 67 deletions

File tree

arch/s390/kernel/perf_cpum_cf.c

Lines changed: 65 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ static inline int ctr_stcctm(enum cpumf_ctr_set set, u64 range, u64 *dest)
7676
}
7777

7878
struct cpu_cf_events {
79-
struct cpumf_ctr_info info;
8079
atomic_t ctr_set[CPUMF_CTR_SET_MAX];
8180
u64 state; /* For perf_event_open SVC */
8281
u64 dev_state; /* For /dev/hwctr */
@@ -95,6 +94,15 @@ static DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events);
9594
static unsigned int cfdiag_cpu_speed; /* CPU speed for CF_DIAG trailer */
9695
static debug_info_t *cf_dbg;
9796

97+
/*
98+
* The CPU Measurement query counter information instruction contains
99+
* information which varies per machine generation, but is constant and
100+
* does not change when running on a particular machine, such as counter
101+
* first and second version number. This is needed to determine the size
102+
* of counter sets. Extract this information at device driver initialization.
103+
*/
104+
static struct cpumf_ctr_info cpumf_ctr_info;
105+
98106
#define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */
99107
/* interval in seconds */
100108

@@ -167,11 +175,10 @@ struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */
167175
/* Create the trailer data at the end of a page. */
168176
static void cfdiag_trailer(struct cf_trailer_entry *te)
169177
{
170-
struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
171178
struct cpuid cpuid;
172179

173-
te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */
174-
te->csvn = cpuhw->info.csvn;
180+
te->cfvn = cpumf_ctr_info.cfvn; /* Counter version numbers */
181+
te->csvn = cpumf_ctr_info.csvn;
175182

176183
get_cpu_id(&cpuid); /* Machine type */
177184
te->mach_type = cpuid.machine;
@@ -184,50 +191,60 @@ static void cfdiag_trailer(struct cf_trailer_entry *te)
184191
}
185192

186193
/*
187-
* Return the maximum possible counter set size (in number of 8 byte counters)
188-
* depending on type and model number.
194+
* The number of counters per counter set varies between machine generations,
195+
* but is constant when running on a particular machine generation.
196+
* Determine each counter set size at device driver initialization and
197+
* retrieve it later.
189198
*/
190-
static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset,
191-
struct cpumf_ctr_info *info)
199+
static size_t cpumf_ctr_setsizes[CPUMF_CTR_SET_MAX];
200+
static void cpum_cf_make_setsize(enum cpumf_ctr_set ctrset)
192201
{
193202
size_t ctrset_size = 0;
194203

195204
switch (ctrset) {
196205
case CPUMF_CTR_SET_BASIC:
197-
if (info->cfvn >= 1)
206+
if (cpumf_ctr_info.cfvn >= 1)
198207
ctrset_size = 6;
199208
break;
200209
case CPUMF_CTR_SET_USER:
201-
if (info->cfvn == 1)
210+
if (cpumf_ctr_info.cfvn == 1)
202211
ctrset_size = 6;
203-
else if (info->cfvn >= 3)
212+
else if (cpumf_ctr_info.cfvn >= 3)
204213
ctrset_size = 2;
205214
break;
206215
case CPUMF_CTR_SET_CRYPTO:
207-
if (info->csvn >= 1 && info->csvn <= 5)
216+
if (cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5)
208217
ctrset_size = 16;
209-
else if (info->csvn == 6 || info->csvn == 7)
218+
else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7)
210219
ctrset_size = 20;
211220
break;
212221
case CPUMF_CTR_SET_EXT:
213-
if (info->csvn == 1)
222+
if (cpumf_ctr_info.csvn == 1)
214223
ctrset_size = 32;
215-
else if (info->csvn == 2)
224+
else if (cpumf_ctr_info.csvn == 2)
216225
ctrset_size = 48;
217-
else if (info->csvn >= 3 && info->csvn <= 5)
226+
else if (cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5)
218227
ctrset_size = 128;
219-
else if (info->csvn == 6 || info->csvn == 7)
228+
else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7)
220229
ctrset_size = 160;
221230
break;
222231
case CPUMF_CTR_SET_MT_DIAG:
223-
if (info->csvn > 3)
232+
if (cpumf_ctr_info.csvn > 3)
224233
ctrset_size = 48;
225234
break;
226235
case CPUMF_CTR_SET_MAX:
227236
break;
228237
}
238+
cpumf_ctr_setsizes[ctrset] = ctrset_size;
239+
}
229240

230-
return ctrset_size;
241+
/*
242+
* Return the maximum possible counter set size (in number of 8 byte counters)
243+
* depending on type and model number.
244+
*/
245+
static size_t cpum_cf_read_setsize(enum cpumf_ctr_set ctrset)
246+
{
247+
return cpumf_ctr_setsizes[ctrset];
231248
}
232249

233250
/* Read a counter set. The counter set number determines the counter set and
@@ -248,14 +265,13 @@ static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset,
248265
static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset,
249266
size_t room, bool error_ok)
250267
{
251-
struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
252268
size_t ctrset_size, need = 0;
253269
int rc = 3; /* Assume write failure */
254270

255271
ctrdata->def = CF_DIAG_CTRSET_DEF;
256272
ctrdata->set = ctrset;
257273
ctrdata->res1 = 0;
258-
ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info);
274+
ctrset_size = cpum_cf_read_setsize(ctrset);
259275

260276
if (ctrset_size) { /* Save data */
261277
need = ctrset_size * sizeof(u64) + sizeof(*ctrdata);
@@ -269,10 +285,6 @@ static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset,
269285
need = 0;
270286
}
271287

272-
debug_sprintf_event(cf_dbg, 3,
273-
"%s ctrset %d ctrset_size %zu cfvn %d csvn %d"
274-
" need %zd rc %d\n", __func__, ctrset, ctrset_size,
275-
cpuhw->info.cfvn, cpuhw->info.csvn, need, rc);
276288
return need;
277289
}
278290

@@ -380,37 +392,34 @@ static enum cpumf_ctr_set get_counter_set(u64 event)
380392
static int validate_ctr_version(const struct hw_perf_event *hwc,
381393
enum cpumf_ctr_set set)
382394
{
383-
struct cpu_cf_events *cpuhw;
384-
int err = 0;
385395
u16 mtdiag_ctl;
386-
387-
cpuhw = &get_cpu_var(cpu_cf_events);
396+
int err = 0;
388397

389398
/* check required version for counter sets */
390399
switch (set) {
391400
case CPUMF_CTR_SET_BASIC:
392401
case CPUMF_CTR_SET_USER:
393-
if (cpuhw->info.cfvn < 1)
402+
if (cpumf_ctr_info.cfvn < 1)
394403
err = -EOPNOTSUPP;
395404
break;
396405
case CPUMF_CTR_SET_CRYPTO:
397-
if ((cpuhw->info.csvn >= 1 && cpuhw->info.csvn <= 5 &&
406+
if ((cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5 &&
398407
hwc->config > 79) ||
399-
(cpuhw->info.csvn >= 6 && hwc->config > 83))
408+
(cpumf_ctr_info.csvn >= 6 && hwc->config > 83))
400409
err = -EOPNOTSUPP;
401410
break;
402411
case CPUMF_CTR_SET_EXT:
403-
if (cpuhw->info.csvn < 1)
412+
if (cpumf_ctr_info.csvn < 1)
404413
err = -EOPNOTSUPP;
405-
if ((cpuhw->info.csvn == 1 && hwc->config > 159) ||
406-
(cpuhw->info.csvn == 2 && hwc->config > 175) ||
407-
(cpuhw->info.csvn >= 3 && cpuhw->info.csvn <= 5
414+
if ((cpumf_ctr_info.csvn == 1 && hwc->config > 159) ||
415+
(cpumf_ctr_info.csvn == 2 && hwc->config > 175) ||
416+
(cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5
408417
&& hwc->config > 255) ||
409-
(cpuhw->info.csvn >= 6 && hwc->config > 287))
418+
(cpumf_ctr_info.csvn >= 6 && hwc->config > 287))
410419
err = -EOPNOTSUPP;
411420
break;
412421
case CPUMF_CTR_SET_MT_DIAG:
413-
if (cpuhw->info.csvn <= 3)
422+
if (cpumf_ctr_info.csvn <= 3)
414423
err = -EOPNOTSUPP;
415424
/*
416425
* MT-diagnostic counters are read-only. The counter set
@@ -425,35 +434,30 @@ static int validate_ctr_version(const struct hw_perf_event *hwc,
425434
* counter set is enabled and active.
426435
*/
427436
mtdiag_ctl = cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG];
428-
if (!((cpuhw->info.auth_ctl & mtdiag_ctl) &&
429-
(cpuhw->info.enable_ctl & mtdiag_ctl) &&
430-
(cpuhw->info.act_ctl & mtdiag_ctl)))
437+
if (!((cpumf_ctr_info.auth_ctl & mtdiag_ctl) &&
438+
(cpumf_ctr_info.enable_ctl & mtdiag_ctl) &&
439+
(cpumf_ctr_info.act_ctl & mtdiag_ctl)))
431440
err = -EOPNOTSUPP;
432441
break;
433442
case CPUMF_CTR_SET_MAX:
434443
err = -EOPNOTSUPP;
435444
}
436445

437-
put_cpu_var(cpu_cf_events);
438446
return err;
439447
}
440448

441449
static int validate_ctr_auth(const struct hw_perf_event *hwc)
442450
{
443-
struct cpu_cf_events *cpuhw;
444-
int err = 0;
445-
446-
cpuhw = &get_cpu_var(cpu_cf_events);
451+
int err = -ENOENT;
447452

448453
/* Check authorization for cpu counter sets.
449454
* If the particular CPU counter set is not authorized,
450455
* return with -ENOENT in order to fall back to other
451456
* PMUs that might suffice the event request.
452457
*/
453-
if (!(hwc->config_base & cpuhw->info.auth_ctl))
454-
err = -ENOENT;
458+
if ((hwc->config_base & cpumf_ctr_info.auth_ctl))
459+
err = 0;
455460

456-
put_cpu_var(cpu_cf_events);
457461
return err;
458462
}
459463

@@ -509,8 +513,6 @@ static void cpum_cf_setup_cpu(void *flags)
509513

510514
switch ((unsigned long)flags) {
511515
case PMC_INIT:
512-
memset(&cpuhw->info, 0, sizeof(cpuhw->info));
513-
qctri(&cpuhw->info);
514516
cpuhw->flags |= PMU_F_RESERVED;
515517
break;
516518

@@ -977,7 +979,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code,
977979

978980
/* counter authorization change alert */
979981
if (alert & CPU_MF_INT_CF_CACA)
980-
qctri(&cpuhw->info);
982+
qctri(&cpumf_ctr_info);
981983

982984
/* loss of counter data alert */
983985
if (alert & CPU_MF_INT_CF_LCDA)
@@ -994,9 +996,14 @@ static int __init cpumf_pmu_init(void)
994996
{
995997
int rc;
996998

997-
if (!cpum_cf_avail())
999+
/* Extract counter measurement facility information */
1000+
if (!cpum_cf_avail() || qctri(&cpumf_ctr_info))
9981001
return -ENODEV;
9991002

1003+
/* Determine and store counter set sizes for later reference */
1004+
for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc)
1005+
cpum_cf_make_setsize(rc);
1006+
10001007
/*
10011008
* Clear bit 15 of cr0 to unauthorize problem-state to
10021009
* extract measurement counters
@@ -1263,21 +1270,19 @@ static int cfset_all_start(struct cfset_request *req)
12631270
*/
12641271
static size_t cfset_needspace(unsigned int sets)
12651272
{
1266-
struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events);
12671273
size_t bytes = 0;
12681274
int i;
12691275

12701276
for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
12711277
if (!(sets & cpumf_ctr_ctl[i]))
12721278
continue;
1273-
bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) +
1279+
bytes += cpum_cf_read_setsize(i) * sizeof(u64) +
12741280
sizeof(((struct s390_ctrset_setdata *)0)->set) +
12751281
sizeof(((struct s390_ctrset_setdata *)0)->no_cnts);
12761282
}
12771283
bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids *
12781284
(bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) +
12791285
sizeof(((struct s390_ctrset_cpudata *)0)->no_sets));
1280-
put_cpu_ptr(&cpu_cf_events);
12811286
return bytes;
12821287
}
12831288

@@ -1351,7 +1356,7 @@ static void cfset_cpu_read(void *parm)
13511356

13521357
if (!(p->sets & cpumf_ctr_ctl[set]))
13531358
continue; /* Counter set not in list */
1354-
set_size = cpum_cf_ctrset_size(set, &cpuhw->info);
1359+
set_size = cpum_cf_read_setsize(set);
13551360
space = sizeof(cpuhw->data) - cpuhw->used;
13561361
space = cfset_cpuset_read(sp, set, set_size, space);
13571362
if (space) {
@@ -1562,16 +1567,13 @@ static void cfdiag_read(struct perf_event *event)
15621567

15631568
static int get_authctrsets(void)
15641569
{
1565-
struct cpu_cf_events *cpuhw;
15661570
unsigned long auth = 0;
15671571
enum cpumf_ctr_set i;
15681572

1569-
cpuhw = &get_cpu_var(cpu_cf_events);
15701573
for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
1571-
if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i])
1574+
if (cpumf_ctr_info.auth_ctl & cpumf_ctr_ctl[i])
15721575
auth |= cpumf_ctr_ctl[i];
15731576
}
1574-
put_cpu_var(cpu_cf_events);
15751577
return auth;
15761578
}
15771579

@@ -1709,7 +1711,7 @@ static size_t cfdiag_maxsize(struct cpumf_ctr_info *info)
17091711
enum cpumf_ctr_set i;
17101712

17111713
for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) {
1712-
size_t size = cpum_cf_ctrset_size(i, info);
1714+
size_t size = cpum_cf_read_setsize(i);
17131715

17141716
if (size)
17151717
max_size += size * sizeof(u64) +
@@ -1743,16 +1745,12 @@ static void cfdiag_get_cpu_speed(void)
17431745

17441746
static int cfset_init(void)
17451747
{
1746-
struct cpumf_ctr_info info;
17471748
size_t need;
17481749
int rc;
17491750

1750-
if (qctri(&info))
1751-
return -ENODEV;
1752-
17531751
cfdiag_get_cpu_speed();
17541752
/* Make sure the counter set data fits into predefined buffer. */
1755-
need = cfdiag_maxsize(&info);
1753+
need = cfdiag_maxsize(&cpumf_ctr_info);
17561754
if (need > sizeof(((struct cpu_cf_events *)0)->start)) {
17571755
pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n",
17581756
need);

0 commit comments

Comments
 (0)