[PATCH RFC 1/3] x86: Add Intel PT common files

From: Takao Indoh
Date: Wed Jul 29 2015 - 00:52:18 EST


Rename existing intel_pt.h to intel_pt_perf.h as a perf-specific header,
and make a new intel_pt.h as a common header of Intel PT feature. Also
add intel_pt_cap.c for Intel PT capability stuff.

Signed-off-by: Takao Indoh <indou.takao@xxxxxxxxxxxxxx>
---
arch/x86/include/asm/intel_pt.h | 82 ++++++++++++++++++
arch/x86/kernel/cpu/Makefile | 1 +
arch/x86/kernel/cpu/intel_pt.h | 131 -----------------------------
arch/x86/kernel/cpu/intel_pt_cap.c | 69 +++++++++++++++
arch/x86/kernel/cpu/intel_pt_perf.h | 78 +++++++++++++++++
arch/x86/kernel/cpu/perf_event_intel_pt.c | 54 ++----------
6 files changed, 239 insertions(+), 176 deletions(-)
create mode 100644 arch/x86/include/asm/intel_pt.h
delete mode 100644 arch/x86/kernel/cpu/intel_pt.h
create mode 100644 arch/x86/kernel/cpu/intel_pt_cap.c
create mode 100644 arch/x86/kernel/cpu/intel_pt_perf.h

diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h
new file mode 100644
index 0000000..7cb16e1
--- /dev/null
+++ b/arch/x86/include/asm/intel_pt.h
@@ -0,0 +1,82 @@
+/*
+ * Intel(R) Processor Trace common header
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Intel PT is specified in the Intel Architecture Instruction Set Extensions
+ * Programming Reference:
+ * http://software.intel.com/en-us/intel-isa-extensions
+ */
+
+#ifndef __INTEL_PT_H__
+#define __INTEL_PT_H__
+
+/*
+ * Table of Physical Addresses bits
+ */
+enum topa_sz {
+ TOPA_4K = 0,
+ TOPA_8K,
+ TOPA_16K,
+ TOPA_32K,
+ TOPA_64K,
+ TOPA_128K,
+ TOPA_256K,
+ TOPA_512K,
+ TOPA_1MB,
+ TOPA_2MB,
+ TOPA_4MB,
+ TOPA_8MB,
+ TOPA_16MB,
+ TOPA_32MB,
+ TOPA_64MB,
+ TOPA_128MB,
+ TOPA_SZ_END,
+};
+
+static inline unsigned int sizes(enum topa_sz tsz)
+{
+ return 1 << (tsz + 12);
+};
+
+struct topa_entry {
+ u64 end : 1;
+ u64 rsvd0 : 1;
+ u64 intr : 1;
+ u64 rsvd1 : 1;
+ u64 stop : 1;
+ u64 rsvd2 : 1;
+ u64 size : 4;
+ u64 rsvd3 : 2;
+ u64 base : 36;
+ u64 rsvd4 : 16;
+};
+
+#define TOPA_SHIFT 12
+#define PT_CPUID_LEAVES 2
+
+/*
+ * Capability stuff
+ */
+enum pt_capabilities {
+ PT_CAP_max_subleaf = 0,
+ PT_CAP_cr3_filtering,
+ PT_CAP_topa_output,
+ PT_CAP_topa_multiple_entries,
+ PT_CAP_payloads_lip,
+};
+
+void pt_cap_init(void);
+u32 pt_cap_get(enum pt_capabilities cap);
+const char *pt_cap_name(enum pt_capabilities cap);
+int pt_cap_num(void);
+
+#endif /* __INTEL_PT_H__ */
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 9bff687..77d371c 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
+obj-$(CONFIG_CPU_SUP_INTEL) += intel_pt_cap.o

obj-$(CONFIG_PERF_EVENTS) += perf_event.o

