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