1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141#include <endian.h>
142#include <errno.h>
143#include <byteswap.h>
144#include <inttypes.h>
145#include <linux/kernel.h>
146#include <linux/types.h>
147#include <linux/bitops.h>
148#include <linux/log2.h>
149#include <linux/zalloc.h>
150
151#include <sys/stat.h>
152#include <sys/types.h>
153
154#include "cpumap.h"
155#include "color.h"
156#include "evsel.h"
157#include "evlist.h"
158#include "machine.h"
159#include "session.h"
160#include "thread.h"
161#include "debug.h"
162#include "auxtrace.h"
163#include "s390-cpumsf.h"
164#include "s390-cpumsf-kernel.h"
165#include "s390-cpumcf-kernel.h"
166#include "config.h"
167
168struct s390_cpumsf {
169 struct auxtrace auxtrace;
170 struct auxtrace_queues queues;
171 struct auxtrace_heap heap;
172 struct perf_session *session;
173 struct machine *machine;
174 u32 auxtrace_type;
175 u32 pmu_type;
176 u16 machine_type;
177 bool data_queued;
178 bool use_logfile;
179 char *logdir;
180};
181
182struct s390_cpumsf_queue {
183 struct s390_cpumsf *sf;
184 unsigned int queue_nr;
185 struct auxtrace_buffer *buffer;
186 int cpu;
187 FILE *logfile;
188 FILE *logfile_ctr;
189};
190
191
192
193
194
195
196static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf,
197 struct perf_sample *sample)
198{
199 struct s390_cpumsf_queue *sfq;
200 struct auxtrace_queue *q;
201 int rc = 0;
202
203 if (!sf->use_logfile || sf->queues.nr_queues <= sample->cpu)
204 return rc;
205
206 q = &sf->queues.queue_array[sample->cpu];
207 sfq = q->priv;
208 if (!sfq)
209 return rc;
210
211 if (!sfq->logfile_ctr) {
212 char *name;
213
214 rc = (sf->logdir)
215 ? asprintf(&name, "%s/aux.ctr.%02x",
216 sf->logdir, sample->cpu)
217 : asprintf(&name, "aux.ctr.%02x", sample->cpu);
218 if (rc > 0)
219 sfq->logfile_ctr = fopen(name, "w");
220 if (sfq->logfile_ctr == NULL) {
221 pr_err("Failed to open counter set log file %s, "
222 "continue...\n", name);
223 rc = 1;
224 }
225 free(name);
226 }
227
228 if (sfq->logfile_ctr) {
229
230 size_t n = fwrite(sample->raw_data, sample->raw_size - 4, 1,
231 sfq->logfile_ctr);
232 if (n != 1) {
233 pr_err("Failed to write counter set data\n");
234 rc = 1;
235 }
236 }
237 return rc;
238}
239
240
241
242
243
244static bool s390_cpumsf_basic_show(const char *color, size_t pos,
245 struct hws_basic_entry *basicp)
246{
247 struct hws_basic_entry *basic = basicp;
248#if __BYTE_ORDER == __LITTLE_ENDIAN
249 struct hws_basic_entry local;
250 unsigned long long word = be64toh(*(unsigned long long *)basicp);
251
252 memset(&local, 0, sizeof(local));
253 local.def = be16toh(basicp->def);
254 local.prim_asn = word & 0xffff;
255 local.CL = word >> 30 & 0x3;
256 local.I = word >> 32 & 0x1;
257 local.AS = word >> 33 & 0x3;
258 local.P = word >> 35 & 0x1;
259 local.W = word >> 36 & 0x1;
260 local.T = word >> 37 & 0x1;
261 local.U = word >> 40 & 0xf;
262 local.ia = be64toh(basicp->ia);
263 local.gpp = be64toh(basicp->gpp);
264 local.hpp = be64toh(basicp->hpp);
265 basic = &local;
266#endif
267 if (basic->def != 1) {
268 pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
269 return false;
270 }
271 color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x"
272 " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
273 "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
274 pos, basic->def, basic->U,
275 basic->T ? 'T' : ' ',
276 basic->W ? 'W' : ' ',
277 basic->P ? 'P' : ' ',
278 basic->I ? 'I' : ' ',
279 basic->AS, basic->prim_asn, basic->ia, basic->CL,
280 basic->hpp, basic->gpp);
281 return true;
282}
283
284
285
286
287
288static bool s390_cpumsf_diag_show(const char *color, size_t pos,
289 struct hws_diag_entry *diagp)
290{
291 struct hws_diag_entry *diag = diagp;
292#if __BYTE_ORDER == __LITTLE_ENDIAN
293 struct hws_diag_entry local;
294 unsigned long long word = be64toh(*(unsigned long long *)diagp);
295
296 local.def = be16toh(diagp->def);
297 local.I = word >> 32 & 0x1;
298 diag = &local;
299#endif
300 if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
301 pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
302 return false;
303 }
304 color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n",
305 pos, diag->def, diag->I ? 'I' : ' ');
306 return true;
307}
308
309
310static unsigned long long trailer_timestamp(struct hws_trailer_entry *te,
311 int idx)
312{
313
314
315
316 unsigned long long ts;
317
318 memcpy(&ts, &te->timestamp[idx], sizeof(ts));
319 return be64toh(ts);
320}
321
322
323static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
324 struct hws_trailer_entry *te)
325{
326#if __BYTE_ORDER == __LITTLE_ENDIAN
327 struct hws_trailer_entry local;
328 const unsigned long long flags = be64toh(te->flags);
329
330 memset(&local, 0, sizeof(local));
331 local.f = flags >> 63 & 0x1;
332 local.a = flags >> 62 & 0x1;
333 local.t = flags >> 61 & 0x1;
334 local.bsdes = be16toh((flags >> 16 & 0xffff));
335 local.dsdes = be16toh((flags & 0xffff));
336 memcpy(&local.timestamp, te->timestamp, sizeof(te->timestamp));
337 local.overflow = be64toh(te->overflow);
338 local.clock_base = be64toh(te->progusage[0]) >> 63 & 1;
339 local.progusage2 = be64toh(te->progusage2);
340 te = &local;
341#endif
342 if (te->bsdes != sizeof(struct hws_basic_entry)) {
343 pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
344 return false;
345 }
346 color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
347 " dsdes:%d Overflow:%lld Time:%#llx\n"
348 "\t\tC:%d TOD:%#lx\n",
349 pos,
350 te->f ? 'F' : ' ',
351 te->a ? 'A' : ' ',
352 te->t ? 'T' : ' ',
353 te->bsdes, te->dsdes, te->overflow,
354 trailer_timestamp(te, te->clock_base),
355 te->clock_base, te->progusage2);
356 return true;
357}
358
359
360
361
362
363
364
365
366
367
368
369
370
371static bool s390_cpumsf_validate(int machine_type,
372 unsigned char *buf, size_t len,
373 unsigned short *bsdes,
374 unsigned short *dsdes)
375{
376 struct hws_basic_entry *basic = (struct hws_basic_entry *)buf;
377 struct hws_trailer_entry *te;
378
379 *dsdes = *bsdes = 0;
380 if (len & (S390_CPUMSF_PAGESZ - 1))
381 return false;
382 if (be16toh(basic->def) != 1)
383 return false;
384
385 te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
386 - sizeof(*te));
387 *bsdes = be16toh(te->bsdes);
388 *dsdes = be16toh(te->dsdes);
389 if (!te->bsdes && !te->dsdes) {
390
391 switch (machine_type) {
392 case 2097:
393 case 2098:
394 *dsdes = 64;
395 *bsdes = 32;
396 break;
397 case 2817:
398 case 2818:
399 *dsdes = 74;
400 *bsdes = 32;
401 break;
402 case 2827:
403 case 2828:
404 *dsdes = 85;
405 *bsdes = 32;
406 break;
407 case 2964:
408 case 2965:
409 *dsdes = 112;
410 *bsdes = 32;
411 break;
412 default:
413
414 return false;
415 }
416 }
417 return true;
418}
419
420
421static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos)
422{
423 size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry);
424
425 if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz)
426 return false;
427 return true;
428}
429
430
431
432
433static void s390_cpumsf_dump(struct s390_cpumsf *sf,
434 unsigned char *buf, size_t len)
435{
436 const char *color = PERF_COLOR_BLUE;
437 struct hws_basic_entry *basic;
438 struct hws_diag_entry *diag;
439 unsigned short bsdes, dsdes;
440 size_t pos = 0;
441
442 color_fprintf(stdout, color,
443 ". ... s390 AUX data: size %zu bytes\n",
444 len);
445
446 if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
447 &dsdes)) {
448 pr_err("Invalid AUX trace data block size:%zu"
449 " (type:%d bsdes:%hd dsdes:%hd)\n",
450 len, sf->machine_type, bsdes, dsdes);
451 return;
452 }
453
454
455
456
457 while (pos < len) {
458
459 basic = (struct hws_basic_entry *)(buf + pos);
460 if (s390_cpumsf_basic_show(color, pos, basic))
461 pos += bsdes;
462 else
463 return;
464
465
466 diag = (struct hws_diag_entry *)(buf + pos);
467 if (s390_cpumsf_diag_show(color, pos, diag))
468 pos += dsdes;
469 else
470 return;
471
472
473 if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
474
475 struct hws_trailer_entry te;
476
477 pos = (pos + S390_CPUMSF_PAGESZ)
478 & ~(S390_CPUMSF_PAGESZ - 1);
479 pos -= sizeof(te);
480 memcpy(&te, buf + pos, sizeof(te));
481
482
483
484 te.bsdes = bsdes;
485 te.dsdes = dsdes;
486 if (s390_cpumsf_trailer_show(color, pos, &te))
487 pos += sizeof(te);
488 else
489 return;
490 }
491 }
492}
493
494static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
495 size_t len)
496{
497 printf(".\n");
498 s390_cpumsf_dump(sf, buf, len);
499}
500
501#define S390_LPP_PID_MASK 0xffffffff
502
503static bool s390_cpumsf_make_event(size_t pos,
504 struct hws_basic_entry *basic,
505 struct s390_cpumsf_queue *sfq)
506{
507 struct perf_sample sample = {
508 .ip = basic->ia,
509 .pid = basic->hpp & S390_LPP_PID_MASK,
510 .tid = basic->hpp & S390_LPP_PID_MASK,
511 .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN,
512 .cpu = sfq->cpu,
513 .period = 1
514 };
515 union perf_event event;
516
517 memset(&event, 0, sizeof(event));
518 if (basic->CL == 1)
519 sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
520 : PERF_RECORD_MISC_KERNEL;
521 else if (basic->CL == 2)
522 sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
523 : PERF_RECORD_MISC_GUEST_KERNEL;
524 else if (basic->gpp || basic->prim_asn != 0xffff)
525
526 sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
527 : PERF_RECORD_MISC_GUEST_KERNEL;
528 else
529 sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
530 : PERF_RECORD_MISC_KERNEL;
531
532 event.sample.header.type = PERF_RECORD_SAMPLE;
533 event.sample.header.misc = sample.cpumode;
534 event.sample.header.size = sizeof(struct perf_event_header);
535
536 pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
537 __func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
538 sample.tid, sample.cpumode, sample.cpu);
539 if (perf_session__deliver_synth_event(sfq->sf->session, &event,
540 &sample)) {
541 pr_err("s390 Auxiliary Trace: failed to deliver event\n");
542 return false;
543 }
544 return true;
545}
546
547static unsigned long long get_trailer_time(const unsigned char *buf)
548{
549 struct hws_trailer_entry *te;
550 unsigned long long aux_time, progusage2;
551 bool clock_base;
552
553 te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
554 - sizeof(*te));
555
556#if __BYTE_ORDER == __LITTLE_ENDIAN
557 clock_base = be64toh(te->progusage[0]) >> 63 & 0x1;
558 progusage2 = be64toh(te->progusage[1]);
559#else
560 clock_base = te->clock_base;
561 progusage2 = te->progusage2;
562#endif
563 if (!clock_base)
564 return 0;
565
566
567
568
569
570 aux_time = trailer_timestamp(te, clock_base) - progusage2;
571 aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9);
572 return aux_time;
573}
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
601{
602 struct s390_cpumsf *sf = sfq->sf;
603 unsigned char *buf = sfq->buffer->use_data;
604 size_t len = sfq->buffer->use_size;
605 struct hws_basic_entry *basic;
606 unsigned short bsdes, dsdes;
607 size_t pos = 0;
608 int err = 1;
609 u64 aux_ts;
610
611 if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
612 &dsdes)) {
613 *ts = ~0ULL;
614 return -1;
615 }
616
617
618
619
620
621
622 aux_ts = get_trailer_time(buf);
623 if (!aux_ts) {
624 pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n",
625 (s64)sfq->buffer->data_offset);
626 aux_ts = ~0ULL;
627 goto out;
628 }
629 if (aux_ts > *ts) {
630 *ts = aux_ts;
631 return 0;
632 }
633
634 while (pos < len) {
635
636 basic = (struct hws_basic_entry *)(buf + pos);
637 if (s390_cpumsf_make_event(pos, basic, sfq))
638 pos += bsdes;
639 else {
640 err = -EBADF;
641 goto out;
642 }
643
644 pos += dsdes;
645
646
647 if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
648 pos = (pos + S390_CPUMSF_PAGESZ)
649 & ~(S390_CPUMSF_PAGESZ - 1);
650
651 if (pos >= len)
652 break;
653 aux_ts = get_trailer_time(buf + pos);
654 if (!aux_ts) {
655 aux_ts = ~0ULL;
656 goto out;
657 }
658 if (aux_ts > *ts) {
659 *ts = aux_ts;
660 sfq->buffer->use_data += pos;
661 sfq->buffer->use_size -= pos;
662 return 0;
663 }
664 }
665 }
666out:
667 *ts = aux_ts;
668 sfq->buffer->use_size = 0;
669 sfq->buffer->use_data = NULL;
670 return err;
671}
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
694 u64 *ts)
695{
696
697 struct auxtrace_buffer *buffer;
698 struct auxtrace_queue *queue;
699 int err;
700
701 queue = &sfq->sf->queues.queue_array[sfq->queue_nr];
702
703
704
705
706
707
708
709 if (sfq->buffer == NULL) {
710 sfq->buffer = buffer = auxtrace_buffer__next(queue,
711 sfq->buffer);
712 if (!buffer) {
713 *ts = ~0ULL;
714 return 1;
715 }
716
717 if (buffer->data) {
718 buffer->use_size = buffer->size;
719 buffer->use_data = buffer->data;
720 }
721 if (sfq->logfile) {
722 size_t rc = fwrite(buffer->data, buffer->size, 1,
723 sfq->logfile);
724 if (rc != 1)
725 pr_err("Failed to write auxiliary data\n");
726 }
727 } else
728 buffer = sfq->buffer;
729
730 if (!buffer->data) {
731 int fd = perf_data__fd(sfq->sf->session->data);
732
733 buffer->data = auxtrace_buffer__get_data(buffer, fd);
734 if (!buffer->data)
735 return -ENOMEM;
736 buffer->use_size = buffer->size;
737 buffer->use_data = buffer->data;
738
739 if (sfq->logfile) {
740 size_t rc = fwrite(buffer->data, buffer->size, 1,
741 sfq->logfile);
742 if (rc != 1)
743 pr_err("Failed to write auxiliary data\n");
744 }
745 }
746 pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
747 __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
748 buffer->size, buffer->use_size);
749 err = s390_cpumsf_samples(sfq, ts);
750
751
752
753
754
755
756
757 if (err) {
758 sfq->buffer = NULL;
759 list_del_init(&buffer->list);
760 auxtrace_buffer__free(buffer);
761 if (err > 0)
762 err = 0;
763 }
764 return err;
765}
766
767static struct s390_cpumsf_queue *
768s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr)
769{
770 struct s390_cpumsf_queue *sfq;
771
772 sfq = zalloc(sizeof(struct s390_cpumsf_queue));
773 if (sfq == NULL)
774 return NULL;
775
776 sfq->sf = sf;
777 sfq->queue_nr = queue_nr;
778 sfq->cpu = -1;
779 if (sf->use_logfile) {
780 char *name;
781 int rc;
782
783 rc = (sf->logdir)
784 ? asprintf(&name, "%s/aux.smp.%02x",
785 sf->logdir, queue_nr)
786 : asprintf(&name, "aux.smp.%02x", queue_nr);
787 if (rc > 0)
788 sfq->logfile = fopen(name, "w");
789 if (sfq->logfile == NULL) {
790 pr_err("Failed to open auxiliary log file %s,"
791 "continue...\n", name);
792 sf->use_logfile = false;
793 }
794 free(name);
795 }
796 return sfq;
797}
798
799static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf,
800 struct auxtrace_queue *queue,
801 unsigned int queue_nr, u64 ts)
802{
803 struct s390_cpumsf_queue *sfq = queue->priv;
804
805 if (list_empty(&queue->head))
806 return 0;
807
808 if (sfq == NULL) {
809 sfq = s390_cpumsf_alloc_queue(sf, queue_nr);
810 if (!sfq)
811 return -ENOMEM;
812 queue->priv = sfq;
813
814 if (queue->cpu != -1)
815 sfq->cpu = queue->cpu;
816 }
817 return auxtrace_heap__add(&sf->heap, queue_nr, ts);
818}
819
820static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts)
821{
822 unsigned int i;
823 int ret = 0;
824
825 for (i = 0; i < sf->queues.nr_queues; i++) {
826 ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i],
827 i, ts);
828 if (ret)
829 break;
830 }
831 return ret;
832}
833
834static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts)
835{
836 if (!sf->queues.new_data)
837 return 0;
838
839 sf->queues.new_data = false;
840 return s390_cpumsf_setup_queues(sf, ts);
841}
842
843static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp)
844{
845 unsigned int queue_nr;
846 u64 ts;
847 int ret;
848
849 while (1) {
850 struct auxtrace_queue *queue;
851 struct s390_cpumsf_queue *sfq;
852
853 if (!sf->heap.heap_cnt)
854 return 0;
855
856 if (sf->heap.heap_array[0].ordinal >= timestamp)
857 return 0;
858
859 queue_nr = sf->heap.heap_array[0].queue_nr;
860 queue = &sf->queues.queue_array[queue_nr];
861 sfq = queue->priv;
862
863 auxtrace_heap__pop(&sf->heap);
864 if (sf->heap.heap_cnt) {
865 ts = sf->heap.heap_array[0].ordinal + 1;
866 if (ts > timestamp)
867 ts = timestamp;
868 } else {
869 ts = timestamp;
870 }
871
872 ret = s390_cpumsf_run_decoder(sfq, &ts);
873 if (ret < 0) {
874 auxtrace_heap__add(&sf->heap, queue_nr, ts);
875 return ret;
876 }
877 if (!ret) {
878 ret = auxtrace_heap__add(&sf->heap, queue_nr, ts);
879 if (ret < 0)
880 return ret;
881 }
882 }
883 return 0;
884}
885
886static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu,
887 pid_t pid, pid_t tid, u64 ip, u64 timestamp)
888{
889 char msg[MAX_AUXTRACE_ERROR_MSG];
890 union perf_event event;
891 int err;
892
893 strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1);
894 auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
895 code, cpu, pid, tid, ip, msg, timestamp);
896
897 err = perf_session__deliver_synth_event(sf->session, &event, NULL);
898 if (err)
899 pr_err("s390 Auxiliary Trace: failed to deliver error event,"
900 "error %d\n", err);
901 return err;
902}
903
904static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
905{
906 return s390_cpumsf_synth_error(sf, 1, sample->cpu,
907 sample->pid, sample->tid, 0,
908 sample->time);
909}
910
911static int
912s390_cpumsf_process_event(struct perf_session *session,
913 union perf_event *event,
914 struct perf_sample *sample,
915 struct perf_tool *tool)
916{
917 struct s390_cpumsf *sf = container_of(session->auxtrace,
918 struct s390_cpumsf,
919 auxtrace);
920 u64 timestamp = sample->time;
921 struct perf_evsel *ev_bc000;
922
923 int err = 0;
924
925 if (dump_trace)
926 return 0;
927
928 if (!tool->ordered_events) {
929 pr_err("s390 Auxiliary Trace requires ordered events\n");
930 return -EINVAL;
931 }
932
933 if (event->header.type == PERF_RECORD_SAMPLE &&
934 sample->raw_size) {
935
936 ev_bc000 = perf_evlist__event2evsel(session->evlist, event);
937 if (ev_bc000 &&
938 ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG)
939 err = s390_cpumcf_dumpctr(sf, sample);
940 return err;
941 }
942
943 if (event->header.type == PERF_RECORD_AUX &&
944 event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
945 return s390_cpumsf_lost(sf, sample);
946
947 if (timestamp) {
948 err = s390_cpumsf_update_queues(sf, timestamp);
949 if (!err)
950 err = s390_cpumsf_process_queues(sf, timestamp);
951 }
952 return err;
953}
954
955struct s390_cpumsf_synth {
956 struct perf_tool cpumsf_tool;
957 struct perf_session *session;
958};
959
960static int
961s390_cpumsf_process_auxtrace_event(struct perf_session *session,
962 union perf_event *event __maybe_unused,
963 struct perf_tool *tool __maybe_unused)
964{
965 struct s390_cpumsf *sf = container_of(session->auxtrace,
966 struct s390_cpumsf,
967 auxtrace);
968
969 int fd = perf_data__fd(session->data);
970 struct auxtrace_buffer *buffer;
971 off_t data_offset;
972 int err;
973
974 if (sf->data_queued)
975 return 0;
976
977 if (perf_data__is_pipe(session->data)) {
978 data_offset = 0;
979 } else {
980 data_offset = lseek(fd, 0, SEEK_CUR);
981 if (data_offset == -1)
982 return -errno;
983 }
984
985 err = auxtrace_queues__add_event(&sf->queues, session, event,
986 data_offset, &buffer);
987 if (err)
988 return err;
989
990
991 if (dump_trace) {
992 if (auxtrace_buffer__get_data(buffer, fd)) {
993 s390_cpumsf_dump_event(sf, buffer->data,
994 buffer->size);
995 auxtrace_buffer__put_data(buffer);
996 }
997 }
998 return 0;
999}
1000
1001static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused)
1002{
1003}
1004
1005static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
1006 struct perf_tool *tool __maybe_unused)
1007{
1008 return 0;
1009}
1010
1011static void s390_cpumsf_free_queues(struct perf_session *session)
1012{
1013 struct s390_cpumsf *sf = container_of(session->auxtrace,
1014 struct s390_cpumsf,
1015 auxtrace);
1016 struct auxtrace_queues *queues = &sf->queues;
1017 unsigned int i;
1018
1019 for (i = 0; i < queues->nr_queues; i++) {
1020 struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *)
1021 queues->queue_array[i].priv;
1022
1023 if (sfq != NULL) {
1024 if (sfq->logfile) {
1025 fclose(sfq->logfile);
1026 sfq->logfile = NULL;
1027 }
1028 if (sfq->logfile_ctr) {
1029 fclose(sfq->logfile_ctr);
1030 sfq->logfile_ctr = NULL;
1031 }
1032 }
1033 zfree(&queues->queue_array[i].priv);
1034 }
1035 auxtrace_queues__free(queues);
1036}
1037
1038static void s390_cpumsf_free(struct perf_session *session)
1039{
1040 struct s390_cpumsf *sf = container_of(session->auxtrace,
1041 struct s390_cpumsf,
1042 auxtrace);
1043
1044 auxtrace_heap__free(&sf->heap);
1045 s390_cpumsf_free_queues(session);
1046 session->auxtrace = NULL;
1047 zfree(&sf->logdir);
1048 free(sf);
1049}
1050
1051static int s390_cpumsf_get_type(const char *cpuid)
1052{
1053 int ret, family = 0;
1054
1055 ret = sscanf(cpuid, "%*[^,],%u", &family);
1056 return (ret == 1) ? family : 0;
1057}
1058
1059
1060
1061
1062
1063
1064static bool check_auxtrace_itrace(struct itrace_synth_opts *itops)
1065{
1066 bool ison = false;
1067
1068 if (!itops || !itops->set)
1069 return true;
1070 ison = itops->inject || itops->instructions || itops->branches ||
1071 itops->transactions || itops->ptwrites ||
1072 itops->pwr_events || itops->errors ||
1073 itops->dont_decode || itops->calls || itops->returns ||
1074 itops->callchain || itops->thread_stack ||
1075 itops->last_branch;
1076 if (!ison)
1077 return true;
1078 pr_err("Unsupported --itrace options specified\n");
1079 return false;
1080}
1081
1082
1083
1084
1085
1086static int s390_cpumsf__config(const char *var, const char *value, void *cb)
1087{
1088 struct s390_cpumsf *sf = cb;
1089 struct stat stbuf;
1090 int rc;
1091
1092 if (strcmp(var, "auxtrace.dumpdir"))
1093 return 0;
1094 sf->logdir = strdup(value);
1095 if (sf->logdir == NULL) {
1096 pr_err("Failed to find auxtrace log directory %s,"
1097 " continue with current directory...\n", value);
1098 return 1;
1099 }
1100 rc = stat(sf->logdir, &stbuf);
1101 if (rc == -1 || !S_ISDIR(stbuf.st_mode)) {
1102 pr_err("Missing auxtrace log directory %s,"
1103 " continue with current directory...\n", value);
1104 zfree(&sf->logdir);
1105 }
1106 return 1;
1107}
1108
1109int s390_cpumsf_process_auxtrace_info(union perf_event *event,
1110 struct perf_session *session)
1111{
1112 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
1113 struct s390_cpumsf *sf;
1114 int err;
1115
1116 if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event))
1117 return -EINVAL;
1118
1119 sf = zalloc(sizeof(struct s390_cpumsf));
1120 if (sf == NULL)
1121 return -ENOMEM;
1122
1123 if (!check_auxtrace_itrace(session->itrace_synth_opts)) {
1124 err = -EINVAL;
1125 goto err_free;
1126 }
1127 sf->use_logfile = session->itrace_synth_opts->log;
1128 if (sf->use_logfile)
1129 perf_config(s390_cpumsf__config, sf);
1130
1131 err = auxtrace_queues__init(&sf->queues);
1132 if (err)
1133 goto err_free;
1134
1135 sf->session = session;
1136 sf->machine = &session->machines.host;
1137 sf->auxtrace_type = auxtrace_info->type;
1138 sf->pmu_type = PERF_TYPE_RAW;
1139 sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid);
1140
1141 sf->auxtrace.process_event = s390_cpumsf_process_event;
1142 sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
1143 sf->auxtrace.flush_events = s390_cpumsf_flush;
1144 sf->auxtrace.free_events = s390_cpumsf_free_events;
1145 sf->auxtrace.free = s390_cpumsf_free;
1146 session->auxtrace = &sf->auxtrace;
1147
1148 if (dump_trace)
1149 return 0;
1150
1151 err = auxtrace_queues__process_index(&sf->queues, session);
1152 if (err)
1153 goto err_free_queues;
1154
1155 if (sf->queues.populated)
1156 sf->data_queued = true;
1157
1158 return 0;
1159
1160err_free_queues:
1161 auxtrace_queues__free(&sf->queues);
1162 session->auxtrace = NULL;
1163err_free:
1164 zfree(&sf->logdir);
1165 free(sf);
1166 return err;
1167}
1168