diff --git a/arch/x86/kernel/cpu/intel_pt.h b/arch/x86/kernel/cpu/intel_pt.h
deleted file mode 100644
index 1c338b0..0000000
--- a/arch/x86/kernel/cpu/intel_pt.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Intel(R) Processor Trace PMU driver for perf
- * Copyright (c) 2013-2014, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * Intel PT is specified in the Intel Architecture Instruction Set Extensions
- * Programming Reference:
- * http://software.intel.com/en-us/intel-isa-extensions
- */
-
-#ifndef __INTEL_PT_H__
-#define __INTEL_PT_H__
-
-/*
- * Single-entry ToPA: when this close to region boundary, switch
- * buffers to avoid losing data.
- */
-#define TOPA_PMI_MARGIN 512
-
-/*
- * Table of Physical Addresses bits
- */
-enum topa_sz {
- TOPA_4K = 0,
- TOPA_8K,
- TOPA_16K,
- TOPA_32K,
- TOPA_64K,
- TOPA_128K,
- TOPA_256K,
- TOPA_512K,
- TOPA_1MB,
- TOPA_2MB,
- TOPA_4MB,
- TOPA_8MB,
- TOPA_16MB,
- TOPA_32MB,
- TOPA_64MB,
- TOPA_128MB,
- TOPA_SZ_END,
-};
-
-static inline unsigned int sizes(enum topa_sz tsz)
-{
- return 1 << (tsz + 12);
-};
-
-struct topa_entry {
- u64 end : 1;
- u64 rsvd0 : 1;
- u64 intr : 1;
- u64 rsvd1 : 1;
- u64 stop : 1;
- u64 rsvd2 : 1;
- u64 size : 4;
- u64 rsvd3 : 2;
- u64 base : 36;
- u64 rsvd4 : 16;
-};
-
-#define TOPA_SHIFT 12
-#define PT_CPUID_LEAVES 2
-
-enum pt_capabilities {
- PT_CAP_max_subleaf = 0,
- PT_CAP_cr3_filtering,
- PT_CAP_topa_output,
- PT_CAP_topa_multiple_entries,
- PT_CAP_payloads_lip,
-};
-
-struct pt_pmu {
- struct pmu pmu;
- u32 caps[4 * PT_CPUID_LEAVES];
-};
-
-/**
- * struct pt_buffer - buffer configuration; one buffer per task_struct or
- * cpu, depending on perf event configuration
- * @cpu: cpu for per-cpu allocation
- * @tables: list of ToPA tables in this buffer
- * @first: shorthand for first topa table
- * @last: shorthand for last topa table
- * @cur: current topa table
- * @nr_pages: buffer size in pages
- * @cur_idx: current output region's index within @cur table
- * @output_off: offset within the current output region
- * @data_size: running total of the amount of data in this buffer
- * @lost: if data was lost/truncated
- * @head: logical write offset inside the buffer
- * @snapshot: if this is for a snapshot/overwrite counter
- * @stop_pos: STOP topa entry in the buffer
- * @intr_pos: INT topa entry in the buffer
- * @data_pages: array of pages from perf
- * @topa_index: table of topa entries indexed by page offset
- */
-struct pt_buffer {
- int cpu;
- struct list_head tables;
- struct topa *first, *last, *cur;
- unsigned int cur_idx;
- size_t output_off;
- unsigned long nr_pages;
- local_t data_size;
- local_t lost;
- local64_t head;
- bool snapshot;
- unsigned long stop_pos, intr_pos;
- void **data_pages;
- struct topa_entry *topa_index[0];
-};
-
-/**
- * struct pt - per-cpu pt context
- * @handle: perf output handle
- * @handle_nmi: do handle PT PMI on this cpu, there's an active event
- */
-struct pt {
- struct perf_output_handle handle;
- int handle_nmi;
-};
-
-#endif /* __INTEL_PT_H__ */
diff --git a/arch/x86/kernel/cpu/intel_pt_cap.c b/arch/x86/kernel/cpu/intel_pt_cap.c
new file mode 100644
index 0000000..a2cfbfc
--- /dev/null
+++ b/arch/x86/kernel/cpu/intel_pt_cap.c
@@ -0,0 +1,69 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mm.h>
+#include <asm/intel_pt.h>
+
+enum cpuid_regs {
+ CR_EAX = 0,
+ CR_ECX,
+ CR_EDX,
+ CR_EBX
+};
+
+static u32 cpuid_cache[4 * PT_CPUID_LEAVES];
+static int pt_cap_initialized;
+
+#define PT_CAP(_n, _l, _r, _m) \
+ [PT_CAP_ ## _n] = { .name = __stringify(_n), .leaf = _l, \
+ .reg = _r, .mask = _m }
+
+static struct pt_cap_desc {
+ const char *name;
+ u32 leaf;
+ u8 reg;
+ u32 mask;
+} pt_caps[] = {
+ PT_CAP(max_subleaf, 0, CR_EAX, 0xffffffff),
+ PT_CAP(cr3_filtering, 0, CR_EBX, BIT(0)),
+ PT_CAP(topa_output, 0, CR_ECX, BIT(0)),
+ PT_CAP(topa_multiple_entries, 0, CR_ECX, BIT(1)),
+ PT_CAP(payloads_lip, 0, CR_ECX, BIT(31)),
+};
+
+u32 pt_cap_get(enum pt_capabilities cap)
+{
+ struct pt_cap_desc *cd = &pt_caps[cap];
+ u32 c = cpuid_cache[cd->leaf * 4 + cd->reg];
+ unsigned int shift = __ffs(cd->mask);
+
+ return (c & cd->mask) >> shift;
+}
+
+const char *pt_cap_name(enum pt_capabilities cap)
+{
+ return pt_caps[cap].name;
+}
+
+int pt_cap_num(void)
+{
+ return ARRAY_SIZE(pt_caps);
+}
+
+void __init pt_cap_init(void)
+{
+ int i;
+
+ if (pt_cap_initialized)
+ return;
+
+ for (i = 0; i < PT_CPUID_LEAVES; i++) {
+ cpuid_count(20, i,
+ &cpuid_cache[CR_EAX + i*4],
+ &cpuid_cache[CR_EBX + i*4],
+ &cpuid_cache[CR_ECX + i*4],
+ &cpuid_cache[CR_EDX + i*4]);
+ }
+
+ pt_cap_initialized = 1;
+}
+
diff --git a/arch/x86/kernel/cpu/intel_pt_perf.h b/arch/x86/kernel/cpu/intel_pt_perf.h
new file mode 100644
index 0000000..1e77646
--- /dev/null
+++ b/arch/x86/kernel/cpu/intel_pt_perf.h
@@ -0,0 +1,78 @@
+/*
+ * Intel(R) Processor Trace PMU driver for perf
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Intel PT is specified in the Intel Architecture Instruction Set Extensions
+ * Programming Reference:
+ * http://software.intel.com/en-us/intel-isa-extensions
+ */
+
+#ifndef __INTEL_PT_PERF_H__
+#define __INTEL_PT_PERF_H__
+
+/*
+ * Single-entry ToPA: when this close to region boundary, switch
+ * buffers to avoid losing data.
+ */
+#define TOPA_PMI_MARGIN 512
+
+struct pt_pmu {
+ struct pmu pmu;
+};
+
+/**
+ * struct pt_buffer - buffer configuration; one buffer per task_struct or
+ * cpu, depending on perf event configuration
+ * @cpu: cpu for per-cpu allocation
+ * @tables: list of ToPA tables in this buffer
+ * @first: shorthand for first topa table
+ * @last: shorthand for last topa table
+ * @cur: current topa table
+ * @nr_pages: buffer size in pages
+ * @cur_idx: current output region's index within @cur table
+ * @output_off: offset within the current output region
+ * @data_size: running total of the amount of data in this buffer
+ * @lost: if data was lost/truncated
+ * @head: logical write offset inside the buffer
+ * @snapshot: if this is for a snapshot/overwrite counter
+ * @stop_pos: STOP topa entry in the buffer
+ * @intr_pos: INT topa entry in the buffer
+ * @data_pages: array of pages from perf
+ * @topa_index: table of topa entries indexed by page offset
+ */
+struct pt_buffer {
+ int cpu;
+ struct list_head tables;
+ struct topa *first, *last, *cur;
+ unsigned int cur_idx;
+ size_t output_off;
+ unsigned long nr_pages;
+ local_t data_size;
+ local_t lost;
+ local64_t head;
+ bool snapshot;
+ unsigned long stop_pos, intr_pos;
+ void **data_pages;
+ struct topa_entry *topa_index[0];
+};
+
+/**
+ * struct pt - per-cpu pt context
+ * @handle: perf output handle
+ * @handle_nmi: do handle PT PMI on this cpu, there's an active event
+ */
+struct pt {
+ struct perf_output_handle handle;
+ int handle_nmi;
+};
+
+#endif /* __INTEL_PT_PERF_H__ */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c
index 183de71..c3aec2c 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_pt.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c
@@ -27,21 +27,15 @@
#include <asm/perf_event.h>
#include <asm/insn.h>
#include <asm/io.h>
+#include <asm/intel_pt.h>

