1c4bbd4ecSAthira Rajeev // SPDX-License-Identifier: GPL-2.0 2c4bbd4ecSAthira Rajeev /* 3c4bbd4ecSAthira Rajeev * VPA DTL PMU support 4c4bbd4ecSAthira Rajeev */ 5c4bbd4ecSAthira Rajeev 671feffa9SAthira Rajeev #include <linux/string.h> 7c4bbd4ecSAthira Rajeev #include <inttypes.h> 8c4bbd4ecSAthira Rajeev #include "color.h" 9c4bbd4ecSAthira Rajeev #include "evlist.h" 10c4bbd4ecSAthira Rajeev #include "session.h" 11c4bbd4ecSAthira Rajeev #include "auxtrace.h" 12c4bbd4ecSAthira Rajeev #include "data.h" 13c4bbd4ecSAthira Rajeev #include "machine.h" 14c4bbd4ecSAthira Rajeev #include "debug.h" 15c4bbd4ecSAthira Rajeev #include "powerpc-vpadtl.h" 16*cd1c3b73SAthira Rajeev #include "sample.h" 17*cd1c3b73SAthira Rajeev #include "tool.h" 18c4bbd4ecSAthira Rajeev 19c4bbd4ecSAthira Rajeev /* 20c4bbd4ecSAthira Rajeev * Structure to save the auxtrace queue 21c4bbd4ecSAthira Rajeev */ 22c4bbd4ecSAthira Rajeev struct powerpc_vpadtl { 23c4bbd4ecSAthira Rajeev struct auxtrace auxtrace; 24c4bbd4ecSAthira Rajeev struct auxtrace_queues queues; 25c4bbd4ecSAthira Rajeev struct auxtrace_heap heap; 26c4bbd4ecSAthira Rajeev u32 auxtrace_type; 27c4bbd4ecSAthira Rajeev struct perf_session *session; 28c4bbd4ecSAthira Rajeev struct machine *machine; 29c4bbd4ecSAthira Rajeev u32 pmu_type; 3071feffa9SAthira Rajeev u64 sample_id; 31c4bbd4ecSAthira Rajeev }; 32c4bbd4ecSAthira Rajeev 33c4bbd4ecSAthira Rajeev struct boottb_freq { 34c4bbd4ecSAthira Rajeev u64 boot_tb; 35c4bbd4ecSAthira Rajeev u64 tb_freq; 36c4bbd4ecSAthira Rajeev u64 timebase; 37c4bbd4ecSAthira Rajeev u64 padded[3]; 38c4bbd4ecSAthira Rajeev }; 39c4bbd4ecSAthira Rajeev 40c4bbd4ecSAthira Rajeev struct powerpc_vpadtl_queue { 41c4bbd4ecSAthira Rajeev struct powerpc_vpadtl *vpa; 42c4bbd4ecSAthira Rajeev unsigned int queue_nr; 43c4bbd4ecSAthira Rajeev struct auxtrace_buffer *buffer; 44c4bbd4ecSAthira Rajeev struct thread *thread; 45c4bbd4ecSAthira Rajeev bool on_heap; 46*cd1c3b73SAthira Rajeev struct powerpc_vpadtl_entry *dtl; 47*cd1c3b73SAthira Rajeev u64 timestamp; 48*cd1c3b73SAthira Rajeev unsigned long pkt_len; 49*cd1c3b73SAthira Rajeev unsigned long buf_len; 50*cd1c3b73SAthira Rajeev u64 boot_tb; 51*cd1c3b73SAthira Rajeev u64 tb_freq; 52*cd1c3b73SAthira Rajeev unsigned int tb_buffer; 53*cd1c3b73SAthira Rajeev unsigned int size; 54c4bbd4ecSAthira Rajeev bool done; 55c4bbd4ecSAthira Rajeev pid_t pid; 56c4bbd4ecSAthira Rajeev pid_t tid; 57c4bbd4ecSAthira Rajeev int cpu; 58c4bbd4ecSAthira Rajeev }; 59c4bbd4ecSAthira Rajeev 60c4bbd4ecSAthira Rajeev const char *dispatch_reasons[11] = { 61c4bbd4ecSAthira Rajeev "external_interrupt", 62c4bbd4ecSAthira Rajeev "firmware_internal_event", 63c4bbd4ecSAthira Rajeev "H_PROD", 64c4bbd4ecSAthira Rajeev "decrementer_interrupt", 65c4bbd4ecSAthira Rajeev "system_reset", 66c4bbd4ecSAthira Rajeev "firmware_internal_event", 67c4bbd4ecSAthira Rajeev "conferred_cycles", 68c4bbd4ecSAthira Rajeev "time_slice", 69c4bbd4ecSAthira Rajeev "virtual_memory_page_fault", 70c4bbd4ecSAthira Rajeev "expropriated_adjunct", 71c4bbd4ecSAthira Rajeev "priv_doorbell"}; 72c4bbd4ecSAthira Rajeev 73c4bbd4ecSAthira Rajeev const char *preempt_reasons[10] = { 74c4bbd4ecSAthira Rajeev "unused", 75c4bbd4ecSAthira Rajeev "firmware_internal_event", 76c4bbd4ecSAthira Rajeev "H_CEDE", 77c4bbd4ecSAthira Rajeev "H_CONFER", 78c4bbd4ecSAthira Rajeev "time_slice", 79c4bbd4ecSAthira Rajeev "migration_hibernation_page_fault", 80c4bbd4ecSAthira Rajeev "virtual_memory_page_fault", 81c4bbd4ecSAthira Rajeev "H_CONFER_ADJUNCT", 82c4bbd4ecSAthira Rajeev "hcall_adjunct", 83c4bbd4ecSAthira Rajeev "HDEC_adjunct"}; 84c4bbd4ecSAthira Rajeev 85c4bbd4ecSAthira Rajeev #define dtl_entry_size sizeof(struct powerpc_vpadtl_entry) 86c4bbd4ecSAthira Rajeev 87c4bbd4ecSAthira Rajeev /* 88c4bbd4ecSAthira Rajeev * Function to dump the dispatch trace data when perf report 89c4bbd4ecSAthira Rajeev * is invoked with -D 90c4bbd4ecSAthira Rajeev */ 91c4bbd4ecSAthira Rajeev static void powerpc_vpadtl_dump(struct powerpc_vpadtl *vpa __maybe_unused, 92c4bbd4ecSAthira Rajeev unsigned char *buf, size_t len) 93c4bbd4ecSAthira Rajeev { 94c4bbd4ecSAthira Rajeev struct powerpc_vpadtl_entry *dtl; 95c4bbd4ecSAthira Rajeev int pkt_len, pos = 0; 96c4bbd4ecSAthira Rajeev const char *color = PERF_COLOR_BLUE; 97c4bbd4ecSAthira Rajeev 98c4bbd4ecSAthira Rajeev color_fprintf(stdout, color, 99c4bbd4ecSAthira Rajeev ". ... VPA DTL PMU data: size %zu bytes, entries is %zu\n", 100c4bbd4ecSAthira Rajeev len, len/dtl_entry_size); 101c4bbd4ecSAthira Rajeev 102c4bbd4ecSAthira Rajeev if (len % dtl_entry_size) 103c4bbd4ecSAthira Rajeev len = len - (len % dtl_entry_size); 104c4bbd4ecSAthira Rajeev 105c4bbd4ecSAthira Rajeev while (len) { 106c4bbd4ecSAthira Rajeev pkt_len = dtl_entry_size; 107c4bbd4ecSAthira Rajeev printf("."); 108c4bbd4ecSAthira Rajeev color_fprintf(stdout, color, " %08x: ", pos); 109c4bbd4ecSAthira Rajeev dtl = (struct powerpc_vpadtl_entry *)buf; 110c4bbd4ecSAthira Rajeev if (dtl->timebase != 0) { 111c4bbd4ecSAthira Rajeev printf("dispatch_reason:%s, preempt_reason:%s, " 112c4bbd4ecSAthira Rajeev "enqueue_to_dispatch_time:%d, ready_to_enqueue_time:%d, " 113c4bbd4ecSAthira Rajeev "waiting_to_ready_time:%d\n", 114c4bbd4ecSAthira Rajeev dispatch_reasons[dtl->dispatch_reason], 115c4bbd4ecSAthira Rajeev preempt_reasons[dtl->preempt_reason], 116c4bbd4ecSAthira Rajeev be32_to_cpu(dtl->enqueue_to_dispatch_time), 117c4bbd4ecSAthira Rajeev be32_to_cpu(dtl->ready_to_enqueue_time), 118c4bbd4ecSAthira Rajeev be32_to_cpu(dtl->waiting_to_ready_time)); 119c4bbd4ecSAthira Rajeev } else { 120c4bbd4ecSAthira Rajeev struct boottb_freq *boot_tb = (struct boottb_freq *)buf; 121c4bbd4ecSAthira Rajeev 122c4bbd4ecSAthira Rajeev printf("boot_tb: %" PRIu64 ", tb_freq: %" PRIu64 "\n", 123c4bbd4ecSAthira Rajeev boot_tb->boot_tb, boot_tb->tb_freq); 124c4bbd4ecSAthira Rajeev } 125c4bbd4ecSAthira Rajeev 126c4bbd4ecSAthira Rajeev pos += pkt_len; 127c4bbd4ecSAthira Rajeev buf += pkt_len; 128c4bbd4ecSAthira Rajeev len -= pkt_len; 129c4bbd4ecSAthira Rajeev } 130c4bbd4ecSAthira Rajeev } 131c4bbd4ecSAthira Rajeev 132*cd1c3b73SAthira Rajeev static unsigned long long powerpc_vpadtl_timestamp(struct powerpc_vpadtl_queue *vpaq) 133*cd1c3b73SAthira Rajeev { 134*cd1c3b73SAthira Rajeev struct powerpc_vpadtl_entry *record = vpaq->dtl; 135*cd1c3b73SAthira Rajeev unsigned long long timestamp = 0; 136*cd1c3b73SAthira Rajeev unsigned long long boot_tb; 137*cd1c3b73SAthira Rajeev unsigned long long diff; 138*cd1c3b73SAthira Rajeev double result, div; 139*cd1c3b73SAthira Rajeev double boot_freq; 140*cd1c3b73SAthira Rajeev /* 141*cd1c3b73SAthira Rajeev * Formula used to get timestamp that can be co-related with 142*cd1c3b73SAthira Rajeev * other perf events: 143*cd1c3b73SAthira Rajeev * ((timbase from DTL entry - boot time) / frequency) * 1000000000 144*cd1c3b73SAthira Rajeev */ 145*cd1c3b73SAthira Rajeev if (record->timebase) { 146*cd1c3b73SAthira Rajeev boot_tb = vpaq->boot_tb; 147*cd1c3b73SAthira Rajeev boot_freq = vpaq->tb_freq; 148*cd1c3b73SAthira Rajeev diff = be64_to_cpu(record->timebase) - boot_tb; 149*cd1c3b73SAthira Rajeev div = diff / boot_freq; 150*cd1c3b73SAthira Rajeev result = div; 151*cd1c3b73SAthira Rajeev result = result * 1000000000; 152*cd1c3b73SAthira Rajeev timestamp = result; 153*cd1c3b73SAthira Rajeev } 154*cd1c3b73SAthira Rajeev 155*cd1c3b73SAthira Rajeev return timestamp; 156*cd1c3b73SAthira Rajeev } 157*cd1c3b73SAthira Rajeev 158c4bbd4ecSAthira Rajeev static struct powerpc_vpadtl *session_to_vpa(struct perf_session *session) 159c4bbd4ecSAthira Rajeev { 160c4bbd4ecSAthira Rajeev return container_of(session->auxtrace, struct powerpc_vpadtl, auxtrace); 161c4bbd4ecSAthira Rajeev } 162c4bbd4ecSAthira Rajeev 163c4bbd4ecSAthira Rajeev static void powerpc_vpadtl_dump_event(struct powerpc_vpadtl *vpa, unsigned char *buf, 164c4bbd4ecSAthira Rajeev size_t len) 165c4bbd4ecSAthira Rajeev { 166c4bbd4ecSAthira Rajeev printf(".\n"); 167c4bbd4ecSAthira Rajeev powerpc_vpadtl_dump(vpa, buf, len); 168c4bbd4ecSAthira Rajeev } 169c4bbd4ecSAthira Rajeev 170*cd1c3b73SAthira Rajeev static int powerpc_vpadtl_get_buffer(struct powerpc_vpadtl_queue *vpaq) 171c4bbd4ecSAthira Rajeev { 172*cd1c3b73SAthira Rajeev struct auxtrace_buffer *buffer = vpaq->buffer; 173*cd1c3b73SAthira Rajeev struct auxtrace_queues *queues = &vpaq->vpa->queues; 174*cd1c3b73SAthira Rajeev struct auxtrace_queue *queue; 175*cd1c3b73SAthira Rajeev 176*cd1c3b73SAthira Rajeev queue = &queues->queue_array[vpaq->queue_nr]; 177*cd1c3b73SAthira Rajeev buffer = auxtrace_buffer__next(queue, buffer); 178*cd1c3b73SAthira Rajeev 179*cd1c3b73SAthira Rajeev if (!buffer) 180c4bbd4ecSAthira Rajeev return 0; 181*cd1c3b73SAthira Rajeev 182*cd1c3b73SAthira Rajeev vpaq->buffer = buffer; 183*cd1c3b73SAthira Rajeev vpaq->size = buffer->size; 184*cd1c3b73SAthira Rajeev 185*cd1c3b73SAthira Rajeev /* If the aux_buffer doesn't have data associated, try to load it */ 186*cd1c3b73SAthira Rajeev if (!buffer->data) { 187*cd1c3b73SAthira Rajeev /* get the file desc associated with the perf data file */ 188*cd1c3b73SAthira Rajeev int fd = perf_data__fd(vpaq->vpa->session->data); 189*cd1c3b73SAthira Rajeev 190*cd1c3b73SAthira Rajeev buffer->data = auxtrace_buffer__get_data(buffer, fd); 191*cd1c3b73SAthira Rajeev if (!buffer->data) 192*cd1c3b73SAthira Rajeev return -ENOMEM; 193*cd1c3b73SAthira Rajeev } 194*cd1c3b73SAthira Rajeev 195*cd1c3b73SAthira Rajeev vpaq->buf_len = buffer->size; 196*cd1c3b73SAthira Rajeev 197*cd1c3b73SAthira Rajeev if (buffer->size % dtl_entry_size) 198*cd1c3b73SAthira Rajeev vpaq->buf_len = buffer->size - (buffer->size % dtl_entry_size); 199*cd1c3b73SAthira Rajeev 200*cd1c3b73SAthira Rajeev if (vpaq->tb_buffer != buffer->buffer_nr) { 201*cd1c3b73SAthira Rajeev vpaq->pkt_len = 0; 202*cd1c3b73SAthira Rajeev vpaq->tb_buffer = 0; 203*cd1c3b73SAthira Rajeev } 204*cd1c3b73SAthira Rajeev 205*cd1c3b73SAthira Rajeev return 1; 206*cd1c3b73SAthira Rajeev } 207*cd1c3b73SAthira Rajeev 208*cd1c3b73SAthira Rajeev /* 209*cd1c3b73SAthira Rajeev * The first entry in the queue for VPA DTL PMU has the boot timebase, 210*cd1c3b73SAthira Rajeev * frequency details which are needed to get timestamp which is required to 211*cd1c3b73SAthira Rajeev * correlate with other events. Save the boot_tb and tb_freq as part of 212*cd1c3b73SAthira Rajeev * powerpc_vpadtl_queue. The very next entry is the actual trace data to 213*cd1c3b73SAthira Rajeev * be returned. 214*cd1c3b73SAthira Rajeev */ 215*cd1c3b73SAthira Rajeev static int powerpc_vpadtl_decode(struct powerpc_vpadtl_queue *vpaq) 216*cd1c3b73SAthira Rajeev { 217*cd1c3b73SAthira Rajeev int ret; 218*cd1c3b73SAthira Rajeev char *buf; 219*cd1c3b73SAthira Rajeev struct boottb_freq *boottb; 220*cd1c3b73SAthira Rajeev 221*cd1c3b73SAthira Rajeev ret = powerpc_vpadtl_get_buffer(vpaq); 222*cd1c3b73SAthira Rajeev if (ret <= 0) 223*cd1c3b73SAthira Rajeev return ret; 224*cd1c3b73SAthira Rajeev 225*cd1c3b73SAthira Rajeev boottb = (struct boottb_freq *)vpaq->buffer->data; 226*cd1c3b73SAthira Rajeev if (boottb->timebase == 0) { 227*cd1c3b73SAthira Rajeev vpaq->boot_tb = boottb->boot_tb; 228*cd1c3b73SAthira Rajeev vpaq->tb_freq = boottb->tb_freq; 229*cd1c3b73SAthira Rajeev vpaq->pkt_len += dtl_entry_size; 230*cd1c3b73SAthira Rajeev } 231*cd1c3b73SAthira Rajeev 232*cd1c3b73SAthira Rajeev buf = vpaq->buffer->data; 233*cd1c3b73SAthira Rajeev buf += vpaq->pkt_len; 234*cd1c3b73SAthira Rajeev vpaq->dtl = (struct powerpc_vpadtl_entry *)buf; 235*cd1c3b73SAthira Rajeev 236*cd1c3b73SAthira Rajeev vpaq->tb_buffer = vpaq->buffer->buffer_nr; 237*cd1c3b73SAthira Rajeev vpaq->buffer = NULL; 238*cd1c3b73SAthira Rajeev vpaq->buf_len = 0; 239*cd1c3b73SAthira Rajeev 240*cd1c3b73SAthira Rajeev return 1; 241*cd1c3b73SAthira Rajeev } 242*cd1c3b73SAthira Rajeev 243*cd1c3b73SAthira Rajeev static struct powerpc_vpadtl_queue *powerpc_vpadtl__alloc_queue(struct powerpc_vpadtl *vpa, 244*cd1c3b73SAthira Rajeev unsigned int queue_nr) 245*cd1c3b73SAthira Rajeev { 246*cd1c3b73SAthira Rajeev struct powerpc_vpadtl_queue *vpaq; 247*cd1c3b73SAthira Rajeev 248*cd1c3b73SAthira Rajeev vpaq = zalloc(sizeof(*vpaq)); 249*cd1c3b73SAthira Rajeev if (!vpaq) 250*cd1c3b73SAthira Rajeev return NULL; 251*cd1c3b73SAthira Rajeev 252*cd1c3b73SAthira Rajeev vpaq->vpa = vpa; 253*cd1c3b73SAthira Rajeev vpaq->queue_nr = queue_nr; 254*cd1c3b73SAthira Rajeev 255*cd1c3b73SAthira Rajeev return vpaq; 256*cd1c3b73SAthira Rajeev } 257*cd1c3b73SAthira Rajeev 258*cd1c3b73SAthira Rajeev /* 259*cd1c3b73SAthira Rajeev * When the Dispatch Trace Log data is collected along with other events 260*cd1c3b73SAthira Rajeev * like sched tracepoint events, it needs to be correlated and present 261*cd1c3b73SAthira Rajeev * interleaved along with these events. Perf events can be collected 262*cd1c3b73SAthira Rajeev * parallely across the CPUs. 263*cd1c3b73SAthira Rajeev * 264*cd1c3b73SAthira Rajeev * An auxtrace_queue is created for each CPU. Data within each queue is in 265*cd1c3b73SAthira Rajeev * increasing order of timestamp. Allocate and setup auxtrace queues here. 266*cd1c3b73SAthira Rajeev * All auxtrace queues is maintained in auxtrace heap in the increasing order 267*cd1c3b73SAthira Rajeev * of timestamp. So always the lowest timestamp (entries to be processed first) 268*cd1c3b73SAthira Rajeev * is on top of the heap. 269*cd1c3b73SAthira Rajeev * 270*cd1c3b73SAthira Rajeev * To add to auxtrace heap, fetch the timestamp from first DTL entry 271*cd1c3b73SAthira Rajeev * for each of the queue. 272*cd1c3b73SAthira Rajeev */ 273*cd1c3b73SAthira Rajeev static int powerpc_vpadtl__setup_queue(struct powerpc_vpadtl *vpa, 274*cd1c3b73SAthira Rajeev struct auxtrace_queue *queue, 275*cd1c3b73SAthira Rajeev unsigned int queue_nr) 276*cd1c3b73SAthira Rajeev { 277*cd1c3b73SAthira Rajeev struct powerpc_vpadtl_queue *vpaq = queue->priv; 278*cd1c3b73SAthira Rajeev 279*cd1c3b73SAthira Rajeev if (list_empty(&queue->head) || vpaq) 280*cd1c3b73SAthira Rajeev return 0; 281*cd1c3b73SAthira Rajeev 282*cd1c3b73SAthira Rajeev vpaq = powerpc_vpadtl__alloc_queue(vpa, queue_nr); 283*cd1c3b73SAthira Rajeev if (!vpaq) 284*cd1c3b73SAthira Rajeev return -ENOMEM; 285*cd1c3b73SAthira Rajeev 286*cd1c3b73SAthira Rajeev queue->priv = vpaq; 287*cd1c3b73SAthira Rajeev 288*cd1c3b73SAthira Rajeev if (queue->cpu != -1) 289*cd1c3b73SAthira Rajeev vpaq->cpu = queue->cpu; 290*cd1c3b73SAthira Rajeev 291*cd1c3b73SAthira Rajeev if (!vpaq->on_heap) { 292*cd1c3b73SAthira Rajeev int ret; 293*cd1c3b73SAthira Rajeev retry: 294*cd1c3b73SAthira Rajeev ret = powerpc_vpadtl_decode(vpaq); 295*cd1c3b73SAthira Rajeev if (!ret) 296*cd1c3b73SAthira Rajeev return 0; 297*cd1c3b73SAthira Rajeev 298*cd1c3b73SAthira Rajeev if (ret < 0) 299*cd1c3b73SAthira Rajeev goto retry; 300*cd1c3b73SAthira Rajeev 301*cd1c3b73SAthira Rajeev vpaq->timestamp = powerpc_vpadtl_timestamp(vpaq); 302*cd1c3b73SAthira Rajeev 303*cd1c3b73SAthira Rajeev ret = auxtrace_heap__add(&vpa->heap, queue_nr, vpaq->timestamp); 304*cd1c3b73SAthira Rajeev if (ret) 305*cd1c3b73SAthira Rajeev return ret; 306*cd1c3b73SAthira Rajeev vpaq->on_heap = true; 307*cd1c3b73SAthira Rajeev } 308*cd1c3b73SAthira Rajeev 309*cd1c3b73SAthira Rajeev return 0; 310*cd1c3b73SAthira Rajeev } 311*cd1c3b73SAthira Rajeev 312*cd1c3b73SAthira Rajeev static int powerpc_vpadtl__setup_queues(struct powerpc_vpadtl *vpa) 313*cd1c3b73SAthira Rajeev { 314*cd1c3b73SAthira Rajeev unsigned int i; 315*cd1c3b73SAthira Rajeev int ret; 316*cd1c3b73SAthira Rajeev 317*cd1c3b73SAthira Rajeev for (i = 0; i < vpa->queues.nr_queues; i++) { 318*cd1c3b73SAthira Rajeev ret = powerpc_vpadtl__setup_queue(vpa, &vpa->queues.queue_array[i], i); 319*cd1c3b73SAthira Rajeev if (ret) 320*cd1c3b73SAthira Rajeev return ret; 321*cd1c3b73SAthira Rajeev } 322*cd1c3b73SAthira Rajeev 323*cd1c3b73SAthira Rajeev return 0; 324*cd1c3b73SAthira Rajeev } 325*cd1c3b73SAthira Rajeev 326*cd1c3b73SAthira Rajeev static int powerpc_vpadtl__update_queues(struct powerpc_vpadtl *vpa) 327*cd1c3b73SAthira Rajeev { 328*cd1c3b73SAthira Rajeev if (vpa->queues.new_data) { 329*cd1c3b73SAthira Rajeev vpa->queues.new_data = false; 330*cd1c3b73SAthira Rajeev return powerpc_vpadtl__setup_queues(vpa); 331*cd1c3b73SAthira Rajeev } 332*cd1c3b73SAthira Rajeev 333*cd1c3b73SAthira Rajeev return 0; 334*cd1c3b73SAthira Rajeev } 335*cd1c3b73SAthira Rajeev 336*cd1c3b73SAthira Rajeev static int powerpc_vpadtl_process_event(struct perf_session *session, 337*cd1c3b73SAthira Rajeev union perf_event *event __maybe_unused, 338*cd1c3b73SAthira Rajeev struct perf_sample *sample, 339*cd1c3b73SAthira Rajeev const struct perf_tool *tool) 340*cd1c3b73SAthira Rajeev { 341*cd1c3b73SAthira Rajeev struct powerpc_vpadtl *vpa = session_to_vpa(session); 342*cd1c3b73SAthira Rajeev int err = 0; 343*cd1c3b73SAthira Rajeev 344*cd1c3b73SAthira Rajeev if (dump_trace) 345*cd1c3b73SAthira Rajeev return 0; 346*cd1c3b73SAthira Rajeev 347*cd1c3b73SAthira Rajeev if (!tool->ordered_events) { 348*cd1c3b73SAthira Rajeev pr_err("VPA requires ordered events\n"); 349*cd1c3b73SAthira Rajeev return -EINVAL; 350*cd1c3b73SAthira Rajeev } 351*cd1c3b73SAthira Rajeev 352*cd1c3b73SAthira Rajeev if (sample->time) { 353*cd1c3b73SAthira Rajeev err = powerpc_vpadtl__update_queues(vpa); 354*cd1c3b73SAthira Rajeev if (err) 355*cd1c3b73SAthira Rajeev return err; 356*cd1c3b73SAthira Rajeev } 357*cd1c3b73SAthira Rajeev 358*cd1c3b73SAthira Rajeev return err; 359c4bbd4ecSAthira Rajeev } 360c4bbd4ecSAthira Rajeev 361c4bbd4ecSAthira Rajeev /* 362c4bbd4ecSAthira Rajeev * Process PERF_RECORD_AUXTRACE records 363c4bbd4ecSAthira Rajeev */ 364c4bbd4ecSAthira Rajeev static int powerpc_vpadtl_process_auxtrace_event(struct perf_session *session, 365c4bbd4ecSAthira Rajeev union perf_event *event, 366c4bbd4ecSAthira Rajeev const struct perf_tool *tool __maybe_unused) 367c4bbd4ecSAthira Rajeev { 368c4bbd4ecSAthira Rajeev struct powerpc_vpadtl *vpa = session_to_vpa(session); 369c4bbd4ecSAthira Rajeev struct auxtrace_buffer *buffer; 370c4bbd4ecSAthira Rajeev int fd = perf_data__fd(session->data); 371c4bbd4ecSAthira Rajeev off_t data_offset; 372c4bbd4ecSAthira Rajeev int err; 373c4bbd4ecSAthira Rajeev 374c4bbd4ecSAthira Rajeev if (!dump_trace) 375c4bbd4ecSAthira Rajeev return 0; 376c4bbd4ecSAthira Rajeev 377c4bbd4ecSAthira Rajeev if (perf_data__is_pipe(session->data)) { 378c4bbd4ecSAthira Rajeev data_offset = 0; 379c4bbd4ecSAthira Rajeev } else { 380c4bbd4ecSAthira Rajeev data_offset = lseek(fd, 0, SEEK_CUR); 381c4bbd4ecSAthira Rajeev if (data_offset == -1) 382c4bbd4ecSAthira Rajeev return -errno; 383c4bbd4ecSAthira Rajeev } 384c4bbd4ecSAthira Rajeev 385c4bbd4ecSAthira Rajeev err = auxtrace_queues__add_event(&vpa->queues, session, event, 386c4bbd4ecSAthira Rajeev data_offset, &buffer); 387c4bbd4ecSAthira Rajeev 388c4bbd4ecSAthira Rajeev if (err) 389c4bbd4ecSAthira Rajeev return err; 390c4bbd4ecSAthira Rajeev 391c4bbd4ecSAthira Rajeev /* Dump here now we have copied a piped trace out of the pipe */ 392c4bbd4ecSAthira Rajeev if (auxtrace_buffer__get_data(buffer, fd)) { 393c4bbd4ecSAthira Rajeev powerpc_vpadtl_dump_event(vpa, buffer->data, buffer->size); 394c4bbd4ecSAthira Rajeev auxtrace_buffer__put_data(buffer); 395c4bbd4ecSAthira Rajeev } 396c4bbd4ecSAthira Rajeev 397c4bbd4ecSAthira Rajeev return 0; 398c4bbd4ecSAthira Rajeev } 399c4bbd4ecSAthira Rajeev 400c4bbd4ecSAthira Rajeev static int powerpc_vpadtl_flush(struct perf_session *session __maybe_unused, 401c4bbd4ecSAthira Rajeev const struct perf_tool *tool __maybe_unused) 402c4bbd4ecSAthira Rajeev { 403c4bbd4ecSAthira Rajeev return 0; 404c4bbd4ecSAthira Rajeev } 405c4bbd4ecSAthira Rajeev 406c4bbd4ecSAthira Rajeev static void powerpc_vpadtl_free_events(struct perf_session *session) 407c4bbd4ecSAthira Rajeev { 408c4bbd4ecSAthira Rajeev struct powerpc_vpadtl *vpa = session_to_vpa(session); 409c4bbd4ecSAthira Rajeev struct auxtrace_queues *queues = &vpa->queues; 410c4bbd4ecSAthira Rajeev 411c4bbd4ecSAthira Rajeev for (unsigned int i = 0; i < queues->nr_queues; i++) 412c4bbd4ecSAthira Rajeev zfree(&queues->queue_array[i].priv); 413c4bbd4ecSAthira Rajeev 414c4bbd4ecSAthira Rajeev auxtrace_queues__free(queues); 415c4bbd4ecSAthira Rajeev } 416c4bbd4ecSAthira Rajeev 417c4bbd4ecSAthira Rajeev static void powerpc_vpadtl_free(struct perf_session *session) 418c4bbd4ecSAthira Rajeev { 419c4bbd4ecSAthira Rajeev struct powerpc_vpadtl *vpa = session_to_vpa(session); 420c4bbd4ecSAthira Rajeev 421c4bbd4ecSAthira Rajeev auxtrace_heap__free(&vpa->heap); 422c4bbd4ecSAthira Rajeev powerpc_vpadtl_free_events(session); 423c4bbd4ecSAthira Rajeev session->auxtrace = NULL; 424c4bbd4ecSAthira Rajeev free(vpa); 425c4bbd4ecSAthira Rajeev } 426c4bbd4ecSAthira Rajeev 427c4bbd4ecSAthira Rajeev static const char * const powerpc_vpadtl_info_fmts[] = { 428c4bbd4ecSAthira Rajeev [POWERPC_VPADTL_TYPE] = " PMU Type %"PRId64"\n", 429c4bbd4ecSAthira Rajeev }; 430c4bbd4ecSAthira Rajeev 431c4bbd4ecSAthira Rajeev static void powerpc_vpadtl_print_info(__u64 *arr) 432c4bbd4ecSAthira Rajeev { 433c4bbd4ecSAthira Rajeev if (!dump_trace) 434c4bbd4ecSAthira Rajeev return; 435c4bbd4ecSAthira Rajeev 436c4bbd4ecSAthira Rajeev fprintf(stdout, powerpc_vpadtl_info_fmts[POWERPC_VPADTL_TYPE], arr[POWERPC_VPADTL_TYPE]); 437c4bbd4ecSAthira Rajeev } 438c4bbd4ecSAthira Rajeev 43971feffa9SAthira Rajeev static void set_event_name(struct evlist *evlist, u64 id, 44071feffa9SAthira Rajeev const char *name) 44171feffa9SAthira Rajeev { 44271feffa9SAthira Rajeev struct evsel *evsel; 44371feffa9SAthira Rajeev 44471feffa9SAthira Rajeev evlist__for_each_entry(evlist, evsel) { 44571feffa9SAthira Rajeev if (evsel->core.id && evsel->core.id[0] == id) { 44671feffa9SAthira Rajeev if (evsel->name) 44771feffa9SAthira Rajeev zfree(&evsel->name); 44871feffa9SAthira Rajeev evsel->name = strdup(name); 44971feffa9SAthira Rajeev break; 45071feffa9SAthira Rajeev } 45171feffa9SAthira Rajeev } 45271feffa9SAthira Rajeev } 45371feffa9SAthira Rajeev 45471feffa9SAthira Rajeev static int 45571feffa9SAthira Rajeev powerpc_vpadtl_synth_events(struct powerpc_vpadtl *vpa, struct perf_session *session) 45671feffa9SAthira Rajeev { 45771feffa9SAthira Rajeev struct evlist *evlist = session->evlist; 45871feffa9SAthira Rajeev struct evsel *evsel; 45971feffa9SAthira Rajeev struct perf_event_attr attr; 46071feffa9SAthira Rajeev bool found = false; 46171feffa9SAthira Rajeev u64 id; 46271feffa9SAthira Rajeev int err; 46371feffa9SAthira Rajeev 46471feffa9SAthira Rajeev evlist__for_each_entry(evlist, evsel) { 46571feffa9SAthira Rajeev if (strstarts(evsel->name, "vpa_dtl")) { 46671feffa9SAthira Rajeev found = true; 46771feffa9SAthira Rajeev break; 46871feffa9SAthira Rajeev } 46971feffa9SAthira Rajeev } 47071feffa9SAthira Rajeev 47171feffa9SAthira Rajeev if (!found) { 47271feffa9SAthira Rajeev pr_debug("No selected events with VPA trace data\n"); 47371feffa9SAthira Rajeev return 0; 47471feffa9SAthira Rajeev } 47571feffa9SAthira Rajeev 47671feffa9SAthira Rajeev memset(&attr, 0, sizeof(struct perf_event_attr)); 47771feffa9SAthira Rajeev attr.size = sizeof(struct perf_event_attr); 47871feffa9SAthira Rajeev attr.sample_type = evsel->core.attr.sample_type; 47971feffa9SAthira Rajeev attr.sample_id_all = evsel->core.attr.sample_id_all; 48071feffa9SAthira Rajeev attr.type = PERF_TYPE_SYNTH; 48171feffa9SAthira Rajeev attr.config = PERF_SYNTH_POWERPC_VPA_DTL; 48271feffa9SAthira Rajeev 48371feffa9SAthira Rajeev /* create new id val to be a fixed offset from evsel id */ 48471feffa9SAthira Rajeev id = evsel->core.id[0] + 1000000000; 48571feffa9SAthira Rajeev if (!id) 48671feffa9SAthira Rajeev id = 1; 48771feffa9SAthira Rajeev 48871feffa9SAthira Rajeev err = perf_session__deliver_synth_attr_event(session, &attr, id); 48971feffa9SAthira Rajeev if (err) 49071feffa9SAthira Rajeev return err; 49171feffa9SAthira Rajeev 49271feffa9SAthira Rajeev vpa->sample_id = id; 49371feffa9SAthira Rajeev set_event_name(evlist, id, "vpa-dtl"); 49471feffa9SAthira Rajeev 49571feffa9SAthira Rajeev return 0; 49671feffa9SAthira Rajeev } 49771feffa9SAthira Rajeev 498c4bbd4ecSAthira Rajeev /* 499c4bbd4ecSAthira Rajeev * Process the PERF_RECORD_AUXTRACE_INFO records and setup 500c4bbd4ecSAthira Rajeev * the infrastructure to process auxtrace events. PERF_RECORD_AUXTRACE_INFO 501c4bbd4ecSAthira Rajeev * is processed first since it is of type perf_user_event_type. 502c4bbd4ecSAthira Rajeev * Initialise the aux buffer queues using auxtrace_queues__init(). 503c4bbd4ecSAthira Rajeev * auxtrace_queue is created for each CPU. 504c4bbd4ecSAthira Rajeev */ 505c4bbd4ecSAthira Rajeev int powerpc_vpadtl_process_auxtrace_info(union perf_event *event, 506c4bbd4ecSAthira Rajeev struct perf_session *session) 507c4bbd4ecSAthira Rajeev { 508c4bbd4ecSAthira Rajeev struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; 509c4bbd4ecSAthira Rajeev size_t min_sz = sizeof(u64) * POWERPC_VPADTL_TYPE; 510c4bbd4ecSAthira Rajeev struct powerpc_vpadtl *vpa; 511c4bbd4ecSAthira Rajeev int err; 512c4bbd4ecSAthira Rajeev 513c4bbd4ecSAthira Rajeev if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + 514c4bbd4ecSAthira Rajeev min_sz) 515c4bbd4ecSAthira Rajeev return -EINVAL; 516c4bbd4ecSAthira Rajeev 517c4bbd4ecSAthira Rajeev vpa = zalloc(sizeof(struct powerpc_vpadtl)); 518c4bbd4ecSAthira Rajeev if (!vpa) 519c4bbd4ecSAthira Rajeev return -ENOMEM; 520c4bbd4ecSAthira Rajeev 521c4bbd4ecSAthira Rajeev err = auxtrace_queues__init(&vpa->queues); 522c4bbd4ecSAthira Rajeev if (err) 523c4bbd4ecSAthira Rajeev goto err_free; 524c4bbd4ecSAthira Rajeev 525c4bbd4ecSAthira Rajeev vpa->session = session; 526c4bbd4ecSAthira Rajeev vpa->machine = &session->machines.host; /* No kvm support */ 527c4bbd4ecSAthira Rajeev vpa->auxtrace_type = auxtrace_info->type; 528c4bbd4ecSAthira Rajeev vpa->pmu_type = auxtrace_info->priv[POWERPC_VPADTL_TYPE]; 529c4bbd4ecSAthira Rajeev 530c4bbd4ecSAthira Rajeev vpa->auxtrace.process_event = powerpc_vpadtl_process_event; 531c4bbd4ecSAthira Rajeev vpa->auxtrace.process_auxtrace_event = powerpc_vpadtl_process_auxtrace_event; 532c4bbd4ecSAthira Rajeev vpa->auxtrace.flush_events = powerpc_vpadtl_flush; 533c4bbd4ecSAthira Rajeev vpa->auxtrace.free_events = powerpc_vpadtl_free_events; 534c4bbd4ecSAthira Rajeev vpa->auxtrace.free = powerpc_vpadtl_free; 535c4bbd4ecSAthira Rajeev session->auxtrace = &vpa->auxtrace; 536c4bbd4ecSAthira Rajeev 537c4bbd4ecSAthira Rajeev powerpc_vpadtl_print_info(&auxtrace_info->priv[0]); 538c4bbd4ecSAthira Rajeev 53971feffa9SAthira Rajeev if (dump_trace) 540c4bbd4ecSAthira Rajeev return 0; 541c4bbd4ecSAthira Rajeev 54271feffa9SAthira Rajeev err = powerpc_vpadtl_synth_events(vpa, session); 54371feffa9SAthira Rajeev if (err) 54471feffa9SAthira Rajeev goto err_free_queues; 54571feffa9SAthira Rajeev 54671feffa9SAthira Rajeev err = auxtrace_queues__process_index(&vpa->queues, session); 54771feffa9SAthira Rajeev if (err) 54871feffa9SAthira Rajeev goto err_free_queues; 54971feffa9SAthira Rajeev 55071feffa9SAthira Rajeev return 0; 55171feffa9SAthira Rajeev 55271feffa9SAthira Rajeev err_free_queues: 55371feffa9SAthira Rajeev auxtrace_queues__free(&vpa->queues); 55471feffa9SAthira Rajeev session->auxtrace = NULL; 55571feffa9SAthira Rajeev 556c4bbd4ecSAthira Rajeev err_free: 557c4bbd4ecSAthira Rajeev free(vpa); 558c4bbd4ecSAthira Rajeev return err; 559c4bbd4ecSAthira Rajeev } 560