arch/x86/events/intel/bts.c

Source file repositories/reference/linux-study-clean/arch/x86/events/intel/bts.c

File Facts

System
Linux kernel
Corpus path
arch/x86/events/intel/bts.c
Extension
.c
Size
15337 bytes
Lines
647
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct bts_ctx {
	struct perf_output_handle	handle;
	struct debug_store		ds_back;
	int				state;
};

/* BTS context states: */
enum {
	/* no ongoing AUX transactions */
	BTS_STATE_STOPPED = 0,
	/* AUX transaction is on, BTS tracing is disabled */
	BTS_STATE_INACTIVE,
	/* AUX transaction is on, BTS tracing is running */
	BTS_STATE_ACTIVE,
};

static struct bts_ctx __percpu *bts_ctx;

#define BTS_RECORD_SIZE		24
#define BTS_SAFETY_MARGIN	4080

struct bts_phys {
	struct page	*page;
	unsigned long	size;
	unsigned long	offset;
	unsigned long	displacement;
};

struct bts_buffer {
	size_t		real_size;	/* multiple of BTS_RECORD_SIZE */
	unsigned int	nr_pages;
	unsigned int	nr_bufs;
	unsigned int	cur_buf;
	bool		snapshot;
	local_t		data_size;
	local_t		head;
	unsigned long	end;
	void		**data_pages;
	struct bts_phys	buf[] __counted_by(nr_bufs);
};

static struct pmu bts_pmu;

static int buf_nr_pages(struct page *page)
{
	if (!PagePrivate(page))
		return 1;

	return 1 << page_private(page);
}

static size_t buf_size(struct page *page)
{
	return buf_nr_pages(page) * PAGE_SIZE;
}

static void *
bts_buffer_setup_aux(struct perf_event *event, void **pages,
		     int nr_pages, bool overwrite)
{
	struct bts_buffer *bb;
	struct page *page;
	int cpu = event->cpu;
	int node = (cpu == -1) ? cpu : cpu_to_node(cpu);
	unsigned long offset;
	size_t size = nr_pages << PAGE_SHIFT;
	int pg, nr_buf, pad;

	/* count all the high order buffers */
	for (pg = 0, nr_buf = 0; pg < nr_pages;) {
		page = virt_to_page(pages[pg]);
		pg += buf_nr_pages(page);
		nr_buf++;
	}

	/*
	 * to avoid interrupts in overwrite mode, only allow one physical
	 */
	if (overwrite && nr_buf > 1)
		return NULL;

	bb = kzalloc_node(struct_size(bb, buf, nr_buf), GFP_KERNEL, node);
	if (!bb)
		return NULL;

	bb->nr_pages = nr_pages;
	bb->nr_bufs = nr_buf;
	bb->snapshot = overwrite;
	bb->data_pages = pages;
	bb->real_size = size - size % BTS_RECORD_SIZE;

Annotation

Implementation Notes