#include "perf_event.h"
-#include "intel_pt.h"
+#include "intel_pt_perf.h"

static DEFINE_PER_CPU(struct pt, pt_ctx);

static struct pt_pmu pt_pmu;

-enum cpuid_regs {
- CR_EAX = 0,
- CR_ECX,
- CR_EDX,
- CR_EBX
-};
-
/*
* Capabilities of Intel PT hardware, such as number of address bits or
* supported output schemes, are cached and exported to userspace as "caps"
@@ -53,32 +47,6 @@ enum cpuid_regs {
* width encoded in IP-related packets), and event configuration (bitmasks with
* permitted values for certain bit fields).
*/
-#define PT_CAP(_n, _l, _r, _m) \
- [PT_CAP_ ## _n] = { .name = __stringify(_n), .leaf = _l, \
- .reg = _r, .mask = _m }
-
-static struct pt_cap_desc {
- const char *name;
- u32 leaf;
- u8 reg;
- u32 mask;
-} pt_caps[] = {
- PT_CAP(max_subleaf, 0, CR_EAX, 0xffffffff),
- PT_CAP(cr3_filtering, 0, CR_EBX, BIT(0)),
- PT_CAP(topa_output, 0, CR_ECX, BIT(0)),
- PT_CAP(topa_multiple_entries, 0, CR_ECX, BIT(1)),
- PT_CAP(payloads_lip, 0, CR_ECX, BIT(31)),
-};
-
-static u32 pt_cap_get(enum pt_capabilities cap)
-{
- struct pt_cap_desc *cd = &pt_caps[cap];
- u32 c = pt_pmu.caps[cd->leaf * 4 + cd->reg];
- unsigned int shift = __ffs(cd->mask);
-
- return (c & cd->mask) >> shift;
-}
-
static ssize_t pt_cap_show(struct device *cdev,
struct device_attribute *attr,
char *buf)
@@ -121,35 +89,31 @@ static int __init pt_pmu_hw_init(void)
size_t size;
int ret;
long i;
+ int cap_num;

