18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * BTS PMU driver for perf 48c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#undef DEBUG 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci#include <linux/coredump.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/sizes.h> 198c2ecf20Sopenharmony_ci#include <asm/perf_event.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "../perf_event.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct bts_ctx { 248c2ecf20Sopenharmony_ci struct perf_output_handle handle; 258c2ecf20Sopenharmony_ci struct debug_store ds_back; 268c2ecf20Sopenharmony_ci int state; 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* BTS context states: */ 308c2ecf20Sopenharmony_cienum { 318c2ecf20Sopenharmony_ci /* no ongoing AUX transactions */ 328c2ecf20Sopenharmony_ci BTS_STATE_STOPPED = 0, 338c2ecf20Sopenharmony_ci /* AUX transaction is on, BTS tracing is disabled */ 348c2ecf20Sopenharmony_ci BTS_STATE_INACTIVE, 358c2ecf20Sopenharmony_ci /* AUX transaction is on, BTS tracing is running */ 368c2ecf20Sopenharmony_ci BTS_STATE_ACTIVE, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bts_ctx, bts_ctx); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define BTS_RECORD_SIZE 24 428c2ecf20Sopenharmony_ci#define BTS_SAFETY_MARGIN 4080 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct bts_phys { 458c2ecf20Sopenharmony_ci struct page *page; 468c2ecf20Sopenharmony_ci unsigned long size; 478c2ecf20Sopenharmony_ci unsigned long offset; 488c2ecf20Sopenharmony_ci unsigned long displacement; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct bts_buffer { 528c2ecf20Sopenharmony_ci size_t real_size; /* multiple of BTS_RECORD_SIZE */ 538c2ecf20Sopenharmony_ci unsigned int nr_pages; 548c2ecf20Sopenharmony_ci unsigned int nr_bufs; 558c2ecf20Sopenharmony_ci unsigned int cur_buf; 568c2ecf20Sopenharmony_ci bool snapshot; 578c2ecf20Sopenharmony_ci local_t data_size; 588c2ecf20Sopenharmony_ci local_t head; 598c2ecf20Sopenharmony_ci unsigned long end; 608c2ecf20Sopenharmony_ci void **data_pages; 618c2ecf20Sopenharmony_ci struct bts_phys buf[]; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct pmu bts_pmu; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int buf_nr_pages(struct page *page) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci if (!PagePrivate(page)) 698c2ecf20Sopenharmony_ci return 1; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return 1 << page_private(page); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic size_t buf_size(struct page *page) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return buf_nr_pages(page) * PAGE_SIZE; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void * 808c2ecf20Sopenharmony_cibts_buffer_setup_aux(struct perf_event *event, void **pages, 818c2ecf20Sopenharmony_ci int nr_pages, bool overwrite) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct bts_buffer *buf; 848c2ecf20Sopenharmony_ci struct page *page; 858c2ecf20Sopenharmony_ci int cpu = event->cpu; 868c2ecf20Sopenharmony_ci int node = (cpu == -1) ? cpu : cpu_to_node(cpu); 878c2ecf20Sopenharmony_ci unsigned long offset; 888c2ecf20Sopenharmony_ci size_t size = nr_pages << PAGE_SHIFT; 898c2ecf20Sopenharmony_ci int pg, nbuf, pad; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* count all the high order buffers */ 928c2ecf20Sopenharmony_ci for (pg = 0, nbuf = 0; pg < nr_pages;) { 938c2ecf20Sopenharmony_ci page = virt_to_page(pages[pg]); 948c2ecf20Sopenharmony_ci pg += buf_nr_pages(page); 958c2ecf20Sopenharmony_ci nbuf++; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * to avoid interrupts in overwrite mode, only allow one physical 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci if (overwrite && nbuf > 1) 1028c2ecf20Sopenharmony_ci return NULL; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci buf = kzalloc_node(offsetof(struct bts_buffer, buf[nbuf]), GFP_KERNEL, node); 1058c2ecf20Sopenharmony_ci if (!buf) 1068c2ecf20Sopenharmony_ci return NULL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci buf->nr_pages = nr_pages; 1098c2ecf20Sopenharmony_ci buf->nr_bufs = nbuf; 1108c2ecf20Sopenharmony_ci buf->snapshot = overwrite; 1118c2ecf20Sopenharmony_ci buf->data_pages = pages; 1128c2ecf20Sopenharmony_ci buf->real_size = size - size % BTS_RECORD_SIZE; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (pg = 0, nbuf = 0, offset = 0, pad = 0; nbuf < buf->nr_bufs; nbuf++) { 1158c2ecf20Sopenharmony_ci unsigned int __nr_pages; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci page = virt_to_page(pages[pg]); 1188c2ecf20Sopenharmony_ci __nr_pages = buf_nr_pages(page); 1198c2ecf20Sopenharmony_ci buf->buf[nbuf].page = page; 1208c2ecf20Sopenharmony_ci buf->buf[nbuf].offset = offset; 1218c2ecf20Sopenharmony_ci buf->buf[nbuf].displacement = (pad ? BTS_RECORD_SIZE - pad : 0); 1228c2ecf20Sopenharmony_ci buf->buf[nbuf].size = buf_size(page) - buf->buf[nbuf].displacement; 1238c2ecf20Sopenharmony_ci pad = buf->buf[nbuf].size % BTS_RECORD_SIZE; 1248c2ecf20Sopenharmony_ci buf->buf[nbuf].size -= pad; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci pg += __nr_pages; 1278c2ecf20Sopenharmony_ci offset += __nr_pages << PAGE_SHIFT; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return buf; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void bts_buffer_free_aux(void *data) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci kfree(data); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic unsigned long bts_buffer_offset(struct bts_buffer *buf, unsigned int idx) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return buf->buf[idx].offset + buf->buf[idx].displacement; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void 1448c2ecf20Sopenharmony_cibts_config_buffer(struct bts_buffer *buf) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int cpu = raw_smp_processor_id(); 1478c2ecf20Sopenharmony_ci struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; 1488c2ecf20Sopenharmony_ci struct bts_phys *phys = &buf->buf[buf->cur_buf]; 1498c2ecf20Sopenharmony_ci unsigned long index, thresh = 0, end = phys->size; 1508c2ecf20Sopenharmony_ci struct page *page = phys->page; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci index = local_read(&buf->head); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (!buf->snapshot) { 1558c2ecf20Sopenharmony_ci if (buf->end < phys->offset + buf_size(page)) 1568c2ecf20Sopenharmony_ci end = buf->end - phys->offset - phys->displacement; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci index -= phys->offset + phys->displacement; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (end - index > BTS_SAFETY_MARGIN) 1618c2ecf20Sopenharmony_ci thresh = end - BTS_SAFETY_MARGIN; 1628c2ecf20Sopenharmony_ci else if (end - index > BTS_RECORD_SIZE) 1638c2ecf20Sopenharmony_ci thresh = end - BTS_RECORD_SIZE; 1648c2ecf20Sopenharmony_ci else 1658c2ecf20Sopenharmony_ci thresh = end; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ds->bts_buffer_base = (u64)(long)page_address(page) + phys->displacement; 1698c2ecf20Sopenharmony_ci ds->bts_index = ds->bts_buffer_base + index; 1708c2ecf20Sopenharmony_ci ds->bts_absolute_maximum = ds->bts_buffer_base + end; 1718c2ecf20Sopenharmony_ci ds->bts_interrupt_threshold = !buf->snapshot 1728c2ecf20Sopenharmony_ci ? ds->bts_buffer_base + thresh 1738c2ecf20Sopenharmony_ci : ds->bts_absolute_maximum + BTS_RECORD_SIZE; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void bts_buffer_pad_out(struct bts_phys *phys, unsigned long head) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci unsigned long index = head - phys->offset; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci memset(page_address(phys->page) + index, 0, phys->size - index); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void bts_update(struct bts_ctx *bts) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int cpu = raw_smp_processor_id(); 1868c2ecf20Sopenharmony_ci struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; 1878c2ecf20Sopenharmony_ci struct bts_buffer *buf = perf_get_aux(&bts->handle); 1888c2ecf20Sopenharmony_ci unsigned long index = ds->bts_index - ds->bts_buffer_base, old, head; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (!buf) 1918c2ecf20Sopenharmony_ci return; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci head = index + bts_buffer_offset(buf, buf->cur_buf); 1948c2ecf20Sopenharmony_ci old = local_xchg(&buf->head, head); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!buf->snapshot) { 1978c2ecf20Sopenharmony_ci if (old == head) 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (ds->bts_index >= ds->bts_absolute_maximum) 2018c2ecf20Sopenharmony_ci perf_aux_output_flag(&bts->handle, 2028c2ecf20Sopenharmony_ci PERF_AUX_FLAG_TRUNCATED); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * old and head are always in the same physical buffer, so we 2068c2ecf20Sopenharmony_ci * can subtract them to get the data size. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci local_add(head - old, &buf->data_size); 2098c2ecf20Sopenharmony_ci } else { 2108c2ecf20Sopenharmony_ci local_set(&buf->data_size, head); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int 2158c2ecf20Sopenharmony_cibts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* 2188c2ecf20Sopenharmony_ci * Ordering PMU callbacks wrt themselves and the PMI is done by means 2198c2ecf20Sopenharmony_ci * of bts::state, which: 2208c2ecf20Sopenharmony_ci * - is set when bts::handle::event is valid, that is, between 2218c2ecf20Sopenharmony_ci * perf_aux_output_begin() and perf_aux_output_end(); 2228c2ecf20Sopenharmony_ci * - is zero otherwise; 2238c2ecf20Sopenharmony_ci * - is ordered against bts::handle::event with a compiler barrier. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void __bts_event_start(struct perf_event *event) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 2298c2ecf20Sopenharmony_ci struct bts_buffer *buf = perf_get_aux(&bts->handle); 2308c2ecf20Sopenharmony_ci u64 config = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (!buf->snapshot) 2338c2ecf20Sopenharmony_ci config |= ARCH_PERFMON_EVENTSEL_INT; 2348c2ecf20Sopenharmony_ci if (!event->attr.exclude_kernel) 2358c2ecf20Sopenharmony_ci config |= ARCH_PERFMON_EVENTSEL_OS; 2368c2ecf20Sopenharmony_ci if (!event->attr.exclude_user) 2378c2ecf20Sopenharmony_ci config |= ARCH_PERFMON_EVENTSEL_USR; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci bts_config_buffer(buf); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * local barrier to make sure that ds configuration made it 2438c2ecf20Sopenharmony_ci * before we enable BTS and bts::state goes ACTIVE 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci wmb(); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* INACTIVE/STOPPED -> ACTIVE */ 2488c2ecf20Sopenharmony_ci WRITE_ONCE(bts->state, BTS_STATE_ACTIVE); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci intel_pmu_enable_bts(config); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void bts_event_start(struct perf_event *event, int flags) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 2578c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 2588c2ecf20Sopenharmony_ci struct bts_buffer *buf; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci buf = perf_aux_output_begin(&bts->handle, event); 2618c2ecf20Sopenharmony_ci if (!buf) 2628c2ecf20Sopenharmony_ci goto fail_stop; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (bts_buffer_reset(buf, &bts->handle)) 2658c2ecf20Sopenharmony_ci goto fail_end_stop; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci bts->ds_back.bts_buffer_base = cpuc->ds->bts_buffer_base; 2688c2ecf20Sopenharmony_ci bts->ds_back.bts_absolute_maximum = cpuc->ds->bts_absolute_maximum; 2698c2ecf20Sopenharmony_ci bts->ds_back.bts_interrupt_threshold = cpuc->ds->bts_interrupt_threshold; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci perf_event_itrace_started(event); 2728c2ecf20Sopenharmony_ci event->hw.state = 0; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci __bts_event_start(event); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cifail_end_stop: 2798c2ecf20Sopenharmony_ci perf_aux_output_end(&bts->handle, 0); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cifail_stop: 2828c2ecf20Sopenharmony_ci event->hw.state = PERF_HES_STOPPED; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void __bts_event_stop(struct perf_event *event, int state) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* ACTIVE -> INACTIVE(PMI)/STOPPED(->stop()) */ 2908c2ecf20Sopenharmony_ci WRITE_ONCE(bts->state, state); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * No extra synchronization is mandated by the documentation to have 2948c2ecf20Sopenharmony_ci * BTS data stores globally visible. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci intel_pmu_disable_bts(); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void bts_event_stop(struct perf_event *event, int flags) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 3028c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 3038c2ecf20Sopenharmony_ci struct bts_buffer *buf = NULL; 3048c2ecf20Sopenharmony_ci int state = READ_ONCE(bts->state); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (state == BTS_STATE_ACTIVE) 3078c2ecf20Sopenharmony_ci __bts_event_stop(event, BTS_STATE_STOPPED); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (state != BTS_STATE_STOPPED) 3108c2ecf20Sopenharmony_ci buf = perf_get_aux(&bts->handle); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci event->hw.state |= PERF_HES_STOPPED; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (flags & PERF_EF_UPDATE) { 3158c2ecf20Sopenharmony_ci bts_update(bts); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (buf) { 3188c2ecf20Sopenharmony_ci if (buf->snapshot) 3198c2ecf20Sopenharmony_ci bts->handle.head = 3208c2ecf20Sopenharmony_ci local_xchg(&buf->data_size, 3218c2ecf20Sopenharmony_ci buf->nr_pages << PAGE_SHIFT); 3228c2ecf20Sopenharmony_ci perf_aux_output_end(&bts->handle, 3238c2ecf20Sopenharmony_ci local_xchg(&buf->data_size, 0)); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci cpuc->ds->bts_index = bts->ds_back.bts_buffer_base; 3278c2ecf20Sopenharmony_ci cpuc->ds->bts_buffer_base = bts->ds_back.bts_buffer_base; 3288c2ecf20Sopenharmony_ci cpuc->ds->bts_absolute_maximum = bts->ds_back.bts_absolute_maximum; 3298c2ecf20Sopenharmony_ci cpuc->ds->bts_interrupt_threshold = bts->ds_back.bts_interrupt_threshold; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_civoid intel_bts_enable_local(void) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 3368c2ecf20Sopenharmony_ci int state = READ_ONCE(bts->state); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * Here we transition from INACTIVE to ACTIVE; 3408c2ecf20Sopenharmony_ci * if we instead are STOPPED from the interrupt handler, 3418c2ecf20Sopenharmony_ci * stay that way. Can't be ACTIVE here though. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(state == BTS_STATE_ACTIVE)) 3448c2ecf20Sopenharmony_ci return; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (state == BTS_STATE_STOPPED) 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (bts->handle.event) 3508c2ecf20Sopenharmony_ci __bts_event_start(bts->handle.event); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_civoid intel_bts_disable_local(void) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Here we transition from ACTIVE to INACTIVE; 3598c2ecf20Sopenharmony_ci * do nothing for STOPPED or INACTIVE. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (READ_ONCE(bts->state) != BTS_STATE_ACTIVE) 3628c2ecf20Sopenharmony_ci return; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (bts->handle.event) 3658c2ecf20Sopenharmony_ci __bts_event_stop(bts->handle.event, BTS_STATE_INACTIVE); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int 3698c2ecf20Sopenharmony_cibts_buffer_reset(struct bts_buffer *buf, struct perf_output_handle *handle) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci unsigned long head, space, next_space, pad, gap, skip, wakeup; 3728c2ecf20Sopenharmony_ci unsigned int next_buf; 3738c2ecf20Sopenharmony_ci struct bts_phys *phys, *next_phys; 3748c2ecf20Sopenharmony_ci int ret; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (buf->snapshot) 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci phys = &buf->buf[buf->cur_buf]; 3828c2ecf20Sopenharmony_ci space = phys->offset + phys->displacement + phys->size - head; 3838c2ecf20Sopenharmony_ci pad = space; 3848c2ecf20Sopenharmony_ci if (space > handle->size) { 3858c2ecf20Sopenharmony_ci space = handle->size; 3868c2ecf20Sopenharmony_ci space -= space % BTS_RECORD_SIZE; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci if (space <= BTS_SAFETY_MARGIN) { 3898c2ecf20Sopenharmony_ci /* See if next phys buffer has more space */ 3908c2ecf20Sopenharmony_ci next_buf = buf->cur_buf + 1; 3918c2ecf20Sopenharmony_ci if (next_buf >= buf->nr_bufs) 3928c2ecf20Sopenharmony_ci next_buf = 0; 3938c2ecf20Sopenharmony_ci next_phys = &buf->buf[next_buf]; 3948c2ecf20Sopenharmony_ci gap = buf_size(phys->page) - phys->displacement - phys->size + 3958c2ecf20Sopenharmony_ci next_phys->displacement; 3968c2ecf20Sopenharmony_ci skip = pad + gap; 3978c2ecf20Sopenharmony_ci if (handle->size >= skip) { 3988c2ecf20Sopenharmony_ci next_space = next_phys->size; 3998c2ecf20Sopenharmony_ci if (next_space + skip > handle->size) { 4008c2ecf20Sopenharmony_ci next_space = handle->size - skip; 4018c2ecf20Sopenharmony_ci next_space -= next_space % BTS_RECORD_SIZE; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci if (next_space > space || !space) { 4048c2ecf20Sopenharmony_ci if (pad) 4058c2ecf20Sopenharmony_ci bts_buffer_pad_out(phys, head); 4068c2ecf20Sopenharmony_ci ret = perf_aux_output_skip(handle, skip); 4078c2ecf20Sopenharmony_ci if (ret) 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci /* Advance to next phys buffer */ 4108c2ecf20Sopenharmony_ci phys = next_phys; 4118c2ecf20Sopenharmony_ci space = next_space; 4128c2ecf20Sopenharmony_ci head = phys->offset + phys->displacement; 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * After this, cur_buf and head won't match ds 4158c2ecf20Sopenharmony_ci * anymore, so we must not be racing with 4168c2ecf20Sopenharmony_ci * bts_update(). 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci buf->cur_buf = next_buf; 4198c2ecf20Sopenharmony_ci local_set(&buf->head, head); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Don't go far beyond wakeup watermark */ 4258c2ecf20Sopenharmony_ci wakeup = BTS_SAFETY_MARGIN + BTS_RECORD_SIZE + handle->wakeup - 4268c2ecf20Sopenharmony_ci handle->head; 4278c2ecf20Sopenharmony_ci if (space > wakeup) { 4288c2ecf20Sopenharmony_ci space = wakeup; 4298c2ecf20Sopenharmony_ci space -= space % BTS_RECORD_SIZE; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci buf->end = head + space; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* 4358c2ecf20Sopenharmony_ci * If we have no space, the lost notification would have been sent when 4368c2ecf20Sopenharmony_ci * we hit absolute_maximum - see bts_update() 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci if (!space) 4398c2ecf20Sopenharmony_ci return -ENOSPC; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ciint intel_bts_interrupt(void) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct debug_store *ds = this_cpu_ptr(&cpu_hw_events)->ds; 4478c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 4488c2ecf20Sopenharmony_ci struct perf_event *event = bts->handle.event; 4498c2ecf20Sopenharmony_ci struct bts_buffer *buf; 4508c2ecf20Sopenharmony_ci s64 old_head; 4518c2ecf20Sopenharmony_ci int err = -ENOSPC, handled = 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * The only surefire way of knowing if this NMI is ours is by checking 4558c2ecf20Sopenharmony_ci * the write ptr against the PMI threshold. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ci if (ds && (ds->bts_index >= ds->bts_interrupt_threshold)) 4588c2ecf20Sopenharmony_ci handled = 1; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* 4618c2ecf20Sopenharmony_ci * this is wrapped in intel_bts_enable_local/intel_bts_disable_local, 4628c2ecf20Sopenharmony_ci * so we can only be INACTIVE or STOPPED 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_ci if (READ_ONCE(bts->state) == BTS_STATE_STOPPED) 4658c2ecf20Sopenharmony_ci return handled; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci buf = perf_get_aux(&bts->handle); 4688c2ecf20Sopenharmony_ci if (!buf) 4698c2ecf20Sopenharmony_ci return handled; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * Skip snapshot counters: they don't use the interrupt, but 4738c2ecf20Sopenharmony_ci * there's no other way of telling, because the pointer will 4748c2ecf20Sopenharmony_ci * keep moving 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci if (buf->snapshot) 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci old_head = local_read(&buf->head); 4808c2ecf20Sopenharmony_ci bts_update(bts); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* no new data */ 4838c2ecf20Sopenharmony_ci if (old_head == local_read(&buf->head)) 4848c2ecf20Sopenharmony_ci return handled; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci perf_aux_output_end(&bts->handle, local_xchg(&buf->data_size, 0)); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci buf = perf_aux_output_begin(&bts->handle, event); 4898c2ecf20Sopenharmony_ci if (buf) 4908c2ecf20Sopenharmony_ci err = bts_buffer_reset(buf, &bts->handle); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (err) { 4938c2ecf20Sopenharmony_ci WRITE_ONCE(bts->state, BTS_STATE_STOPPED); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (buf) { 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * BTS_STATE_STOPPED should be visible before 4988c2ecf20Sopenharmony_ci * cleared handle::event 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci barrier(); 5018c2ecf20Sopenharmony_ci perf_aux_output_end(&bts->handle, 0); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 1; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void bts_event_del(struct perf_event *event, int mode) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci bts_event_stop(event, PERF_EF_UPDATE); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int bts_event_add(struct perf_event *event, int mode) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct bts_ctx *bts = this_cpu_ptr(&bts_ctx); 5168c2ecf20Sopenharmony_ci struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 5178c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci event->hw.state = PERF_HES_STOPPED; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask)) 5228c2ecf20Sopenharmony_ci return -EBUSY; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (bts->handle.event) 5258c2ecf20Sopenharmony_ci return -EBUSY; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (mode & PERF_EF_START) { 5288c2ecf20Sopenharmony_ci bts_event_start(event, 0); 5298c2ecf20Sopenharmony_ci if (hwc->state & PERF_HES_STOPPED) 5308c2ecf20Sopenharmony_ci return -EINVAL; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void bts_event_destroy(struct perf_event *event) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci x86_release_hardware(); 5398c2ecf20Sopenharmony_ci x86_del_exclusive(x86_lbr_exclusive_bts); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int bts_event_init(struct perf_event *event) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int ret; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (event->attr.type != bts_pmu.type) 5478c2ecf20Sopenharmony_ci return -ENOENT; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * BTS leaks kernel addresses even when CPL0 tracing is 5518c2ecf20Sopenharmony_ci * disabled, so disallow intel_bts driver for unprivileged 5528c2ecf20Sopenharmony_ci * users on paranoid systems since it provides trace data 5538c2ecf20Sopenharmony_ci * to the user in a zero-copy fashion. 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci * Note that the default paranoia setting permits unprivileged 5568c2ecf20Sopenharmony_ci * users to profile the kernel. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci if (event->attr.exclude_kernel) { 5598c2ecf20Sopenharmony_ci ret = perf_allow_kernel(&event->attr); 5608c2ecf20Sopenharmony_ci if (ret) 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (x86_add_exclusive(x86_lbr_exclusive_bts)) 5658c2ecf20Sopenharmony_ci return -EBUSY; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ret = x86_reserve_hardware(); 5688c2ecf20Sopenharmony_ci if (ret) { 5698c2ecf20Sopenharmony_ci x86_del_exclusive(x86_lbr_exclusive_bts); 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci event->destroy = bts_event_destroy; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return 0; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic void bts_event_read(struct perf_event *event) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic __init int bts_init(void) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_DTES64) || !x86_pmu.bts) 5858c2ecf20Sopenharmony_ci return -ENODEV; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_PTI)) { 5888c2ecf20Sopenharmony_ci /* 5898c2ecf20Sopenharmony_ci * BTS hardware writes through a virtual memory map we must 5908c2ecf20Sopenharmony_ci * either use the kernel physical map, or the user mapping of 5918c2ecf20Sopenharmony_ci * the AUX buffer. 5928c2ecf20Sopenharmony_ci * 5938c2ecf20Sopenharmony_ci * However, since this driver supports per-CPU and per-task inherit 5948c2ecf20Sopenharmony_ci * we cannot use the user mapping since it will not be available 5958c2ecf20Sopenharmony_ci * if we're not running the owning process. 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * With PTI we can't use the kernal map either, because its not 5988c2ecf20Sopenharmony_ci * there when we run userspace. 5998c2ecf20Sopenharmony_ci * 6008c2ecf20Sopenharmony_ci * For now, disable this driver when using PTI. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci return -ENODEV; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci bts_pmu.capabilities = PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_ITRACE | 6068c2ecf20Sopenharmony_ci PERF_PMU_CAP_EXCLUSIVE; 6078c2ecf20Sopenharmony_ci bts_pmu.task_ctx_nr = perf_sw_context; 6088c2ecf20Sopenharmony_ci bts_pmu.event_init = bts_event_init; 6098c2ecf20Sopenharmony_ci bts_pmu.add = bts_event_add; 6108c2ecf20Sopenharmony_ci bts_pmu.del = bts_event_del; 6118c2ecf20Sopenharmony_ci bts_pmu.start = bts_event_start; 6128c2ecf20Sopenharmony_ci bts_pmu.stop = bts_event_stop; 6138c2ecf20Sopenharmony_ci bts_pmu.read = bts_event_read; 6148c2ecf20Sopenharmony_ci bts_pmu.setup_aux = bts_buffer_setup_aux; 6158c2ecf20Sopenharmony_ci bts_pmu.free_aux = bts_buffer_free_aux; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return perf_pmu_register(&bts_pmu, "intel_bts", -1); 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ciarch_initcall(bts_init); 620