attrs = NULL;
ret = -ENODEV;
if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT))
goto fail;

- for (i = 0; i < PT_CPUID_LEAVES; i++) {
- cpuid_count(20, i,
- &pt_pmu.caps[CR_EAX + i*4],
- &pt_pmu.caps[CR_EBX + i*4],
- &pt_pmu.caps[CR_ECX + i*4],
- &pt_pmu.caps[CR_EDX + i*4]);
- }
+ pt_cap_init();
+ cap_num = pt_cap_num();

ret = -ENOMEM;
- size = sizeof(struct attribute *) * (ARRAY_SIZE(pt_caps)+1);
+ size = sizeof(struct attribute *) * (cap_num+1);
attrs = kzalloc(size, GFP_KERNEL);
if (!attrs)
goto fail;

- size = sizeof(struct dev_ext_attribute) * (ARRAY_SIZE(pt_caps)+1);
+ size = sizeof(struct dev_ext_attribute) * (cap_num+1);
de_attrs = kzalloc(size, GFP_KERNEL);
if (!de_attrs)
goto fail;

- for (i = 0; i < ARRAY_SIZE(pt_caps); i++) {
+ for (i = 0; i < cap_num; i++) {
struct dev_ext_attribute *de_attr = de_attrs + i;

- de_attr->attr.attr.name = pt_caps[i].name;
+ de_attr->attr.attr.name = pt_cap_name(i);

sysfs_attr_init(&de_attr->attr.attr);

--
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/