mirror of
https://github.com/torvalds/linux
synced 2024-09-20 11:07:02 +00:00
Merge remote-tracking branch 'tip/perf/core' into perf/urgent
To pick up fixes. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
commit
e3b22a6534
|
@ -538,3 +538,26 @@ Description: Intel Energy and Performance Bias Hint (EPB)
|
||||||
|
|
||||||
This attribute is present for all online CPUs supporting the
|
This attribute is present for all online CPUs supporting the
|
||||||
Intel EPB feature.
|
Intel EPB feature.
|
||||||
|
|
||||||
|
What: /sys/devices/system/cpu/umwait_control
|
||||||
|
/sys/devices/system/cpu/umwait_control/enable_c02
|
||||||
|
/sys/devices/system/cpu/umwait_control/max_time
|
||||||
|
Date: May 2019
|
||||||
|
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||||
|
Description: Umwait control
|
||||||
|
|
||||||
|
enable_c02: Read/write interface to control umwait C0.2 state
|
||||||
|
Read returns C0.2 state status:
|
||||||
|
0: C0.2 is disabled
|
||||||
|
1: C0.2 is enabled
|
||||||
|
|
||||||
|
Write 'y' or '1' or 'on' to enable C0.2 state.
|
||||||
|
Write 'n' or '0' or 'off' to disable C0.2 state.
|
||||||
|
|
||||||
|
The interface is case insensitive.
|
||||||
|
|
||||||
|
max_time: Read/write interface to control umwait maximum time
|
||||||
|
in TSC-quanta that the CPU can reside in either C0.1
|
||||||
|
or C0.2 state. The time is an unsigned 32-bit number.
|
||||||
|
Note that a value of zero means there is no limit.
|
||||||
|
Low order two bits must be zero.
|
||||||
|
|
|
@ -12,6 +12,12 @@ physical_package_id:
|
||||||
socket number, but the actual value is architecture and platform
|
socket number, but the actual value is architecture and platform
|
||||||
dependent.
|
dependent.
|
||||||
|
|
||||||
|
die_id:
|
||||||
|
|
||||||
|
the CPU die ID of cpuX. Typically it is the hardware platform's
|
||||||
|
identifier (rather than the kernel's). The actual value is
|
||||||
|
architecture and platform dependent.
|
||||||
|
|
||||||
core_id:
|
core_id:
|
||||||
|
|
||||||
the CPU core ID of cpuX. Typically it is the hardware platform's
|
the CPU core ID of cpuX. Typically it is the hardware platform's
|
||||||
|
@ -30,25 +36,33 @@ drawer_id:
|
||||||
identifier (rather than the kernel's). The actual value is
|
identifier (rather than the kernel's). The actual value is
|
||||||
architecture and platform dependent.
|
architecture and platform dependent.
|
||||||
|
|
||||||
thread_siblings:
|
core_cpus:
|
||||||
|
|
||||||
internal kernel map of cpuX's hardware threads within the same
|
internal kernel map of CPUs within the same core.
|
||||||
core as cpuX.
|
(deprecated name: "thread_siblings")
|
||||||
|
|
||||||
thread_siblings_list:
|
core_cpus_list:
|
||||||
|
|
||||||
human-readable list of cpuX's hardware threads within the same
|
human-readable list of CPUs within the same core.
|
||||||
core as cpuX.
|
(deprecated name: "thread_siblings_list");
|
||||||
|
|
||||||
core_siblings:
|
package_cpus:
|
||||||
|
|
||||||
internal kernel map of cpuX's hardware threads within the same
|
internal kernel map of the CPUs sharing the same physical_package_id.
|
||||||
physical_package_id.
|
(deprecated name: "core_siblings")
|
||||||
|
|
||||||
core_siblings_list:
|
package_cpus_list:
|
||||||
|
|
||||||
human-readable list of cpuX's hardware threads within the same
|
human-readable list of CPUs sharing the same physical_package_id.
|
||||||
physical_package_id.
|
(deprecated name: "core_siblings_list")
|
||||||
|
|
||||||
|
die_cpus:
|
||||||
|
|
||||||
|
internal kernel map of CPUs within the same die.
|
||||||
|
|
||||||
|
die_cpus_list:
|
||||||
|
|
||||||
|
human-readable list of CPUs within the same die.
|
||||||
|
|
||||||
book_siblings:
|
book_siblings:
|
||||||
|
|
||||||
|
@ -81,11 +95,13 @@ For an architecture to support this feature, it must define some of
|
||||||
these macros in include/asm-XXX/topology.h::
|
these macros in include/asm-XXX/topology.h::
|
||||||
|
|
||||||
#define topology_physical_package_id(cpu)
|
#define topology_physical_package_id(cpu)
|
||||||
|
#define topology_die_id(cpu)
|
||||||
#define topology_core_id(cpu)
|
#define topology_core_id(cpu)
|
||||||
#define topology_book_id(cpu)
|
#define topology_book_id(cpu)
|
||||||
#define topology_drawer_id(cpu)
|
#define topology_drawer_id(cpu)
|
||||||
#define topology_sibling_cpumask(cpu)
|
#define topology_sibling_cpumask(cpu)
|
||||||
#define topology_core_cpumask(cpu)
|
#define topology_core_cpumask(cpu)
|
||||||
|
#define topology_die_cpumask(cpu)
|
||||||
#define topology_book_cpumask(cpu)
|
#define topology_book_cpumask(cpu)
|
||||||
#define topology_drawer_cpumask(cpu)
|
#define topology_drawer_cpumask(cpu)
|
||||||
|
|
||||||
|
@ -99,9 +115,11 @@ provides default definitions for any of the above macros that are
|
||||||
not defined by include/asm-XXX/topology.h:
|
not defined by include/asm-XXX/topology.h:
|
||||||
|
|
||||||
1) topology_physical_package_id: -1
|
1) topology_physical_package_id: -1
|
||||||
2) topology_core_id: 0
|
2) topology_die_id: -1
|
||||||
3) topology_sibling_cpumask: just the given CPU
|
3) topology_core_id: 0
|
||||||
4) topology_core_cpumask: just the given CPU
|
4) topology_sibling_cpumask: just the given CPU
|
||||||
|
5) topology_core_cpumask: just the given CPU
|
||||||
|
6) topology_die_cpumask: just the given CPU
|
||||||
|
|
||||||
For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
|
For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
|
||||||
default definitions for topology_book_id() and topology_book_cpumask().
|
default definitions for topology_book_id() and topology_book_cpumask().
|
||||||
|
|
|
@ -31,7 +31,7 @@ you probably needn't concern yourself with isdn4k-utils.
|
||||||
====================== =============== ========================================
|
====================== =============== ========================================
|
||||||
GNU C 4.6 gcc --version
|
GNU C 4.6 gcc --version
|
||||||
GNU make 3.81 make --version
|
GNU make 3.81 make --version
|
||||||
binutils 2.20 ld -v
|
binutils 2.21 ld -v
|
||||||
flex 2.5.35 flex --version
|
flex 2.5.35 flex --version
|
||||||
bison 2.0 bison --version
|
bison 2.0 bison --version
|
||||||
util-linux 2.10o fdformat --version
|
util-linux 2.10o fdformat --version
|
||||||
|
@ -77,9 +77,7 @@ You will need GNU make 3.81 or later to build the kernel.
|
||||||
Binutils
|
Binutils
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The build system has, as of 4.13, switched to using thin archives (`ar T`)
|
Binutils 2.21 or newer is needed to build the kernel.
|
||||||
rather than incremental linking (`ld -r`) for built-in.a intermediate steps.
|
|
||||||
This requires binutils 2.20 or newer.
|
|
||||||
|
|
||||||
pkg-config
|
pkg-config
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -49,6 +49,10 @@ Package-related topology information in the kernel:
|
||||||
|
|
||||||
The number of cores in a package. This information is retrieved via CPUID.
|
The number of cores in a package. This information is retrieved via CPUID.
|
||||||
|
|
||||||
|
- cpuinfo_x86.x86_max_dies:
|
||||||
|
|
||||||
|
The number of dies in a package. This information is retrieved via CPUID.
|
||||||
|
|
||||||
- cpuinfo_x86.phys_proc_id:
|
- cpuinfo_x86.phys_proc_id:
|
||||||
|
|
||||||
The physical ID of the package. This information is retrieved via CPUID
|
The physical ID of the package. This information is retrieved via CPUID
|
||||||
|
|
|
@ -7810,7 +7810,7 @@ INGENIC JZ4780 NAND DRIVER
|
||||||
M: Harvey Hunt <harveyhuntnexus@gmail.com>
|
M: Harvey Hunt <harveyhuntnexus@gmail.com>
|
||||||
L: linux-mtd@lists.infradead.org
|
L: linux-mtd@lists.infradead.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/mtd/nand/raw/jz4780_*
|
F: drivers/mtd/nand/raw/ingenic/
|
||||||
|
|
||||||
INOTIFY
|
INOTIFY
|
||||||
M: Jan Kara <jack@suse.cz>
|
M: Jan Kara <jack@suse.cz>
|
||||||
|
@ -17496,6 +17496,12 @@ Q: https://patchwork.linuxtv.org/project/linux-media/list/
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/media/dvb-frontends/zd1301_demod*
|
F: drivers/media/dvb-frontends/zd1301_demod*
|
||||||
|
|
||||||
|
ZHAOXIN PROCESSOR SUPPORT
|
||||||
|
M: Tony W Wang-oc <TonyWWang-oc@zhaoxin.com>
|
||||||
|
L: linux-kernel@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: arch/x86/kernel/cpu/zhaoxin.c
|
||||||
|
|
||||||
ZPOOL COMPRESSED PAGE STORAGE API
|
ZPOOL COMPRESSED PAGE STORAGE API
|
||||||
M: Dan Streetman <ddstreet@ieee.org>
|
M: Dan Streetman <ddstreet@ieee.org>
|
||||||
L: linux-mm@kvack.org
|
L: linux-mm@kvack.org
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
||||||
VERSION = 5
|
VERSION = 5
|
||||||
PATCHLEVEL = 2
|
PATCHLEVEL = 2
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION = -rc7
|
EXTRAVERSION =
|
||||||
NAME = Bobtail Squid
|
NAME = Bobtail Squid
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
|
|
@ -17,6 +17,7 @@ archscripts: scripts_basic
|
||||||
$(Q)$(MAKE) $(build)=arch/mips/boot/tools relocs
|
$(Q)$(MAKE) $(build)=arch/mips/boot/tools relocs
|
||||||
|
|
||||||
KBUILD_DEFCONFIG := 32r2el_defconfig
|
KBUILD_DEFCONFIG := 32r2el_defconfig
|
||||||
|
KBUILD_DTBS := dtbs
|
||||||
|
|
||||||
#
|
#
|
||||||
# Select the object file format to substitute into the linker script.
|
# Select the object file format to substitute into the linker script.
|
||||||
|
@ -384,7 +385,7 @@ quiet_cmd_64 = OBJCOPY $@
|
||||||
vmlinux.64: vmlinux
|
vmlinux.64: vmlinux
|
||||||
$(call cmd,64)
|
$(call cmd,64)
|
||||||
|
|
||||||
all: $(all-y)
|
all: $(all-y) $(KBUILD_DTBS)
|
||||||
|
|
||||||
# boot
|
# boot
|
||||||
$(boot-y): $(vmlinux-32) FORCE
|
$(boot-y): $(vmlinux-32) FORCE
|
||||||
|
|
|
@ -78,6 +78,8 @@ OBJCOPYFLAGS_piggy.o := --add-section=.image=$(obj)/vmlinux.bin.z \
|
||||||
$(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
|
$(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
|
||||||
$(call if_changed,objcopy)
|
$(call if_changed,objcopy)
|
||||||
|
|
||||||
|
HOSTCFLAGS_calc_vmlinuz_load_addr.o += $(LINUXINCLUDE)
|
||||||
|
|
||||||
# Calculate the load address of the compressed kernel image
|
# Calculate the load address of the compressed kernel image
|
||||||
hostprogs-y := calc_vmlinuz_load_addr
|
hostprogs-y := calc_vmlinuz_load_addr
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../../../../include/linux/sizes.h"
|
#include <linux/sizes.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#define AR933X_UART_CS_PARITY_S 0
|
#define AR933X_UART_CS_PARITY_S 0
|
||||||
#define AR933X_UART_CS_PARITY_M 0x3
|
#define AR933X_UART_CS_PARITY_M 0x3
|
||||||
#define AR933X_UART_CS_PARITY_NONE 0
|
#define AR933X_UART_CS_PARITY_NONE 0
|
||||||
#define AR933X_UART_CS_PARITY_ODD 1
|
#define AR933X_UART_CS_PARITY_ODD 2
|
||||||
#define AR933X_UART_CS_PARITY_EVEN 2
|
#define AR933X_UART_CS_PARITY_EVEN 3
|
||||||
#define AR933X_UART_CS_IF_MODE_S 2
|
#define AR933X_UART_CS_IF_MODE_S 2
|
||||||
#define AR933X_UART_CS_IF_MODE_M 0x3
|
#define AR933X_UART_CS_IF_MODE_M 0x3
|
||||||
#define AR933X_UART_CS_IF_MODE_NONE 0
|
#define AR933X_UART_CS_IF_MODE_NONE 0
|
||||||
|
|
|
@ -203,7 +203,7 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
|
||||||
|
|
||||||
bool __virt_addr_valid(const volatile void *kaddr)
|
bool __virt_addr_valid(const volatile void *kaddr)
|
||||||
{
|
{
|
||||||
unsigned long vaddr = (unsigned long)vaddr;
|
unsigned long vaddr = (unsigned long)kaddr;
|
||||||
|
|
||||||
if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE))
|
if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -391,6 +391,7 @@ static struct work_registers build_get_work_registers(u32 **p)
|
||||||
static void build_restore_work_registers(u32 **p)
|
static void build_restore_work_registers(u32 **p)
|
||||||
{
|
{
|
||||||
if (scratch_reg >= 0) {
|
if (scratch_reg >= 0) {
|
||||||
|
uasm_i_ehb(p);
|
||||||
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -668,10 +669,12 @@ static void build_restore_pagemask(u32 **p, struct uasm_reloc **r,
|
||||||
uasm_i_mtc0(p, 0, C0_PAGEMASK);
|
uasm_i_mtc0(p, 0, C0_PAGEMASK);
|
||||||
uasm_il_b(p, r, lid);
|
uasm_il_b(p, r, lid);
|
||||||
}
|
}
|
||||||
if (scratch_reg >= 0)
|
if (scratch_reg >= 0) {
|
||||||
|
uasm_i_ehb(p);
|
||||||
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
||||||
else
|
} else {
|
||||||
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Reset default page size */
|
/* Reset default page size */
|
||||||
if (PM_DEFAULT_MASK >> 16) {
|
if (PM_DEFAULT_MASK >> 16) {
|
||||||
|
@ -938,10 +941,12 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
||||||
uasm_i_jr(p, ptr);
|
uasm_i_jr(p, ptr);
|
||||||
|
|
||||||
if (mode == refill_scratch) {
|
if (mode == refill_scratch) {
|
||||||
if (scratch_reg >= 0)
|
if (scratch_reg >= 0) {
|
||||||
|
uasm_i_ehb(p);
|
||||||
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
|
||||||
else
|
} else {
|
||||||
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uasm_i_nop(p);
|
uasm_i_nop(p);
|
||||||
}
|
}
|
||||||
|
@ -1258,6 +1263,7 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
|
||||||
UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */
|
UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */
|
||||||
|
|
||||||
if (c0_scratch_reg >= 0) {
|
if (c0_scratch_reg >= 0) {
|
||||||
|
uasm_i_ehb(p);
|
||||||
UASM_i_MFC0(p, scratch, c0_kscratch(), c0_scratch_reg);
|
UASM_i_MFC0(p, scratch, c0_kscratch(), c0_scratch_reg);
|
||||||
build_tlb_write_entry(p, l, r, tlb_random);
|
build_tlb_write_entry(p, l, r, tlb_random);
|
||||||
uasm_l_leave(l, *p);
|
uasm_l_leave(l, *p);
|
||||||
|
@ -1603,15 +1609,17 @@ static void build_setup_pgd(void)
|
||||||
uasm_i_dinsm(&p, a0, 0, 29, 64 - 29);
|
uasm_i_dinsm(&p, a0, 0, 29, 64 - 29);
|
||||||
uasm_l_tlbl_goaround1(&l, p);
|
uasm_l_tlbl_goaround1(&l, p);
|
||||||
UASM_i_SLL(&p, a0, a0, 11);
|
UASM_i_SLL(&p, a0, a0, 11);
|
||||||
uasm_i_jr(&p, 31);
|
|
||||||
UASM_i_MTC0(&p, a0, C0_CONTEXT);
|
UASM_i_MTC0(&p, a0, C0_CONTEXT);
|
||||||
|
uasm_i_jr(&p, 31);
|
||||||
|
uasm_i_ehb(&p);
|
||||||
} else {
|
} else {
|
||||||
/* PGD in c0_KScratch */
|
/* PGD in c0_KScratch */
|
||||||
uasm_i_jr(&p, 31);
|
|
||||||
if (cpu_has_ldpte)
|
if (cpu_has_ldpte)
|
||||||
UASM_i_MTC0(&p, a0, C0_PWBASE);
|
UASM_i_MTC0(&p, a0, C0_PWBASE);
|
||||||
else
|
else
|
||||||
UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
||||||
|
uasm_i_jr(&p, 31);
|
||||||
|
uasm_i_ehb(&p);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@ -1625,13 +1633,16 @@ static void build_setup_pgd(void)
|
||||||
UASM_i_LA_mostly(&p, a2, pgdc);
|
UASM_i_LA_mostly(&p, a2, pgdc);
|
||||||
UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
|
UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2);
|
||||||
#endif /* SMP */
|
#endif /* SMP */
|
||||||
uasm_i_jr(&p, 31);
|
|
||||||
|
|
||||||
/* if pgd_reg is allocated, save PGD also to scratch register */
|
/* if pgd_reg is allocated, save PGD also to scratch register */
|
||||||
if (pgd_reg != -1)
|
if (pgd_reg != -1) {
|
||||||
UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg);
|
||||||
else
|
uasm_i_jr(&p, 31);
|
||||||
|
uasm_i_ehb(&p);
|
||||||
|
} else {
|
||||||
|
uasm_i_jr(&p, 31);
|
||||||
uasm_i_nop(&p);
|
uasm_i_nop(&p);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (p >= (u32 *)tlbmiss_handler_setup_pgd_end)
|
if (p >= (u32 *)tlbmiss_handler_setup_pgd_end)
|
||||||
panic("tlbmiss_handler_setup_pgd space exceeded");
|
panic("tlbmiss_handler_setup_pgd space exceeded");
|
||||||
|
|
|
@ -480,3 +480,16 @@ config CPU_SUP_UMC_32
|
||||||
CPU might render the kernel unbootable.
|
CPU might render the kernel unbootable.
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config CPU_SUP_ZHAOXIN
|
||||||
|
default y
|
||||||
|
bool "Support Zhaoxin processors" if PROCESSOR_SELECT
|
||||||
|
help
|
||||||
|
This enables detection, tunings and quirks for Zhaoxin processors
|
||||||
|
|
||||||
|
You need this enabled if you want your kernel to run on a
|
||||||
|
Zhaoxin CPU. Disabling this option on other types of CPUs
|
||||||
|
makes the kernel a tiny bit smaller. Disabling it on a Zhaoxin
|
||||||
|
CPU might render the kernel unbootable.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
|
@ -1670,11 +1670,17 @@ nmi_restore:
|
||||||
iretq
|
iretq
|
||||||
END(nmi)
|
END(nmi)
|
||||||
|
|
||||||
|
#ifndef CONFIG_IA32_EMULATION
|
||||||
|
/*
|
||||||
|
* This handles SYSCALL from 32-bit code. There is no way to program
|
||||||
|
* MSRs to fully disable 32-bit SYSCALL.
|
||||||
|
*/
|
||||||
ENTRY(ignore_sysret)
|
ENTRY(ignore_sysret)
|
||||||
UNWIND_HINT_EMPTY
|
UNWIND_HINT_EMPTY
|
||||||
mov $-ENOSYS, %eax
|
mov $-ENOSYS, %eax
|
||||||
sysret
|
sysret
|
||||||
END(ignore_sysret)
|
END(ignore_sysret)
|
||||||
|
#endif
|
||||||
|
|
||||||
ENTRY(rewind_stack_do_exit)
|
ENTRY(rewind_stack_do_exit)
|
||||||
UNWIND_HINT_FUNC
|
UNWIND_HINT_FUNC
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
obj-y += core.o
|
obj-y += core.o probe.o
|
||||||
obj-y += amd/
|
obj-y += amd/
|
||||||
obj-$(CONFIG_X86_LOCAL_APIC) += msr.o
|
obj-$(CONFIG_X86_LOCAL_APIC) += msr.o
|
||||||
obj-$(CONFIG_CPU_SUP_INTEL) += intel/
|
obj-$(CONFIG_CPU_SUP_INTEL) += intel/
|
||||||
|
|
|
@ -1618,68 +1618,6 @@ static struct attribute_group x86_pmu_format_group __ro_after_init = {
|
||||||
.attrs = NULL,
|
.attrs = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove all undefined events (x86_pmu.event_map(id) == 0)
|
|
||||||
* out of events_attr attributes.
|
|
||||||
*/
|
|
||||||
static void __init filter_events(struct attribute **attrs)
|
|
||||||
{
|
|
||||||
struct device_attribute *d;
|
|
||||||
struct perf_pmu_events_attr *pmu_attr;
|
|
||||||
int offset = 0;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; attrs[i]; i++) {
|
|
||||||
d = (struct device_attribute *)attrs[i];
|
|
||||||
pmu_attr = container_of(d, struct perf_pmu_events_attr, attr);
|
|
||||||
/* str trumps id */
|
|
||||||
if (pmu_attr->event_str)
|
|
||||||
continue;
|
|
||||||
if (x86_pmu.event_map(i + offset))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (j = i; attrs[j]; j++)
|
|
||||||
attrs[j] = attrs[j + 1];
|
|
||||||
|
|
||||||
/* Check the shifted attr. */
|
|
||||||
i--;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* event_map() is index based, the attrs array is organized
|
|
||||||
* by increasing event index. If we shift the events, then
|
|
||||||
* we need to compensate for the event_map(), otherwise
|
|
||||||
* we are looking up the wrong event in the map
|
|
||||||
*/
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Merge two pointer arrays */
|
|
||||||
__init struct attribute **merge_attr(struct attribute **a, struct attribute **b)
|
|
||||||
{
|
|
||||||
struct attribute **new;
|
|
||||||
int j, i;
|
|
||||||
|
|
||||||
for (j = 0; a && a[j]; j++)
|
|
||||||
;
|
|
||||||
for (i = 0; b && b[i]; i++)
|
|
||||||
j++;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
new = kmalloc_array(j, sizeof(struct attribute *), GFP_KERNEL);
|
|
||||||
if (!new)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
j = 0;
|
|
||||||
for (i = 0; a && a[i]; i++)
|
|
||||||
new[j++] = a[i];
|
|
||||||
for (i = 0; b && b[i]; i++)
|
|
||||||
new[j++] = b[i];
|
|
||||||
new[j] = NULL;
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page)
|
ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page)
|
||||||
{
|
{
|
||||||
struct perf_pmu_events_attr *pmu_attr = \
|
struct perf_pmu_events_attr *pmu_attr = \
|
||||||
|
@ -1744,9 +1682,24 @@ static struct attribute *events_attr[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove all undefined events (x86_pmu.event_map(id) == 0)
|
||||||
|
* out of events_attr attributes.
|
||||||
|
*/
|
||||||
|
static umode_t
|
||||||
|
is_visible(struct kobject *kobj, struct attribute *attr, int idx)
|
||||||
|
{
|
||||||
|
struct perf_pmu_events_attr *pmu_attr;
|
||||||
|
|
||||||
|
pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
|
||||||
|
/* str trumps id */
|
||||||
|
return pmu_attr->event_str || x86_pmu.event_map(idx) ? attr->mode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct attribute_group x86_pmu_events_group __ro_after_init = {
|
static struct attribute_group x86_pmu_events_group __ro_after_init = {
|
||||||
.name = "events",
|
.name = "events",
|
||||||
.attrs = events_attr,
|
.attrs = events_attr,
|
||||||
|
.is_visible = is_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event)
|
ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event)
|
||||||
|
@ -1842,37 +1795,10 @@ static int __init init_hw_perf_events(void)
|
||||||
|
|
||||||
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
|
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
|
||||||
|
|
||||||
if (x86_pmu.caps_attrs) {
|
|
||||||
struct attribute **tmp;
|
|
||||||
|
|
||||||
tmp = merge_attr(x86_pmu_caps_group.attrs, x86_pmu.caps_attrs);
|
|
||||||
if (!WARN_ON(!tmp))
|
|
||||||
x86_pmu_caps_group.attrs = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x86_pmu.event_attrs)
|
|
||||||
x86_pmu_events_group.attrs = x86_pmu.event_attrs;
|
|
||||||
|
|
||||||
if (!x86_pmu.events_sysfs_show)
|
if (!x86_pmu.events_sysfs_show)
|
||||||
x86_pmu_events_group.attrs = &empty_attrs;
|
x86_pmu_events_group.attrs = &empty_attrs;
|
||||||
else
|
|
||||||
filter_events(x86_pmu_events_group.attrs);
|
|
||||||
|
|
||||||
if (x86_pmu.cpu_events) {
|
pmu.attr_update = x86_pmu.attr_update;
|
||||||
struct attribute **tmp;
|
|
||||||
|
|
||||||
tmp = merge_attr(x86_pmu_events_group.attrs, x86_pmu.cpu_events);
|
|
||||||
if (!WARN_ON(!tmp))
|
|
||||||
x86_pmu_events_group.attrs = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x86_pmu.attrs) {
|
|
||||||
struct attribute **tmp;
|
|
||||||
|
|
||||||
tmp = merge_attr(x86_pmu_attr_group.attrs, x86_pmu.attrs);
|
|
||||||
if (!WARN_ON(!tmp))
|
|
||||||
x86_pmu_attr_group.attrs = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("... version: %d\n", x86_pmu.version);
|
pr_info("... version: %d\n", x86_pmu.version);
|
||||||
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
|
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <asm/intel-family.h>
|
#include <asm/intel-family.h>
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/cpu_device_id.h>
|
#include <asm/cpu_device_id.h>
|
||||||
|
#include <asm/hypervisor.h>
|
||||||
|
|
||||||
#include "../perf_event.h"
|
#include "../perf_event.h"
|
||||||
|
|
||||||
|
@ -3897,8 +3898,6 @@ static __initconst const struct x86_pmu core_pmu = {
|
||||||
.check_period = intel_pmu_check_period,
|
.check_period = intel_pmu_check_period,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute *intel_pmu_attrs[];
|
|
||||||
|
|
||||||
static __initconst const struct x86_pmu intel_pmu = {
|
static __initconst const struct x86_pmu intel_pmu = {
|
||||||
.name = "Intel",
|
.name = "Intel",
|
||||||
.handle_irq = intel_pmu_handle_irq,
|
.handle_irq = intel_pmu_handle_irq,
|
||||||
|
@ -3930,8 +3929,6 @@ static __initconst const struct x86_pmu intel_pmu = {
|
||||||
.format_attrs = intel_arch3_formats_attr,
|
.format_attrs = intel_arch3_formats_attr,
|
||||||
.events_sysfs_show = intel_event_sysfs_show,
|
.events_sysfs_show = intel_event_sysfs_show,
|
||||||
|
|
||||||
.attrs = intel_pmu_attrs,
|
|
||||||
|
|
||||||
.cpu_prepare = intel_pmu_cpu_prepare,
|
.cpu_prepare = intel_pmu_cpu_prepare,
|
||||||
.cpu_starting = intel_pmu_cpu_starting,
|
.cpu_starting = intel_pmu_cpu_starting,
|
||||||
.cpu_dying = intel_pmu_cpu_dying,
|
.cpu_dying = intel_pmu_cpu_dying,
|
||||||
|
@ -4054,6 +4051,13 @@ static bool check_msr(unsigned long msr, u64 mask)
|
||||||
{
|
{
|
||||||
u64 val_old, val_new, val_tmp;
|
u64 val_old, val_new, val_tmp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the check for real HW, so we don't
|
||||||
|
* mess with potentionaly enabled registers:
|
||||||
|
*/
|
||||||
|
if (hypervisor_is_type(X86_HYPER_NATIVE))
|
||||||
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the current value, change it and read it back to see if it
|
* Read the current value, change it and read it back to see if it
|
||||||
* matches, this is needed to detect certain hardware emulators
|
* matches, this is needed to detect certain hardware emulators
|
||||||
|
@ -4274,13 +4278,6 @@ static struct attribute *icl_tsx_events_attrs[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static __init struct attribute **get_icl_events_attrs(void)
|
|
||||||
{
|
|
||||||
return boot_cpu_has(X86_FEATURE_RTM) ?
|
|
||||||
merge_attr(icl_events_attrs, icl_tsx_events_attrs) :
|
|
||||||
icl_events_attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t freeze_on_smi_show(struct device *cdev,
|
static ssize_t freeze_on_smi_show(struct device *cdev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
|
@ -4402,43 +4399,111 @@ static DEVICE_ATTR(allow_tsx_force_abort, 0644,
|
||||||
|
|
||||||
static struct attribute *intel_pmu_attrs[] = {
|
static struct attribute *intel_pmu_attrs[] = {
|
||||||
&dev_attr_freeze_on_smi.attr,
|
&dev_attr_freeze_on_smi.attr,
|
||||||
NULL, /* &dev_attr_allow_tsx_force_abort.attr.attr */
|
&dev_attr_allow_tsx_force_abort.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static __init struct attribute **
|
static umode_t
|
||||||
get_events_attrs(struct attribute **base,
|
tsx_is_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
struct attribute **mem,
|
|
||||||
struct attribute **tsx)
|
|
||||||
{
|
{
|
||||||
struct attribute **attrs = base;
|
return boot_cpu_has(X86_FEATURE_RTM) ? attr->mode : 0;
|
||||||
struct attribute **old;
|
|
||||||
|
|
||||||
if (mem && x86_pmu.pebs)
|
|
||||||
attrs = merge_attr(attrs, mem);
|
|
||||||
|
|
||||||
if (tsx && boot_cpu_has(X86_FEATURE_RTM)) {
|
|
||||||
old = attrs;
|
|
||||||
attrs = merge_attr(attrs, tsx);
|
|
||||||
if (old != base)
|
|
||||||
kfree(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
return attrs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static umode_t
|
||||||
|
pebs_is_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
return x86_pmu.pebs ? attr->mode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static umode_t
|
||||||
|
lbr_is_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
return x86_pmu.lbr_nr ? attr->mode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static umode_t
|
||||||
|
exra_is_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
return x86_pmu.version >= 2 ? attr->mode : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static umode_t
|
||||||
|
default_is_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
if (attr == &dev_attr_allow_tsx_force_abort.attr)
|
||||||
|
return x86_pmu.flags & PMU_FL_TFA ? attr->mode : 0;
|
||||||
|
|
||||||
|
return attr->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct attribute_group group_events_td = {
|
||||||
|
.name = "events",
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_events_mem = {
|
||||||
|
.name = "events",
|
||||||
|
.is_visible = pebs_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_events_tsx = {
|
||||||
|
.name = "events",
|
||||||
|
.is_visible = tsx_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_caps_gen = {
|
||||||
|
.name = "caps",
|
||||||
|
.attrs = intel_pmu_caps_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_caps_lbr = {
|
||||||
|
.name = "caps",
|
||||||
|
.attrs = lbr_attrs,
|
||||||
|
.is_visible = lbr_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_format_extra = {
|
||||||
|
.name = "format",
|
||||||
|
.is_visible = exra_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_format_extra_skl = {
|
||||||
|
.name = "format",
|
||||||
|
.is_visible = exra_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group group_default = {
|
||||||
|
.attrs = intel_pmu_attrs,
|
||||||
|
.is_visible = default_is_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group *attr_update[] = {
|
||||||
|
&group_events_td,
|
||||||
|
&group_events_mem,
|
||||||
|
&group_events_tsx,
|
||||||
|
&group_caps_gen,
|
||||||
|
&group_caps_lbr,
|
||||||
|
&group_format_extra,
|
||||||
|
&group_format_extra_skl,
|
||||||
|
&group_default,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *empty_attrs;
|
||||||
|
|
||||||
__init int intel_pmu_init(void)
|
__init int intel_pmu_init(void)
|
||||||
{
|
{
|
||||||
struct attribute **extra_attr = NULL;
|
struct attribute **extra_skl_attr = &empty_attrs;
|
||||||
struct attribute **mem_attr = NULL;
|
struct attribute **extra_attr = &empty_attrs;
|
||||||
struct attribute **tsx_attr = NULL;
|
struct attribute **td_attr = &empty_attrs;
|
||||||
struct attribute **to_free = NULL;
|
struct attribute **mem_attr = &empty_attrs;
|
||||||
|
struct attribute **tsx_attr = &empty_attrs;
|
||||||
union cpuid10_edx edx;
|
union cpuid10_edx edx;
|
||||||
union cpuid10_eax eax;
|
union cpuid10_eax eax;
|
||||||
union cpuid10_ebx ebx;
|
union cpuid10_ebx ebx;
|
||||||
struct event_constraint *c;
|
struct event_constraint *c;
|
||||||
unsigned int unused;
|
unsigned int unused;
|
||||||
struct extra_reg *er;
|
struct extra_reg *er;
|
||||||
|
bool pmem = false;
|
||||||
int version, i;
|
int version, i;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
|
@ -4596,7 +4661,7 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
|
x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
|
||||||
x86_pmu.extra_regs = intel_slm_extra_regs;
|
x86_pmu.extra_regs = intel_slm_extra_regs;
|
||||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||||
x86_pmu.cpu_events = slm_events_attrs;
|
td_attr = slm_events_attrs;
|
||||||
extra_attr = slm_format_attr;
|
extra_attr = slm_format_attr;
|
||||||
pr_cont("Silvermont events, ");
|
pr_cont("Silvermont events, ");
|
||||||
name = "silvermont";
|
name = "silvermont";
|
||||||
|
@ -4624,7 +4689,7 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.pebs_prec_dist = true;
|
x86_pmu.pebs_prec_dist = true;
|
||||||
x86_pmu.lbr_pt_coexist = true;
|
x86_pmu.lbr_pt_coexist = true;
|
||||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||||
x86_pmu.cpu_events = glm_events_attrs;
|
td_attr = glm_events_attrs;
|
||||||
extra_attr = slm_format_attr;
|
extra_attr = slm_format_attr;
|
||||||
pr_cont("Goldmont events, ");
|
pr_cont("Goldmont events, ");
|
||||||
name = "goldmont";
|
name = "goldmont";
|
||||||
|
@ -4651,7 +4716,7 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||||
x86_pmu.flags |= PMU_FL_PEBS_ALL;
|
x86_pmu.flags |= PMU_FL_PEBS_ALL;
|
||||||
x86_pmu.get_event_constraints = glp_get_event_constraints;
|
x86_pmu.get_event_constraints = glp_get_event_constraints;
|
||||||
x86_pmu.cpu_events = glm_events_attrs;
|
td_attr = glm_events_attrs;
|
||||||
/* Goldmont Plus has 4-wide pipeline */
|
/* Goldmont Plus has 4-wide pipeline */
|
||||||
event_attr_td_total_slots_scale_glm.event_str = "4";
|
event_attr_td_total_slots_scale_glm.event_str = "4";
|
||||||
extra_attr = slm_format_attr;
|
extra_attr = slm_format_attr;
|
||||||
|
@ -4740,7 +4805,7 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||||
|
|
||||||
x86_pmu.cpu_events = snb_events_attrs;
|
td_attr = snb_events_attrs;
|
||||||
mem_attr = snb_mem_events_attrs;
|
mem_attr = snb_mem_events_attrs;
|
||||||
|
|
||||||
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
|
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
|
||||||
|
@ -4781,7 +4846,7 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||||
|
|
||||||
x86_pmu.cpu_events = snb_events_attrs;
|
td_attr = snb_events_attrs;
|
||||||
mem_attr = snb_mem_events_attrs;
|
mem_attr = snb_mem_events_attrs;
|
||||||
|
|
||||||
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
|
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
|
||||||
|
@ -4818,10 +4883,10 @@ __init int intel_pmu_init(void)
|
||||||
|
|
||||||
x86_pmu.hw_config = hsw_hw_config;
|
x86_pmu.hw_config = hsw_hw_config;
|
||||||
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
||||||
x86_pmu.cpu_events = hsw_events_attrs;
|
|
||||||
x86_pmu.lbr_double_abort = true;
|
x86_pmu.lbr_double_abort = true;
|
||||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||||
hsw_format_attr : nhm_format_attr;
|
hsw_format_attr : nhm_format_attr;
|
||||||
|
td_attr = hsw_events_attrs;
|
||||||
mem_attr = hsw_mem_events_attrs;
|
mem_attr = hsw_mem_events_attrs;
|
||||||
tsx_attr = hsw_tsx_events_attrs;
|
tsx_attr = hsw_tsx_events_attrs;
|
||||||
pr_cont("Haswell events, ");
|
pr_cont("Haswell events, ");
|
||||||
|
@ -4860,10 +4925,10 @@ __init int intel_pmu_init(void)
|
||||||
|
|
||||||
x86_pmu.hw_config = hsw_hw_config;
|
x86_pmu.hw_config = hsw_hw_config;
|
||||||
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
||||||
x86_pmu.cpu_events = hsw_events_attrs;
|
|
||||||
x86_pmu.limit_period = bdw_limit_period;
|
x86_pmu.limit_period = bdw_limit_period;
|
||||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||||
hsw_format_attr : nhm_format_attr;
|
hsw_format_attr : nhm_format_attr;
|
||||||
|
td_attr = hsw_events_attrs;
|
||||||
mem_attr = hsw_mem_events_attrs;
|
mem_attr = hsw_mem_events_attrs;
|
||||||
tsx_attr = hsw_tsx_events_attrs;
|
tsx_attr = hsw_tsx_events_attrs;
|
||||||
pr_cont("Broadwell events, ");
|
pr_cont("Broadwell events, ");
|
||||||
|
@ -4890,9 +4955,10 @@ __init int intel_pmu_init(void)
|
||||||
name = "knights-landing";
|
name = "knights-landing";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INTEL_FAM6_SKYLAKE_X:
|
||||||
|
pmem = true;
|
||||||
case INTEL_FAM6_SKYLAKE_MOBILE:
|
case INTEL_FAM6_SKYLAKE_MOBILE:
|
||||||
case INTEL_FAM6_SKYLAKE_DESKTOP:
|
case INTEL_FAM6_SKYLAKE_DESKTOP:
|
||||||
case INTEL_FAM6_SKYLAKE_X:
|
|
||||||
case INTEL_FAM6_KABYLAKE_MOBILE:
|
case INTEL_FAM6_KABYLAKE_MOBILE:
|
||||||
case INTEL_FAM6_KABYLAKE_DESKTOP:
|
case INTEL_FAM6_KABYLAKE_DESKTOP:
|
||||||
x86_add_quirk(intel_pebs_isolation_quirk);
|
x86_add_quirk(intel_pebs_isolation_quirk);
|
||||||
|
@ -4920,27 +4986,28 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
x86_pmu.get_event_constraints = hsw_get_event_constraints;
|
||||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||||
hsw_format_attr : nhm_format_attr;
|
hsw_format_attr : nhm_format_attr;
|
||||||
extra_attr = merge_attr(extra_attr, skl_format_attr);
|
extra_skl_attr = skl_format_attr;
|
||||||
to_free = extra_attr;
|
td_attr = hsw_events_attrs;
|
||||||
x86_pmu.cpu_events = hsw_events_attrs;
|
|
||||||
mem_attr = hsw_mem_events_attrs;
|
mem_attr = hsw_mem_events_attrs;
|
||||||
tsx_attr = hsw_tsx_events_attrs;
|
tsx_attr = hsw_tsx_events_attrs;
|
||||||
intel_pmu_pebs_data_source_skl(
|
intel_pmu_pebs_data_source_skl(pmem);
|
||||||
boot_cpu_data.x86_model == INTEL_FAM6_SKYLAKE_X);
|
|
||||||
|
|
||||||
if (boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
|
if (boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
|
||||||
x86_pmu.flags |= PMU_FL_TFA;
|
x86_pmu.flags |= PMU_FL_TFA;
|
||||||
x86_pmu.get_event_constraints = tfa_get_event_constraints;
|
x86_pmu.get_event_constraints = tfa_get_event_constraints;
|
||||||
x86_pmu.enable_all = intel_tfa_pmu_enable_all;
|
x86_pmu.enable_all = intel_tfa_pmu_enable_all;
|
||||||
x86_pmu.commit_scheduling = intel_tfa_commit_scheduling;
|
x86_pmu.commit_scheduling = intel_tfa_commit_scheduling;
|
||||||
intel_pmu_attrs[1] = &dev_attr_allow_tsx_force_abort.attr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_cont("Skylake events, ");
|
pr_cont("Skylake events, ");
|
||||||
name = "skylake";
|
name = "skylake";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INTEL_FAM6_ICELAKE_X:
|
||||||
|
case INTEL_FAM6_ICELAKE_XEON_D:
|
||||||
|
pmem = true;
|
||||||
case INTEL_FAM6_ICELAKE_MOBILE:
|
case INTEL_FAM6_ICELAKE_MOBILE:
|
||||||
|
case INTEL_FAM6_ICELAKE_DESKTOP:
|
||||||
x86_pmu.late_ack = true;
|
x86_pmu.late_ack = true;
|
||||||
memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
||||||
memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
|
memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
|
||||||
|
@ -4959,11 +5026,12 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.get_event_constraints = icl_get_event_constraints;
|
x86_pmu.get_event_constraints = icl_get_event_constraints;
|
||||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||||
hsw_format_attr : nhm_format_attr;
|
hsw_format_attr : nhm_format_attr;
|
||||||
extra_attr = merge_attr(extra_attr, skl_format_attr);
|
extra_skl_attr = skl_format_attr;
|
||||||
x86_pmu.cpu_events = get_icl_events_attrs();
|
mem_attr = icl_events_attrs;
|
||||||
|
tsx_attr = icl_tsx_events_attrs;
|
||||||
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xca, .umask=0x02);
|
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xca, .umask=0x02);
|
||||||
x86_pmu.lbr_pt_coexist = true;
|
x86_pmu.lbr_pt_coexist = true;
|
||||||
intel_pmu_pebs_data_source_skl(false);
|
intel_pmu_pebs_data_source_skl(pmem);
|
||||||
pr_cont("Icelake events, ");
|
pr_cont("Icelake events, ");
|
||||||
name = "icelake";
|
name = "icelake";
|
||||||
break;
|
break;
|
||||||
|
@ -4988,14 +5056,14 @@ __init int intel_pmu_init(void)
|
||||||
|
|
||||||
snprintf(pmu_name_str, sizeof(pmu_name_str), "%s", name);
|
snprintf(pmu_name_str, sizeof(pmu_name_str), "%s", name);
|
||||||
|
|
||||||
if (version >= 2 && extra_attr) {
|
|
||||||
x86_pmu.format_attrs = merge_attr(intel_arch3_formats_attr,
|
|
||||||
extra_attr);
|
|
||||||
WARN_ON(!x86_pmu.format_attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
x86_pmu.cpu_events = get_events_attrs(x86_pmu.cpu_events,
|
group_events_td.attrs = td_attr;
|
||||||
mem_attr, tsx_attr);
|
group_events_mem.attrs = mem_attr;
|
||||||
|
group_events_tsx.attrs = tsx_attr;
|
||||||
|
group_format_extra.attrs = extra_attr;
|
||||||
|
group_format_extra_skl.attrs = extra_skl_attr;
|
||||||
|
|
||||||
|
x86_pmu.attr_update = attr_update;
|
||||||
|
|
||||||
if (x86_pmu.num_counters > INTEL_PMC_MAX_GENERIC) {
|
if (x86_pmu.num_counters > INTEL_PMC_MAX_GENERIC) {
|
||||||
WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
|
WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
|
||||||
|
@ -5043,12 +5111,8 @@ __init int intel_pmu_init(void)
|
||||||
x86_pmu.lbr_nr = 0;
|
x86_pmu.lbr_nr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
x86_pmu.caps_attrs = intel_pmu_caps_attrs;
|
if (x86_pmu.lbr_nr)
|
||||||
|
|
||||||
if (x86_pmu.lbr_nr) {
|
|
||||||
x86_pmu.caps_attrs = merge_attr(x86_pmu.caps_attrs, lbr_attrs);
|
|
||||||
pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
|
pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Access extra MSR may cause #GP under certain circumstances.
|
* Access extra MSR may cause #GP under certain circumstances.
|
||||||
|
@ -5078,7 +5142,6 @@ __init int intel_pmu_init(void)
|
||||||
if (x86_pmu.counter_freezing)
|
if (x86_pmu.counter_freezing)
|
||||||
x86_pmu.handle_irq = intel_pmu_handle_irq_v4;
|
x86_pmu.handle_irq = intel_pmu_handle_irq_v4;
|
||||||
|
|
||||||
kfree(to_free);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@
|
||||||
#include <asm/cpu_device_id.h>
|
#include <asm/cpu_device_id.h>
|
||||||
#include <asm/intel-family.h>
|
#include <asm/intel-family.h>
|
||||||
#include "../perf_event.h"
|
#include "../perf_event.h"
|
||||||
|
#include "../probe.h"
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@ -144,25 +145,42 @@ enum perf_cstate_core_events {
|
||||||
PERF_CSTATE_CORE_EVENT_MAX,
|
PERF_CSTATE_CORE_EVENT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00");
|
PMU_EVENT_ATTR_STRING(c1-residency, attr_cstate_core_c1, "event=0x00");
|
||||||
PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01");
|
PMU_EVENT_ATTR_STRING(c3-residency, attr_cstate_core_c3, "event=0x01");
|
||||||
PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02");
|
PMU_EVENT_ATTR_STRING(c6-residency, attr_cstate_core_c6, "event=0x02");
|
||||||
PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03");
|
PMU_EVENT_ATTR_STRING(c7-residency, attr_cstate_core_c7, "event=0x03");
|
||||||
|
|
||||||
static struct perf_cstate_msr core_msr[] = {
|
static unsigned long core_msr_mask;
|
||||||
[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1 },
|
|
||||||
[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3 },
|
PMU_EVENT_GROUP(events, cstate_core_c1);
|
||||||
[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6 },
|
PMU_EVENT_GROUP(events, cstate_core_c3);
|
||||||
[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7 },
|
PMU_EVENT_GROUP(events, cstate_core_c6);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_core_c7);
|
||||||
|
|
||||||
|
static bool test_msr(int idx, void *data)
|
||||||
|
{
|
||||||
|
return test_bit(idx, (unsigned long *) data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_msr core_msr[] = {
|
||||||
|
[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &group_cstate_core_c1, test_msr },
|
||||||
|
[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &group_cstate_core_c3, test_msr },
|
||||||
|
[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &group_cstate_core_c6, test_msr },
|
||||||
|
[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &group_cstate_core_c7, test_msr },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = {
|
static struct attribute *attrs_empty[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are no default events, but we need to create
|
||||||
|
* "events" group (with empty attrs) before updating
|
||||||
|
* it with detected events.
|
||||||
|
*/
|
||||||
static struct attribute_group core_events_attr_group = {
|
static struct attribute_group core_events_attr_group = {
|
||||||
.name = "events",
|
.name = "events",
|
||||||
.attrs = core_events_attrs,
|
.attrs = attrs_empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
|
DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
|
||||||
|
@ -211,31 +229,37 @@ enum perf_cstate_pkg_events {
|
||||||
PERF_CSTATE_PKG_EVENT_MAX,
|
PERF_CSTATE_PKG_EVENT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00");
|
PMU_EVENT_ATTR_STRING(c2-residency, attr_cstate_pkg_c2, "event=0x00");
|
||||||
PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01");
|
PMU_EVENT_ATTR_STRING(c3-residency, attr_cstate_pkg_c3, "event=0x01");
|
||||||
PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02");
|
PMU_EVENT_ATTR_STRING(c6-residency, attr_cstate_pkg_c6, "event=0x02");
|
||||||
PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_pkg_c7, "event=0x03");
|
PMU_EVENT_ATTR_STRING(c7-residency, attr_cstate_pkg_c7, "event=0x03");
|
||||||
PMU_EVENT_ATTR_STRING(c8-residency, evattr_cstate_pkg_c8, "event=0x04");
|
PMU_EVENT_ATTR_STRING(c8-residency, attr_cstate_pkg_c8, "event=0x04");
|
||||||
PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05");
|
PMU_EVENT_ATTR_STRING(c9-residency, attr_cstate_pkg_c9, "event=0x05");
|
||||||
PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06");
|
PMU_EVENT_ATTR_STRING(c10-residency, attr_cstate_pkg_c10, "event=0x06");
|
||||||
|
|
||||||
static struct perf_cstate_msr pkg_msr[] = {
|
static unsigned long pkg_msr_mask;
|
||||||
[PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2 },
|
|
||||||
[PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3 },
|
|
||||||
[PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6 },
|
|
||||||
[PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7 },
|
|
||||||
[PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8 },
|
|
||||||
[PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9 },
|
|
||||||
[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = {
|
PMU_EVENT_GROUP(events, cstate_pkg_c2);
|
||||||
NULL,
|
PMU_EVENT_GROUP(events, cstate_pkg_c3);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_pkg_c6);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_pkg_c7);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_pkg_c8);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_pkg_c9);
|
||||||
|
PMU_EVENT_GROUP(events, cstate_pkg_c10);
|
||||||
|
|
||||||
|
static struct perf_msr pkg_msr[] = {
|
||||||
|
[PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &group_cstate_pkg_c2, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &group_cstate_pkg_c3, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &group_cstate_pkg_c6, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &group_cstate_pkg_c7, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &group_cstate_pkg_c8, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &group_cstate_pkg_c9, test_msr },
|
||||||
|
[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &group_cstate_pkg_c10, test_msr },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group pkg_events_attr_group = {
|
static struct attribute_group pkg_events_attr_group = {
|
||||||
.name = "events",
|
.name = "events",
|
||||||
.attrs = pkg_events_attrs,
|
.attrs = attrs_empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
|
DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
|
||||||
|
@ -289,7 +313,8 @@ static int cstate_pmu_event_init(struct perf_event *event)
|
||||||
if (event->pmu == &cstate_core_pmu) {
|
if (event->pmu == &cstate_core_pmu) {
|
||||||
if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
|
if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!core_msr[cfg].attr)
|
cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_CORE_EVENT_MAX);
|
||||||
|
if (!(core_msr_mask & (1 << cfg)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
event->hw.event_base = core_msr[cfg].msr;
|
event->hw.event_base = core_msr[cfg].msr;
|
||||||
cpu = cpumask_any_and(&cstate_core_cpu_mask,
|
cpu = cpumask_any_and(&cstate_core_cpu_mask,
|
||||||
|
@ -298,11 +323,11 @@ static int cstate_pmu_event_init(struct perf_event *event)
|
||||||
if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
|
if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
|
cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
|
||||||
if (!pkg_msr[cfg].attr)
|
if (!(pkg_msr_mask & (1 << cfg)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
event->hw.event_base = pkg_msr[cfg].msr;
|
event->hw.event_base = pkg_msr[cfg].msr;
|
||||||
cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
|
cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
|
||||||
topology_core_cpumask(event->cpu));
|
topology_die_cpumask(event->cpu));
|
||||||
} else {
|
} else {
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -385,7 +410,7 @@ static int cstate_cpu_exit(unsigned int cpu)
|
||||||
if (has_cstate_pkg &&
|
if (has_cstate_pkg &&
|
||||||
cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
|
cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
|
||||||
|
|
||||||
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
|
target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
|
||||||
/* Migrate events if there is a valid target */
|
/* Migrate events if there is a valid target */
|
||||||
if (target < nr_cpu_ids) {
|
if (target < nr_cpu_ids) {
|
||||||
cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
|
cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
|
||||||
|
@ -414,15 +439,35 @@ static int cstate_cpu_init(unsigned int cpu)
|
||||||
* in the package cpu mask as the designated reader.
|
* in the package cpu mask as the designated reader.
|
||||||
*/
|
*/
|
||||||
target = cpumask_any_and(&cstate_pkg_cpu_mask,
|
target = cpumask_any_and(&cstate_pkg_cpu_mask,
|
||||||
topology_core_cpumask(cpu));
|
topology_die_cpumask(cpu));
|
||||||
if (has_cstate_pkg && target >= nr_cpu_ids)
|
if (has_cstate_pkg && target >= nr_cpu_ids)
|
||||||
cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
|
cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct attribute_group *core_attr_update[] = {
|
||||||
|
&group_cstate_core_c1,
|
||||||
|
&group_cstate_core_c3,
|
||||||
|
&group_cstate_core_c6,
|
||||||
|
&group_cstate_core_c7,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct attribute_group *pkg_attr_update[] = {
|
||||||
|
&group_cstate_pkg_c2,
|
||||||
|
&group_cstate_pkg_c3,
|
||||||
|
&group_cstate_pkg_c6,
|
||||||
|
&group_cstate_pkg_c7,
|
||||||
|
&group_cstate_pkg_c8,
|
||||||
|
&group_cstate_pkg_c9,
|
||||||
|
&group_cstate_pkg_c10,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static struct pmu cstate_core_pmu = {
|
static struct pmu cstate_core_pmu = {
|
||||||
.attr_groups = core_attr_groups,
|
.attr_groups = core_attr_groups,
|
||||||
|
.attr_update = core_attr_update,
|
||||||
.name = "cstate_core",
|
.name = "cstate_core",
|
||||||
.task_ctx_nr = perf_invalid_context,
|
.task_ctx_nr = perf_invalid_context,
|
||||||
.event_init = cstate_pmu_event_init,
|
.event_init = cstate_pmu_event_init,
|
||||||
|
@ -437,6 +482,7 @@ static struct pmu cstate_core_pmu = {
|
||||||
|
|
||||||
static struct pmu cstate_pkg_pmu = {
|
static struct pmu cstate_pkg_pmu = {
|
||||||
.attr_groups = pkg_attr_groups,
|
.attr_groups = pkg_attr_groups,
|
||||||
|
.attr_update = pkg_attr_update,
|
||||||
.name = "cstate_pkg",
|
.name = "cstate_pkg",
|
||||||
.task_ctx_nr = perf_invalid_context,
|
.task_ctx_nr = perf_invalid_context,
|
||||||
.event_init = cstate_pmu_event_init,
|
.event_init = cstate_pmu_event_init,
|
||||||
|
@ -580,35 +626,11 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
|
||||||
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates),
|
X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates),
|
||||||
|
|
||||||
X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_MOBILE, snb_cstates),
|
X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_MOBILE, snb_cstates),
|
||||||
|
X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_DESKTOP, snb_cstates),
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
|
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
|
||||||
|
|
||||||
/*
|
|
||||||
* Probe the cstate events and insert the available one into sysfs attrs
|
|
||||||
* Return false if there are no available events.
|
|
||||||
*/
|
|
||||||
static bool __init cstate_probe_msr(const unsigned long evmsk, int max,
|
|
||||||
struct perf_cstate_msr *msr,
|
|
||||||
struct attribute **attrs)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
unsigned int bit;
|
|
||||||
u64 val;
|
|
||||||
|
|
||||||
for (bit = 0; bit < max; bit++) {
|
|
||||||
if (test_bit(bit, &evmsk) && !rdmsrl_safe(msr[bit].msr, &val)) {
|
|
||||||
*attrs++ = &msr[bit].attr->attr.attr;
|
|
||||||
found = true;
|
|
||||||
} else {
|
|
||||||
msr[bit].attr = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*attrs = NULL;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init cstate_probe(const struct cstate_model *cm)
|
static int __init cstate_probe(const struct cstate_model *cm)
|
||||||
{
|
{
|
||||||
/* SLM has different MSR for PKG C6 */
|
/* SLM has different MSR for PKG C6 */
|
||||||
|
@ -620,13 +642,14 @@ static int __init cstate_probe(const struct cstate_model *cm)
|
||||||
pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY;
|
pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY;
|
||||||
|
|
||||||
|
|
||||||
has_cstate_core = cstate_probe_msr(cm->core_events,
|
core_msr_mask = perf_msr_probe(core_msr, PERF_CSTATE_CORE_EVENT_MAX,
|
||||||
PERF_CSTATE_CORE_EVENT_MAX,
|
true, (void *) &cm->core_events);
|
||||||
core_msr, core_events_attrs);
|
|
||||||
|
|
||||||
has_cstate_pkg = cstate_probe_msr(cm->pkg_events,
|
pkg_msr_mask = perf_msr_probe(pkg_msr, PERF_CSTATE_PKG_EVENT_MAX,
|
||||||
PERF_CSTATE_PKG_EVENT_MAX,
|
true, (void *) &cm->pkg_events);
|
||||||
pkg_msr, pkg_events_attrs);
|
|
||||||
|
has_cstate_core = !!core_msr_mask;
|
||||||
|
has_cstate_pkg = !!pkg_msr_mask;
|
||||||
|
|
||||||
return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
|
return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -663,7 +686,13 @@ static int __init cstate_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_cstate_pkg) {
|
if (has_cstate_pkg) {
|
||||||
err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1);
|
if (topology_max_die_per_package() > 1) {
|
||||||
|
err = perf_pmu_register(&cstate_pkg_pmu,
|
||||||
|
"cstate_die", -1);
|
||||||
|
} else {
|
||||||
|
err = perf_pmu_register(&cstate_pkg_pmu,
|
||||||
|
cstate_pkg_pmu.name, -1);
|
||||||
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
has_cstate_pkg = false;
|
has_cstate_pkg = false;
|
||||||
pr_info("Failed to register cstate pkg pmu\n");
|
pr_info("Failed to register cstate pkg pmu\n");
|
||||||
|
|
|
@ -55,27 +55,28 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <linux/nospec.h>
|
||||||
#include <asm/cpu_device_id.h>
|
#include <asm/cpu_device_id.h>
|
||||||
#include <asm/intel-family.h>
|
#include <asm/intel-family.h>
|
||||||
#include "../perf_event.h"
|
#include "../perf_event.h"
|
||||||
|
#include "../probe.h"
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAPL energy status counters
|
* RAPL energy status counters
|
||||||
*/
|
*/
|
||||||
#define RAPL_IDX_PP0_NRG_STAT 0 /* all cores */
|
enum perf_rapl_events {
|
||||||
#define INTEL_RAPL_PP0 0x1 /* pseudo-encoding */
|
PERF_RAPL_PP0 = 0, /* all cores */
|
||||||
#define RAPL_IDX_PKG_NRG_STAT 1 /* entire package */
|
PERF_RAPL_PKG, /* entire package */
|
||||||
#define INTEL_RAPL_PKG 0x2 /* pseudo-encoding */
|
PERF_RAPL_RAM, /* DRAM */
|
||||||
#define RAPL_IDX_RAM_NRG_STAT 2 /* DRAM */
|
PERF_RAPL_PP1, /* gpu */
|
||||||
#define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */
|
PERF_RAPL_PSYS, /* psys */
|
||||||
#define RAPL_IDX_PP1_NRG_STAT 3 /* gpu */
|
|
||||||
#define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */
|
PERF_RAPL_MAX,
|
||||||
#define RAPL_IDX_PSYS_NRG_STAT 4 /* psys */
|
NR_RAPL_DOMAINS = PERF_RAPL_MAX,
|
||||||
#define INTEL_RAPL_PSYS 0x5 /* pseudo-encoding */
|
};
|
||||||
|
|
||||||
#define NR_RAPL_DOMAINS 0x5
|
|
||||||
static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
|
static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
|
||||||
"pp0-core",
|
"pp0-core",
|
||||||
"package",
|
"package",
|
||||||
|
@ -84,33 +85,6 @@ static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
|
||||||
"psys",
|
"psys",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Clients have PP0, PKG */
|
|
||||||
#define RAPL_IDX_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PKG_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PP1_NRG_STAT)
|
|
||||||
|
|
||||||
/* Servers have PP0, PKG, RAM */
|
|
||||||
#define RAPL_IDX_SRV (1<<RAPL_IDX_PP0_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PKG_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_RAM_NRG_STAT)
|
|
||||||
|
|
||||||
/* Servers have PP0, PKG, RAM, PP1 */
|
|
||||||
#define RAPL_IDX_HSW (1<<RAPL_IDX_PP0_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PKG_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_RAM_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PP1_NRG_STAT)
|
|
||||||
|
|
||||||
/* SKL clients have PP0, PKG, RAM, PP1, PSYS */
|
|
||||||
#define RAPL_IDX_SKL_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PKG_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_RAM_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PP1_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_PSYS_NRG_STAT)
|
|
||||||
|
|
||||||
/* Knights Landing has PKG, RAM */
|
|
||||||
#define RAPL_IDX_KNL (1<<RAPL_IDX_PKG_NRG_STAT|\
|
|
||||||
1<<RAPL_IDX_RAM_NRG_STAT)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* event code: LSB 8 bits, passed in attr->config
|
* event code: LSB 8 bits, passed in attr->config
|
||||||
* any other bit is reserved
|
* any other bit is reserved
|
||||||
|
@ -149,26 +123,32 @@ struct rapl_pmu {
|
||||||
|
|
||||||
struct rapl_pmus {
|
struct rapl_pmus {
|
||||||
struct pmu pmu;
|
struct pmu pmu;
|
||||||
unsigned int maxpkg;
|
unsigned int maxdie;
|
||||||
struct rapl_pmu *pmus[];
|
struct rapl_pmu *pmus[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct rapl_model {
|
||||||
|
unsigned long events;
|
||||||
|
bool apply_quirk;
|
||||||
|
};
|
||||||
|
|
||||||
/* 1/2^hw_unit Joule */
|
/* 1/2^hw_unit Joule */
|
||||||
static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly;
|
static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly;
|
||||||
static struct rapl_pmus *rapl_pmus;
|
static struct rapl_pmus *rapl_pmus;
|
||||||
static cpumask_t rapl_cpu_mask;
|
static cpumask_t rapl_cpu_mask;
|
||||||
static unsigned int rapl_cntr_mask;
|
static unsigned int rapl_cntr_mask;
|
||||||
static u64 rapl_timer_ms;
|
static u64 rapl_timer_ms;
|
||||||
|
static struct perf_msr rapl_msrs[];
|
||||||
|
|
||||||
static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
|
static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
|
||||||
{
|
{
|
||||||
unsigned int pkgid = topology_logical_package_id(cpu);
|
unsigned int dieid = topology_logical_die_id(cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The unsigned check also catches the '-1' return value for non
|
* The unsigned check also catches the '-1' return value for non
|
||||||
* existent mappings in the topology map.
|
* existent mappings in the topology map.
|
||||||
*/
|
*/
|
||||||
return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL;
|
return dieid < rapl_pmus->maxdie ? rapl_pmus->pmus[dieid] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 rapl_read_counter(struct perf_event *event)
|
static inline u64 rapl_read_counter(struct perf_event *event)
|
||||||
|
@ -350,7 +330,7 @@ static void rapl_pmu_event_del(struct perf_event *event, int flags)
|
||||||
static int rapl_pmu_event_init(struct perf_event *event)
|
static int rapl_pmu_event_init(struct perf_event *event)
|
||||||
{
|
{
|
||||||
u64 cfg = event->attr.config & RAPL_EVENT_MASK;
|
u64 cfg = event->attr.config & RAPL_EVENT_MASK;
|
||||||
int bit, msr, ret = 0;
|
int bit, ret = 0;
|
||||||
struct rapl_pmu *pmu;
|
struct rapl_pmu *pmu;
|
||||||
|
|
||||||
/* only look at RAPL events */
|
/* only look at RAPL events */
|
||||||
|
@ -366,33 +346,12 @@ static int rapl_pmu_event_init(struct perf_event *event)
|
||||||
|
|
||||||
event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
|
event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
|
||||||
|
|
||||||
/*
|
if (!cfg || cfg >= NR_RAPL_DOMAINS + 1)
|
||||||
* check event is known (determines counter)
|
|
||||||
*/
|
|
||||||
switch (cfg) {
|
|
||||||
case INTEL_RAPL_PP0:
|
|
||||||
bit = RAPL_IDX_PP0_NRG_STAT;
|
|
||||||
msr = MSR_PP0_ENERGY_STATUS;
|
|
||||||
break;
|
|
||||||
case INTEL_RAPL_PKG:
|
|
||||||
bit = RAPL_IDX_PKG_NRG_STAT;
|
|
||||||
msr = MSR_PKG_ENERGY_STATUS;
|
|
||||||
break;
|
|
||||||
case INTEL_RAPL_RAM:
|
|
||||||
bit = RAPL_IDX_RAM_NRG_STAT;
|
|
||||||
msr = MSR_DRAM_ENERGY_STATUS;
|
|
||||||
break;
|
|
||||||
case INTEL_RAPL_PP1:
|
|
||||||
bit = RAPL_IDX_PP1_NRG_STAT;
|
|
||||||
msr = MSR_PP1_ENERGY_STATUS;
|
|
||||||
break;
|
|
||||||
case INTEL_RAPL_PSYS:
|
|
||||||
bit = RAPL_IDX_PSYS_NRG_STAT;
|
|
||||||
msr = MSR_PLATFORM_ENERGY_STATUS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
cfg = array_index_nospec((long)cfg, NR_RAPL_DOMAINS + 1);
|
||||||
|
bit = cfg - 1;
|
||||||
|
|
||||||
/* check event supported */
|
/* check event supported */
|
||||||
if (!(rapl_cntr_mask & (1 << bit)))
|
if (!(rapl_cntr_mask & (1 << bit)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -407,7 +366,7 @@ static int rapl_pmu_event_init(struct perf_event *event)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
event->cpu = pmu->cpu;
|
event->cpu = pmu->cpu;
|
||||||
event->pmu_private = pmu;
|
event->pmu_private = pmu;
|
||||||
event->hw.event_base = msr;
|
event->hw.event_base = rapl_msrs[bit].msr;
|
||||||
event->hw.config = cfg;
|
event->hw.config = cfg;
|
||||||
event->hw.idx = bit;
|
event->hw.idx = bit;
|
||||||
|
|
||||||
|
@ -457,90 +416,18 @@ RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890
|
||||||
RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10");
|
RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10");
|
||||||
RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10");
|
RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10");
|
||||||
|
|
||||||
static struct attribute *rapl_events_srv_attr[] = {
|
/*
|
||||||
EVENT_PTR(rapl_cores),
|
* There are no default events, but we need to create
|
||||||
EVENT_PTR(rapl_pkg),
|
* "events" group (with empty attrs) before updating
|
||||||
EVENT_PTR(rapl_ram),
|
* it with detected events.
|
||||||
|
*/
|
||||||
EVENT_PTR(rapl_cores_unit),
|
static struct attribute *attrs_empty[] = {
|
||||||
EVENT_PTR(rapl_pkg_unit),
|
|
||||||
EVENT_PTR(rapl_ram_unit),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_scale),
|
|
||||||
EVENT_PTR(rapl_pkg_scale),
|
|
||||||
EVENT_PTR(rapl_ram_scale),
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute *rapl_events_cln_attr[] = {
|
|
||||||
EVENT_PTR(rapl_cores),
|
|
||||||
EVENT_PTR(rapl_pkg),
|
|
||||||
EVENT_PTR(rapl_gpu),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_unit),
|
|
||||||
EVENT_PTR(rapl_pkg_unit),
|
|
||||||
EVENT_PTR(rapl_gpu_unit),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_scale),
|
|
||||||
EVENT_PTR(rapl_pkg_scale),
|
|
||||||
EVENT_PTR(rapl_gpu_scale),
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute *rapl_events_hsw_attr[] = {
|
|
||||||
EVENT_PTR(rapl_cores),
|
|
||||||
EVENT_PTR(rapl_pkg),
|
|
||||||
EVENT_PTR(rapl_gpu),
|
|
||||||
EVENT_PTR(rapl_ram),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_unit),
|
|
||||||
EVENT_PTR(rapl_pkg_unit),
|
|
||||||
EVENT_PTR(rapl_gpu_unit),
|
|
||||||
EVENT_PTR(rapl_ram_unit),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_scale),
|
|
||||||
EVENT_PTR(rapl_pkg_scale),
|
|
||||||
EVENT_PTR(rapl_gpu_scale),
|
|
||||||
EVENT_PTR(rapl_ram_scale),
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute *rapl_events_skl_attr[] = {
|
|
||||||
EVENT_PTR(rapl_cores),
|
|
||||||
EVENT_PTR(rapl_pkg),
|
|
||||||
EVENT_PTR(rapl_gpu),
|
|
||||||
EVENT_PTR(rapl_ram),
|
|
||||||
EVENT_PTR(rapl_psys),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_unit),
|
|
||||||
EVENT_PTR(rapl_pkg_unit),
|
|
||||||
EVENT_PTR(rapl_gpu_unit),
|
|
||||||
EVENT_PTR(rapl_ram_unit),
|
|
||||||
EVENT_PTR(rapl_psys_unit),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_cores_scale),
|
|
||||||
EVENT_PTR(rapl_pkg_scale),
|
|
||||||
EVENT_PTR(rapl_gpu_scale),
|
|
||||||
EVENT_PTR(rapl_ram_scale),
|
|
||||||
EVENT_PTR(rapl_psys_scale),
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute *rapl_events_knl_attr[] = {
|
|
||||||
EVENT_PTR(rapl_pkg),
|
|
||||||
EVENT_PTR(rapl_ram),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_pkg_unit),
|
|
||||||
EVENT_PTR(rapl_ram_unit),
|
|
||||||
|
|
||||||
EVENT_PTR(rapl_pkg_scale),
|
|
||||||
EVENT_PTR(rapl_ram_scale),
|
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group rapl_pmu_events_group = {
|
static struct attribute_group rapl_pmu_events_group = {
|
||||||
.name = "events",
|
.name = "events",
|
||||||
.attrs = NULL, /* patched at runtime */
|
.attrs = attrs_empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7");
|
DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7");
|
||||||
|
@ -561,6 +448,79 @@ static const struct attribute_group *rapl_attr_groups[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct attribute *rapl_events_cores[] = {
|
||||||
|
EVENT_PTR(rapl_cores),
|
||||||
|
EVENT_PTR(rapl_cores_unit),
|
||||||
|
EVENT_PTR(rapl_cores_scale),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group rapl_events_cores_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = rapl_events_cores,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *rapl_events_pkg[] = {
|
||||||
|
EVENT_PTR(rapl_pkg),
|
||||||
|
EVENT_PTR(rapl_pkg_unit),
|
||||||
|
EVENT_PTR(rapl_pkg_scale),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group rapl_events_pkg_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = rapl_events_pkg,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *rapl_events_ram[] = {
|
||||||
|
EVENT_PTR(rapl_ram),
|
||||||
|
EVENT_PTR(rapl_ram_unit),
|
||||||
|
EVENT_PTR(rapl_ram_scale),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group rapl_events_ram_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = rapl_events_ram,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *rapl_events_gpu[] = {
|
||||||
|
EVENT_PTR(rapl_gpu),
|
||||||
|
EVENT_PTR(rapl_gpu_unit),
|
||||||
|
EVENT_PTR(rapl_gpu_scale),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group rapl_events_gpu_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = rapl_events_gpu,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *rapl_events_psys[] = {
|
||||||
|
EVENT_PTR(rapl_psys),
|
||||||
|
EVENT_PTR(rapl_psys_unit),
|
||||||
|
EVENT_PTR(rapl_psys_scale),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group rapl_events_psys_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = rapl_events_psys,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool test_msr(int idx, void *data)
|
||||||
|
{
|
||||||
|
return test_bit(idx, (unsigned long *) data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_msr rapl_msrs[] = {
|
||||||
|
[PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr },
|
||||||
|
[PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr },
|
||||||
|
[PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr },
|
||||||
|
[PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr },
|
||||||
|
[PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr },
|
||||||
|
};
|
||||||
|
|
||||||
static int rapl_cpu_offline(unsigned int cpu)
|
static int rapl_cpu_offline(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
|
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
|
||||||
|
@ -572,7 +532,7 @@ static int rapl_cpu_offline(unsigned int cpu)
|
||||||
|
|
||||||
pmu->cpu = -1;
|
pmu->cpu = -1;
|
||||||
/* Find a new cpu to collect rapl events */
|
/* Find a new cpu to collect rapl events */
|
||||||
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
|
target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
|
||||||
|
|
||||||
/* Migrate rapl events to the new target */
|
/* Migrate rapl events to the new target */
|
||||||
if (target < nr_cpu_ids) {
|
if (target < nr_cpu_ids) {
|
||||||
|
@ -599,14 +559,14 @@ static int rapl_cpu_online(unsigned int cpu)
|
||||||
pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
|
pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
|
||||||
rapl_hrtimer_init(pmu);
|
rapl_hrtimer_init(pmu);
|
||||||
|
|
||||||
rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
|
rapl_pmus->pmus[topology_logical_die_id(cpu)] = pmu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if there is an online cpu in the package which collects rapl
|
* Check if there is an online cpu in the package which collects rapl
|
||||||
* events already.
|
* events already.
|
||||||
*/
|
*/
|
||||||
target = cpumask_any_and(&rapl_cpu_mask, topology_core_cpumask(cpu));
|
target = cpumask_any_and(&rapl_cpu_mask, topology_die_cpumask(cpu));
|
||||||
if (target < nr_cpu_ids)
|
if (target < nr_cpu_ids)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -633,7 +593,7 @@ static int rapl_check_hw_unit(bool apply_quirk)
|
||||||
* of 2. Datasheet, September 2014, Reference Number: 330784-001 "
|
* of 2. Datasheet, September 2014, Reference Number: 330784-001 "
|
||||||
*/
|
*/
|
||||||
if (apply_quirk)
|
if (apply_quirk)
|
||||||
rapl_hw_unit[RAPL_IDX_RAM_NRG_STAT] = 16;
|
rapl_hw_unit[PERF_RAPL_RAM] = 16;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the timer rate:
|
* Calculate the timer rate:
|
||||||
|
@ -669,23 +629,33 @@ static void cleanup_rapl_pmus(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < rapl_pmus->maxpkg; i++)
|
for (i = 0; i < rapl_pmus->maxdie; i++)
|
||||||
kfree(rapl_pmus->pmus[i]);
|
kfree(rapl_pmus->pmus[i]);
|
||||||
kfree(rapl_pmus);
|
kfree(rapl_pmus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct attribute_group *rapl_attr_update[] = {
|
||||||
|
&rapl_events_cores_group,
|
||||||
|
&rapl_events_pkg_group,
|
||||||
|
&rapl_events_ram_group,
|
||||||
|
&rapl_events_gpu_group,
|
||||||
|
&rapl_events_gpu_group,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init init_rapl_pmus(void)
|
static int __init init_rapl_pmus(void)
|
||||||
{
|
{
|
||||||
int maxpkg = topology_max_packages();
|
int maxdie = topology_max_packages() * topology_max_die_per_package();
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
size = sizeof(*rapl_pmus) + maxpkg * sizeof(struct rapl_pmu *);
|
size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *);
|
||||||
rapl_pmus = kzalloc(size, GFP_KERNEL);
|
rapl_pmus = kzalloc(size, GFP_KERNEL);
|
||||||
if (!rapl_pmus)
|
if (!rapl_pmus)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rapl_pmus->maxpkg = maxpkg;
|
rapl_pmus->maxdie = maxdie;
|
||||||
rapl_pmus->pmu.attr_groups = rapl_attr_groups;
|
rapl_pmus->pmu.attr_groups = rapl_attr_groups;
|
||||||
|
rapl_pmus->pmu.attr_update = rapl_attr_update;
|
||||||
rapl_pmus->pmu.task_ctx_nr = perf_invalid_context;
|
rapl_pmus->pmu.task_ctx_nr = perf_invalid_context;
|
||||||
rapl_pmus->pmu.event_init = rapl_pmu_event_init;
|
rapl_pmus->pmu.event_init = rapl_pmu_event_init;
|
||||||
rapl_pmus->pmu.add = rapl_pmu_event_add;
|
rapl_pmus->pmu.add = rapl_pmu_event_add;
|
||||||
|
@ -701,105 +671,96 @@ static int __init init_rapl_pmus(void)
|
||||||
#define X86_RAPL_MODEL_MATCH(model, init) \
|
#define X86_RAPL_MODEL_MATCH(model, init) \
|
||||||
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
|
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
|
||||||
|
|
||||||
struct intel_rapl_init_fun {
|
static struct rapl_model model_snb = {
|
||||||
bool apply_quirk;
|
.events = BIT(PERF_RAPL_PP0) |
|
||||||
int cntr_mask;
|
BIT(PERF_RAPL_PKG) |
|
||||||
struct attribute **attrs;
|
BIT(PERF_RAPL_PP1),
|
||||||
|
.apply_quirk = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun snb_rapl_init __initconst = {
|
static struct rapl_model model_snbep = {
|
||||||
.apply_quirk = false,
|
.events = BIT(PERF_RAPL_PP0) |
|
||||||
.cntr_mask = RAPL_IDX_CLN,
|
BIT(PERF_RAPL_PKG) |
|
||||||
.attrs = rapl_events_cln_attr,
|
BIT(PERF_RAPL_RAM),
|
||||||
|
.apply_quirk = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun hsx_rapl_init __initconst = {
|
static struct rapl_model model_hsw = {
|
||||||
.apply_quirk = true,
|
.events = BIT(PERF_RAPL_PP0) |
|
||||||
.cntr_mask = RAPL_IDX_SRV,
|
BIT(PERF_RAPL_PKG) |
|
||||||
.attrs = rapl_events_srv_attr,
|
BIT(PERF_RAPL_RAM) |
|
||||||
|
BIT(PERF_RAPL_PP1),
|
||||||
|
.apply_quirk = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun hsw_rapl_init __initconst = {
|
static struct rapl_model model_hsx = {
|
||||||
.apply_quirk = false,
|
.events = BIT(PERF_RAPL_PP0) |
|
||||||
.cntr_mask = RAPL_IDX_HSW,
|
BIT(PERF_RAPL_PKG) |
|
||||||
.attrs = rapl_events_hsw_attr,
|
BIT(PERF_RAPL_RAM),
|
||||||
|
.apply_quirk = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun snbep_rapl_init __initconst = {
|
static struct rapl_model model_knl = {
|
||||||
.apply_quirk = false,
|
.events = BIT(PERF_RAPL_PKG) |
|
||||||
.cntr_mask = RAPL_IDX_SRV,
|
BIT(PERF_RAPL_RAM),
|
||||||
.attrs = rapl_events_srv_attr,
|
.apply_quirk = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun knl_rapl_init __initconst = {
|
static struct rapl_model model_skl = {
|
||||||
.apply_quirk = true,
|
.events = BIT(PERF_RAPL_PP0) |
|
||||||
.cntr_mask = RAPL_IDX_KNL,
|
BIT(PERF_RAPL_PKG) |
|
||||||
.attrs = rapl_events_knl_attr,
|
BIT(PERF_RAPL_RAM) |
|
||||||
|
BIT(PERF_RAPL_PP1) |
|
||||||
|
BIT(PERF_RAPL_PSYS),
|
||||||
|
.apply_quirk = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_rapl_init_fun skl_rapl_init __initconst = {
|
static const struct x86_cpu_id rapl_model_match[] __initconst = {
|
||||||
.apply_quirk = false,
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE, model_snb),
|
||||||
.cntr_mask = RAPL_IDX_SKL_CLN,
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, model_snbep),
|
||||||
.attrs = rapl_events_skl_attr,
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, model_snb),
|
||||||
};
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, model_snbep),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, model_hsw),
|
||||||
static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X, model_hsx),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE, snb_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, model_hsw),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, snbep_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, model_hsw),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, model_hsw),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, snb_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, model_hsw),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, snbep_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, model_hsx),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, model_hsx),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, hsw_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, model_knl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X, hsx_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, model_knl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, hsw_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, model_skl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, hsw_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, model_skl),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, model_hsx),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, hsw_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, model_skl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, hsw_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, model_skl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsx_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_MOBILE, model_skl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsx_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, model_hsw),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_X, model_hsw),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, model_hsw),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_rapl_init),
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, model_skl),
|
||||||
|
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_DESKTOP, model_skl),
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_rapl_init),
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init),
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, hsx_rapl_init),
|
|
||||||
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, skl_rapl_init),
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_rapl_init),
|
|
||||||
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_MOBILE, skl_rapl_init),
|
|
||||||
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, hsw_rapl_init),
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_X, hsw_rapl_init),
|
|
||||||
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS, hsw_rapl_init),
|
|
||||||
|
|
||||||
X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, skl_rapl_init),
|
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(x86cpu, rapl_cpu_match);
|
MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
|
||||||
|
|
||||||
static int __init rapl_pmu_init(void)
|
static int __init rapl_pmu_init(void)
|
||||||
{
|
{
|
||||||
const struct x86_cpu_id *id;
|
const struct x86_cpu_id *id;
|
||||||
struct intel_rapl_init_fun *rapl_init;
|
struct rapl_model *rm;
|
||||||
bool apply_quirk;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
id = x86_match_cpu(rapl_cpu_match);
|
id = x86_match_cpu(rapl_model_match);
|
||||||
if (!id)
|
if (!id)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rapl_init = (struct intel_rapl_init_fun *)id->driver_data;
|
rm = (struct rapl_model *) id->driver_data;
|
||||||
apply_quirk = rapl_init->apply_quirk;
|
rapl_cntr_mask = perf_msr_probe(rapl_msrs, PERF_RAPL_MAX,
|
||||||
rapl_cntr_mask = rapl_init->cntr_mask;
|
false, (void *) &rm->events);
|
||||||
rapl_pmu_events_group.attrs = rapl_init->attrs;
|
|
||||||
|
|
||||||
ret = rapl_check_hw_unit(apply_quirk);
|
ret = rapl_check_hw_unit(rm->apply_quirk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
static struct intel_uncore_type *empty_uncore[] = { NULL, };
|
static struct intel_uncore_type *empty_uncore[] = { NULL, };
|
||||||
struct intel_uncore_type **uncore_msr_uncores = empty_uncore;
|
struct intel_uncore_type **uncore_msr_uncores = empty_uncore;
|
||||||
struct intel_uncore_type **uncore_pci_uncores = empty_uncore;
|
struct intel_uncore_type **uncore_pci_uncores = empty_uncore;
|
||||||
|
struct intel_uncore_type **uncore_mmio_uncores = empty_uncore;
|
||||||
|
|
||||||
static bool pcidrv_registered;
|
static bool pcidrv_registered;
|
||||||
struct pci_driver *uncore_pci_driver;
|
struct pci_driver *uncore_pci_driver;
|
||||||
|
@ -15,7 +16,7 @@ struct pci_driver *uncore_pci_driver;
|
||||||
DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
|
DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
|
||||||
struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
|
struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
|
||||||
struct pci_extra_dev *uncore_extra_pci_dev;
|
struct pci_extra_dev *uncore_extra_pci_dev;
|
||||||
static int max_packages;
|
static int max_dies;
|
||||||
|
|
||||||
/* mask of cpus that collect uncore events */
|
/* mask of cpus that collect uncore events */
|
||||||
static cpumask_t uncore_cpu_mask;
|
static cpumask_t uncore_cpu_mask;
|
||||||
|
@ -28,7 +29,7 @@ struct event_constraint uncore_constraint_empty =
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static int uncore_pcibus_to_physid(struct pci_bus *bus)
|
int uncore_pcibus_to_physid(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
struct pci2phy_map *map;
|
struct pci2phy_map *map;
|
||||||
int phys_id = -1;
|
int phys_id = -1;
|
||||||
|
@ -101,13 +102,13 @@ ssize_t uncore_event_show(struct kobject *kobj,
|
||||||
|
|
||||||
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
|
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
|
||||||
{
|
{
|
||||||
unsigned int pkgid = topology_logical_package_id(cpu);
|
unsigned int dieid = topology_logical_die_id(cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The unsigned check also catches the '-1' return value for non
|
* The unsigned check also catches the '-1' return value for non
|
||||||
* existent mappings in the topology map.
|
* existent mappings in the topology map.
|
||||||
*/
|
*/
|
||||||
return pkgid < max_packages ? pmu->boxes[pkgid] : NULL;
|
return dieid < max_dies ? pmu->boxes[dieid] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
|
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
|
||||||
|
@ -119,6 +120,21 @@ u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *eve
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uncore_mmio_exit_box(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
if (box->io_addr)
|
||||||
|
iounmap(box->io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 uncore_mmio_read_counter(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event)
|
||||||
|
{
|
||||||
|
if (!box->io_addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return readq(box->io_addr + event->hw.event_base);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic get constraint function for shared match/mask registers.
|
* generic get constraint function for shared match/mask registers.
|
||||||
*/
|
*/
|
||||||
|
@ -312,7 +328,7 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
|
||||||
uncore_pmu_init_hrtimer(box);
|
uncore_pmu_init_hrtimer(box);
|
||||||
box->cpu = -1;
|
box->cpu = -1;
|
||||||
box->pci_phys_id = -1;
|
box->pci_phys_id = -1;
|
||||||
box->pkgid = -1;
|
box->dieid = -1;
|
||||||
|
|
||||||
/* set default hrtimer timeout */
|
/* set default hrtimer timeout */
|
||||||
box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
|
box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
|
||||||
|
@ -827,10 +843,10 @@ static void uncore_pmu_unregister(struct intel_uncore_pmu *pmu)
|
||||||
|
|
||||||
static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
|
static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
|
||||||
{
|
{
|
||||||
int pkg;
|
int die;
|
||||||
|
|
||||||
for (pkg = 0; pkg < max_packages; pkg++)
|
for (die = 0; die < max_dies; die++)
|
||||||
kfree(pmu->boxes[pkg]);
|
kfree(pmu->boxes[die]);
|
||||||
kfree(pmu->boxes);
|
kfree(pmu->boxes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,7 +883,7 @@ static int __init uncore_type_init(struct intel_uncore_type *type, bool setid)
|
||||||
if (!pmus)
|
if (!pmus)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
size = max_packages * sizeof(struct intel_uncore_box *);
|
size = max_dies * sizeof(struct intel_uncore_box *);
|
||||||
|
|
||||||
for (i = 0; i < type->num_boxes; i++) {
|
for (i = 0; i < type->num_boxes; i++) {
|
||||||
pmus[i].func_id = setid ? i : -1;
|
pmus[i].func_id = setid ? i : -1;
|
||||||
|
@ -937,20 +953,21 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||||
struct intel_uncore_type *type;
|
struct intel_uncore_type *type;
|
||||||
struct intel_uncore_pmu *pmu = NULL;
|
struct intel_uncore_pmu *pmu = NULL;
|
||||||
struct intel_uncore_box *box;
|
struct intel_uncore_box *box;
|
||||||
int phys_id, pkg, ret;
|
int phys_id, die, ret;
|
||||||
|
|
||||||
phys_id = uncore_pcibus_to_physid(pdev->bus);
|
phys_id = uncore_pcibus_to_physid(pdev->bus);
|
||||||
if (phys_id < 0)
|
if (phys_id < 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
pkg = topology_phys_to_logical_pkg(phys_id);
|
die = (topology_max_die_per_package() > 1) ? phys_id :
|
||||||
if (pkg < 0)
|
topology_phys_to_logical_pkg(phys_id);
|
||||||
|
if (die < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
|
if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
|
||||||
int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
|
int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
|
||||||
|
|
||||||
uncore_extra_pci_dev[pkg].dev[idx] = pdev;
|
uncore_extra_pci_dev[die].dev[idx] = pdev;
|
||||||
pci_set_drvdata(pdev, NULL);
|
pci_set_drvdata(pdev, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -989,7 +1006,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||||
pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
|
pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WARN_ON_ONCE(pmu->boxes[pkg] != NULL))
|
if (WARN_ON_ONCE(pmu->boxes[die] != NULL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
box = uncore_alloc_box(type, NUMA_NO_NODE);
|
box = uncore_alloc_box(type, NUMA_NO_NODE);
|
||||||
|
@ -1003,13 +1020,13 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||||
|
|
||||||
atomic_inc(&box->refcnt);
|
atomic_inc(&box->refcnt);
|
||||||
box->pci_phys_id = phys_id;
|
box->pci_phys_id = phys_id;
|
||||||
box->pkgid = pkg;
|
box->dieid = die;
|
||||||
box->pci_dev = pdev;
|
box->pci_dev = pdev;
|
||||||
box->pmu = pmu;
|
box->pmu = pmu;
|
||||||
uncore_box_init(box);
|
uncore_box_init(box);
|
||||||
pci_set_drvdata(pdev, box);
|
pci_set_drvdata(pdev, box);
|
||||||
|
|
||||||
pmu->boxes[pkg] = box;
|
pmu->boxes[die] = box;
|
||||||
if (atomic_inc_return(&pmu->activeboxes) > 1)
|
if (atomic_inc_return(&pmu->activeboxes) > 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1017,7 +1034,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||||
ret = uncore_pmu_register(pmu);
|
ret = uncore_pmu_register(pmu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pci_set_drvdata(pdev, NULL);
|
pci_set_drvdata(pdev, NULL);
|
||||||
pmu->boxes[pkg] = NULL;
|
pmu->boxes[die] = NULL;
|
||||||
uncore_box_exit(box);
|
uncore_box_exit(box);
|
||||||
kfree(box);
|
kfree(box);
|
||||||
}
|
}
|
||||||
|
@ -1028,16 +1045,17 @@ static void uncore_pci_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct intel_uncore_box *box;
|
struct intel_uncore_box *box;
|
||||||
struct intel_uncore_pmu *pmu;
|
struct intel_uncore_pmu *pmu;
|
||||||
int i, phys_id, pkg;
|
int i, phys_id, die;
|
||||||
|
|
||||||
phys_id = uncore_pcibus_to_physid(pdev->bus);
|
phys_id = uncore_pcibus_to_physid(pdev->bus);
|
||||||
|
|
||||||
box = pci_get_drvdata(pdev);
|
box = pci_get_drvdata(pdev);
|
||||||
if (!box) {
|
if (!box) {
|
||||||
pkg = topology_phys_to_logical_pkg(phys_id);
|
die = (topology_max_die_per_package() > 1) ? phys_id :
|
||||||
|
topology_phys_to_logical_pkg(phys_id);
|
||||||
for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
|
for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
|
||||||
if (uncore_extra_pci_dev[pkg].dev[i] == pdev) {
|
if (uncore_extra_pci_dev[die].dev[i] == pdev) {
|
||||||
uncore_extra_pci_dev[pkg].dev[i] = NULL;
|
uncore_extra_pci_dev[die].dev[i] = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1050,7 +1068,7 @@ static void uncore_pci_remove(struct pci_dev *pdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_set_drvdata(pdev, NULL);
|
pci_set_drvdata(pdev, NULL);
|
||||||
pmu->boxes[box->pkgid] = NULL;
|
pmu->boxes[box->dieid] = NULL;
|
||||||
if (atomic_dec_return(&pmu->activeboxes) == 0)
|
if (atomic_dec_return(&pmu->activeboxes) == 0)
|
||||||
uncore_pmu_unregister(pmu);
|
uncore_pmu_unregister(pmu);
|
||||||
uncore_box_exit(box);
|
uncore_box_exit(box);
|
||||||
|
@ -1062,7 +1080,7 @@ static int __init uncore_pci_init(void)
|
||||||
size_t size;
|
size_t size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = max_packages * sizeof(struct pci_extra_dev);
|
size = max_dies * sizeof(struct pci_extra_dev);
|
||||||
uncore_extra_pci_dev = kzalloc(size, GFP_KERNEL);
|
uncore_extra_pci_dev = kzalloc(size, GFP_KERNEL);
|
||||||
if (!uncore_extra_pci_dev) {
|
if (!uncore_extra_pci_dev) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1109,11 +1127,11 @@ static void uncore_change_type_ctx(struct intel_uncore_type *type, int old_cpu,
|
||||||
{
|
{
|
||||||
struct intel_uncore_pmu *pmu = type->pmus;
|
struct intel_uncore_pmu *pmu = type->pmus;
|
||||||
struct intel_uncore_box *box;
|
struct intel_uncore_box *box;
|
||||||
int i, pkg;
|
int i, die;
|
||||||
|
|
||||||
pkg = topology_logical_package_id(old_cpu < 0 ? new_cpu : old_cpu);
|
die = topology_logical_die_id(old_cpu < 0 ? new_cpu : old_cpu);
|
||||||
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
||||||
box = pmu->boxes[pkg];
|
box = pmu->boxes[die];
|
||||||
if (!box)
|
if (!box)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1141,18 +1159,33 @@ static void uncore_change_context(struct intel_uncore_type **uncores,
|
||||||
uncore_change_type_ctx(*uncores, old_cpu, new_cpu);
|
uncore_change_type_ctx(*uncores, old_cpu, new_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uncore_event_cpu_offline(unsigned int cpu)
|
static void uncore_box_unref(struct intel_uncore_type **types, int id)
|
||||||
{
|
{
|
||||||
struct intel_uncore_type *type, **types = uncore_msr_uncores;
|
struct intel_uncore_type *type;
|
||||||
struct intel_uncore_pmu *pmu;
|
struct intel_uncore_pmu *pmu;
|
||||||
struct intel_uncore_box *box;
|
struct intel_uncore_box *box;
|
||||||
int i, pkg, target;
|
int i;
|
||||||
|
|
||||||
|
for (; *types; types++) {
|
||||||
|
type = *types;
|
||||||
|
pmu = type->pmus;
|
||||||
|
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
||||||
|
box = pmu->boxes[id];
|
||||||
|
if (box && atomic_dec_return(&box->refcnt) == 0)
|
||||||
|
uncore_box_exit(box);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uncore_event_cpu_offline(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int die, target;
|
||||||
|
|
||||||
/* Check if exiting cpu is used for collecting uncore events */
|
/* Check if exiting cpu is used for collecting uncore events */
|
||||||
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
|
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
|
||||||
goto unref;
|
goto unref;
|
||||||
/* Find a new cpu to collect uncore events */
|
/* Find a new cpu to collect uncore events */
|
||||||
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
|
target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
|
||||||
|
|
||||||
/* Migrate uncore events to the new target */
|
/* Migrate uncore events to the new target */
|
||||||
if (target < nr_cpu_ids)
|
if (target < nr_cpu_ids)
|
||||||
|
@ -1161,25 +1194,19 @@ static int uncore_event_cpu_offline(unsigned int cpu)
|
||||||
target = -1;
|
target = -1;
|
||||||
|
|
||||||
uncore_change_context(uncore_msr_uncores, cpu, target);
|
uncore_change_context(uncore_msr_uncores, cpu, target);
|
||||||
|
uncore_change_context(uncore_mmio_uncores, cpu, target);
|
||||||
uncore_change_context(uncore_pci_uncores, cpu, target);
|
uncore_change_context(uncore_pci_uncores, cpu, target);
|
||||||
|
|
||||||
unref:
|
unref:
|
||||||
/* Clear the references */
|
/* Clear the references */
|
||||||
pkg = topology_logical_package_id(cpu);
|
die = topology_logical_die_id(cpu);
|
||||||
for (; *types; types++) {
|
uncore_box_unref(uncore_msr_uncores, die);
|
||||||
type = *types;
|
uncore_box_unref(uncore_mmio_uncores, die);
|
||||||
pmu = type->pmus;
|
|
||||||
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
|
||||||
box = pmu->boxes[pkg];
|
|
||||||
if (box && atomic_dec_return(&box->refcnt) == 0)
|
|
||||||
uncore_box_exit(box);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int allocate_boxes(struct intel_uncore_type **types,
|
static int allocate_boxes(struct intel_uncore_type **types,
|
||||||
unsigned int pkg, unsigned int cpu)
|
unsigned int die, unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct intel_uncore_box *box, *tmp;
|
struct intel_uncore_box *box, *tmp;
|
||||||
struct intel_uncore_type *type;
|
struct intel_uncore_type *type;
|
||||||
|
@ -1192,20 +1219,20 @@ static int allocate_boxes(struct intel_uncore_type **types,
|
||||||
type = *types;
|
type = *types;
|
||||||
pmu = type->pmus;
|
pmu = type->pmus;
|
||||||
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
||||||
if (pmu->boxes[pkg])
|
if (pmu->boxes[die])
|
||||||
continue;
|
continue;
|
||||||
box = uncore_alloc_box(type, cpu_to_node(cpu));
|
box = uncore_alloc_box(type, cpu_to_node(cpu));
|
||||||
if (!box)
|
if (!box)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
box->pmu = pmu;
|
box->pmu = pmu;
|
||||||
box->pkgid = pkg;
|
box->dieid = die;
|
||||||
list_add(&box->active_list, &allocated);
|
list_add(&box->active_list, &allocated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Install them in the pmus */
|
/* Install them in the pmus */
|
||||||
list_for_each_entry_safe(box, tmp, &allocated, active_list) {
|
list_for_each_entry_safe(box, tmp, &allocated, active_list) {
|
||||||
list_del_init(&box->active_list);
|
list_del_init(&box->active_list);
|
||||||
box->pmu->boxes[pkg] = box;
|
box->pmu->boxes[die] = box;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1217,15 +1244,15 @@ static int allocate_boxes(struct intel_uncore_type **types,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uncore_event_cpu_online(unsigned int cpu)
|
static int uncore_box_ref(struct intel_uncore_type **types,
|
||||||
|
int id, unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct intel_uncore_type *type, **types = uncore_msr_uncores;
|
struct intel_uncore_type *type;
|
||||||
struct intel_uncore_pmu *pmu;
|
struct intel_uncore_pmu *pmu;
|
||||||
struct intel_uncore_box *box;
|
struct intel_uncore_box *box;
|
||||||
int i, ret, pkg, target;
|
int i, ret;
|
||||||
|
|
||||||
pkg = topology_logical_package_id(cpu);
|
ret = allocate_boxes(types, id, cpu);
|
||||||
ret = allocate_boxes(types, pkg, cpu);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1233,23 +1260,38 @@ static int uncore_event_cpu_online(unsigned int cpu)
|
||||||
type = *types;
|
type = *types;
|
||||||
pmu = type->pmus;
|
pmu = type->pmus;
|
||||||
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
for (i = 0; i < type->num_boxes; i++, pmu++) {
|
||||||
box = pmu->boxes[pkg];
|
box = pmu->boxes[id];
|
||||||
if (box && atomic_inc_return(&box->refcnt) == 1)
|
if (box && atomic_inc_return(&box->refcnt) == 1)
|
||||||
uncore_box_init(box);
|
uncore_box_init(box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uncore_event_cpu_online(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int die, target, msr_ret, mmio_ret;
|
||||||
|
|
||||||
|
die = topology_logical_die_id(cpu);
|
||||||
|
msr_ret = uncore_box_ref(uncore_msr_uncores, die, cpu);
|
||||||
|
mmio_ret = uncore_box_ref(uncore_mmio_uncores, die, cpu);
|
||||||
|
if (msr_ret && mmio_ret)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if there is an online cpu in the package
|
* Check if there is an online cpu in the package
|
||||||
* which collects uncore events already.
|
* which collects uncore events already.
|
||||||
*/
|
*/
|
||||||
target = cpumask_any_and(&uncore_cpu_mask, topology_core_cpumask(cpu));
|
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
|
||||||
if (target < nr_cpu_ids)
|
if (target < nr_cpu_ids)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cpumask_set_cpu(cpu, &uncore_cpu_mask);
|
cpumask_set_cpu(cpu, &uncore_cpu_mask);
|
||||||
|
|
||||||
uncore_change_context(uncore_msr_uncores, -1, cpu);
|
if (!msr_ret)
|
||||||
|
uncore_change_context(uncore_msr_uncores, -1, cpu);
|
||||||
|
if (!mmio_ret)
|
||||||
|
uncore_change_context(uncore_mmio_uncores, -1, cpu);
|
||||||
uncore_change_context(uncore_pci_uncores, -1, cpu);
|
uncore_change_context(uncore_pci_uncores, -1, cpu);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1297,12 +1339,35 @@ static int __init uncore_cpu_init(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __init uncore_mmio_init(void)
|
||||||
|
{
|
||||||
|
struct intel_uncore_type **types = uncore_mmio_uncores;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uncore_types_init(types, true);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
for (; *types; types++) {
|
||||||
|
ret = type_pmu_register(*types);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
uncore_types_exit(uncore_mmio_uncores);
|
||||||
|
uncore_mmio_uncores = empty_uncore;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define X86_UNCORE_MODEL_MATCH(model, init) \
|
#define X86_UNCORE_MODEL_MATCH(model, init) \
|
||||||
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
|
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
|
||||||
|
|
||||||
struct intel_uncore_init_fun {
|
struct intel_uncore_init_fun {
|
||||||
void (*cpu_init)(void);
|
void (*cpu_init)(void);
|
||||||
int (*pci_init)(void);
|
int (*pci_init)(void);
|
||||||
|
void (*mmio_init)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_uncore_init_fun nhm_uncore_init __initconst = {
|
static const struct intel_uncore_init_fun nhm_uncore_init __initconst = {
|
||||||
|
@ -1373,6 +1438,12 @@ static const struct intel_uncore_init_fun icl_uncore_init __initconst = {
|
||||||
.pci_init = skl_uncore_pci_init,
|
.pci_init = skl_uncore_pci_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct intel_uncore_init_fun snr_uncore_init __initconst = {
|
||||||
|
.cpu_init = snr_uncore_cpu_init,
|
||||||
|
.pci_init = snr_uncore_pci_init,
|
||||||
|
.mmio_init = snr_uncore_mmio_init,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP, nhm_uncore_init),
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP, nhm_uncore_init),
|
||||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM, nhm_uncore_init),
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM, nhm_uncore_init),
|
||||||
|
@ -1400,6 +1471,9 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, skl_uncore_init),
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_MOBILE, skl_uncore_init),
|
||||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_uncore_init),
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_DESKTOP, skl_uncore_init),
|
||||||
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, icl_uncore_init),
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_MOBILE, icl_uncore_init),
|
||||||
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_NNPI, icl_uncore_init),
|
||||||
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_DESKTOP, icl_uncore_init),
|
||||||
|
X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ATOM_TREMONT_X, snr_uncore_init),
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1409,7 +1483,7 @@ static int __init intel_uncore_init(void)
|
||||||
{
|
{
|
||||||
const struct x86_cpu_id *id;
|
const struct x86_cpu_id *id;
|
||||||
struct intel_uncore_init_fun *uncore_init;
|
struct intel_uncore_init_fun *uncore_init;
|
||||||
int pret = 0, cret = 0, ret;
|
int pret = 0, cret = 0, mret = 0, ret;
|
||||||
|
|
||||||
id = x86_match_cpu(intel_uncore_match);
|
id = x86_match_cpu(intel_uncore_match);
|
||||||
if (!id)
|
if (!id)
|
||||||
|
@ -1418,7 +1492,7 @@ static int __init intel_uncore_init(void)
|
||||||
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
max_packages = topology_max_packages();
|
max_dies = topology_max_packages() * topology_max_die_per_package();
|
||||||
|
|
||||||
uncore_init = (struct intel_uncore_init_fun *)id->driver_data;
|
uncore_init = (struct intel_uncore_init_fun *)id->driver_data;
|
||||||
if (uncore_init->pci_init) {
|
if (uncore_init->pci_init) {
|
||||||
|
@ -1432,7 +1506,12 @@ static int __init intel_uncore_init(void)
|
||||||
cret = uncore_cpu_init();
|
cret = uncore_cpu_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cret && pret)
|
if (uncore_init->mmio_init) {
|
||||||
|
uncore_init->mmio_init();
|
||||||
|
mret = uncore_mmio_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cret && pret && mret)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Install hotplug callbacks to setup the targets for each package */
|
/* Install hotplug callbacks to setup the targets for each package */
|
||||||
|
@ -1446,6 +1525,7 @@ static int __init intel_uncore_init(void)
|
||||||
|
|
||||||
err:
|
err:
|
||||||
uncore_types_exit(uncore_msr_uncores);
|
uncore_types_exit(uncore_msr_uncores);
|
||||||
|
uncore_types_exit(uncore_mmio_uncores);
|
||||||
uncore_pci_exit();
|
uncore_pci_exit();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1455,6 +1535,7 @@ static void __exit intel_uncore_exit(void)
|
||||||
{
|
{
|
||||||
cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
|
cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
|
||||||
uncore_types_exit(uncore_msr_uncores);
|
uncore_types_exit(uncore_msr_uncores);
|
||||||
|
uncore_types_exit(uncore_mmio_uncores);
|
||||||
uncore_pci_exit();
|
uncore_pci_exit();
|
||||||
}
|
}
|
||||||
module_exit(intel_uncore_exit);
|
module_exit(intel_uncore_exit);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <asm/apicdef.h>
|
#include <asm/apicdef.h>
|
||||||
|
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||||
|
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
#include "../perf_event.h"
|
#include "../perf_event.h"
|
||||||
|
@ -56,7 +57,10 @@ struct intel_uncore_type {
|
||||||
unsigned fixed_ctr;
|
unsigned fixed_ctr;
|
||||||
unsigned fixed_ctl;
|
unsigned fixed_ctl;
|
||||||
unsigned box_ctl;
|
unsigned box_ctl;
|
||||||
unsigned msr_offset;
|
union {
|
||||||
|
unsigned msr_offset;
|
||||||
|
unsigned mmio_offset;
|
||||||
|
};
|
||||||
unsigned num_shared_regs:8;
|
unsigned num_shared_regs:8;
|
||||||
unsigned single_fixed:1;
|
unsigned single_fixed:1;
|
||||||
unsigned pair_ctr_ctl:1;
|
unsigned pair_ctr_ctl:1;
|
||||||
|
@ -108,7 +112,7 @@ struct intel_uncore_extra_reg {
|
||||||
|
|
||||||
struct intel_uncore_box {
|
struct intel_uncore_box {
|
||||||
int pci_phys_id;
|
int pci_phys_id;
|
||||||
int pkgid; /* Logical package ID */
|
int dieid; /* Logical die ID */
|
||||||
int n_active; /* number of active events */
|
int n_active; /* number of active events */
|
||||||
int n_events;
|
int n_events;
|
||||||
int cpu; /* cpu to collect events */
|
int cpu; /* cpu to collect events */
|
||||||
|
@ -125,7 +129,7 @@ struct intel_uncore_box {
|
||||||
struct hrtimer hrtimer;
|
struct hrtimer hrtimer;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct list_head active_list;
|
struct list_head active_list;
|
||||||
void *io_addr;
|
void __iomem *io_addr;
|
||||||
struct intel_uncore_extra_reg shared_regs[0];
|
struct intel_uncore_extra_reg shared_regs[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,6 +163,7 @@ struct pci2phy_map {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pci2phy_map *__find_pci2phy_map(int segment);
|
struct pci2phy_map *__find_pci2phy_map(int segment);
|
||||||
|
int uncore_pcibus_to_physid(struct pci_bus *bus);
|
||||||
|
|
||||||
ssize_t uncore_event_show(struct kobject *kobj,
|
ssize_t uncore_event_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf);
|
struct kobj_attribute *attr, char *buf);
|
||||||
|
@ -190,6 +195,13 @@ static inline bool uncore_pmc_freerunning(int idx)
|
||||||
return idx == UNCORE_PMC_IDX_FREERUNNING;
|
return idx == UNCORE_PMC_IDX_FREERUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
unsigned int uncore_mmio_box_ctl(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
return box->pmu->type->box_ctl +
|
||||||
|
box->pmu->type->mmio_offset * box->pmu->pmu_idx;
|
||||||
|
}
|
||||||
|
|
||||||
static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
|
static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
|
||||||
{
|
{
|
||||||
return box->pmu->type->box_ctl;
|
return box->pmu->type->box_ctl;
|
||||||
|
@ -330,7 +342,7 @@ unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
|
||||||
static inline
|
static inline
|
||||||
unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
|
unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
|
||||||
{
|
{
|
||||||
if (box->pci_dev)
|
if (box->pci_dev || box->io_addr)
|
||||||
return uncore_pci_fixed_ctl(box);
|
return uncore_pci_fixed_ctl(box);
|
||||||
else
|
else
|
||||||
return uncore_msr_fixed_ctl(box);
|
return uncore_msr_fixed_ctl(box);
|
||||||
|
@ -339,7 +351,7 @@ unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
|
||||||
static inline
|
static inline
|
||||||
unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
|
unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
|
||||||
{
|
{
|
||||||
if (box->pci_dev)
|
if (box->pci_dev || box->io_addr)
|
||||||
return uncore_pci_fixed_ctr(box);
|
return uncore_pci_fixed_ctr(box);
|
||||||
else
|
else
|
||||||
return uncore_msr_fixed_ctr(box);
|
return uncore_msr_fixed_ctr(box);
|
||||||
|
@ -348,7 +360,7 @@ unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
|
||||||
static inline
|
static inline
|
||||||
unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
|
unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
|
||||||
{
|
{
|
||||||
if (box->pci_dev)
|
if (box->pci_dev || box->io_addr)
|
||||||
return uncore_pci_event_ctl(box, idx);
|
return uncore_pci_event_ctl(box, idx);
|
||||||
else
|
else
|
||||||
return uncore_msr_event_ctl(box, idx);
|
return uncore_msr_event_ctl(box, idx);
|
||||||
|
@ -357,7 +369,7 @@ unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
|
||||||
static inline
|
static inline
|
||||||
unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx)
|
unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx)
|
||||||
{
|
{
|
||||||
if (box->pci_dev)
|
if (box->pci_dev || box->io_addr)
|
||||||
return uncore_pci_perf_ctr(box, idx);
|
return uncore_pci_perf_ctr(box, idx);
|
||||||
else
|
else
|
||||||
return uncore_msr_perf_ctr(box, idx);
|
return uncore_msr_perf_ctr(box, idx);
|
||||||
|
@ -419,6 +431,16 @@ static inline bool is_freerunning_event(struct perf_event *event)
|
||||||
(((cfg >> 8) & 0xff) >= UNCORE_FREERUNNING_UMASK_START);
|
(((cfg >> 8) & 0xff) >= UNCORE_FREERUNNING_UMASK_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check and reject invalid config */
|
||||||
|
static inline int uncore_freerunning_hw_config(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event)
|
||||||
|
{
|
||||||
|
if (is_freerunning_event(event))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void uncore_disable_box(struct intel_uncore_box *box)
|
static inline void uncore_disable_box(struct intel_uncore_box *box)
|
||||||
{
|
{
|
||||||
if (box->pmu->type->ops->disable_box)
|
if (box->pmu->type->ops->disable_box)
|
||||||
|
@ -467,7 +489,7 @@ static inline void uncore_box_exit(struct intel_uncore_box *box)
|
||||||
|
|
||||||
static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
|
static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
|
||||||
{
|
{
|
||||||
return (box->pkgid < 0);
|
return (box->dieid < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
|
static inline struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
|
||||||
|
@ -482,6 +504,9 @@ static inline struct intel_uncore_box *uncore_event_to_box(struct perf_event *ev
|
||||||
|
|
||||||
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu);
|
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu);
|
||||||
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event);
|
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event);
|
||||||
|
void uncore_mmio_exit_box(struct intel_uncore_box *box);
|
||||||
|
u64 uncore_mmio_read_counter(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event);
|
||||||
void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
|
void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
|
||||||
void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
|
void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
|
||||||
void uncore_pmu_event_start(struct perf_event *event, int flags);
|
void uncore_pmu_event_start(struct perf_event *event, int flags);
|
||||||
|
@ -497,6 +522,7 @@ u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx);
|
||||||
|
|
||||||
extern struct intel_uncore_type **uncore_msr_uncores;
|
extern struct intel_uncore_type **uncore_msr_uncores;
|
||||||
extern struct intel_uncore_type **uncore_pci_uncores;
|
extern struct intel_uncore_type **uncore_pci_uncores;
|
||||||
|
extern struct intel_uncore_type **uncore_mmio_uncores;
|
||||||
extern struct pci_driver *uncore_pci_driver;
|
extern struct pci_driver *uncore_pci_driver;
|
||||||
extern raw_spinlock_t pci2phy_map_lock;
|
extern raw_spinlock_t pci2phy_map_lock;
|
||||||
extern struct list_head pci2phy_map_head;
|
extern struct list_head pci2phy_map_head;
|
||||||
|
@ -528,6 +554,9 @@ int knl_uncore_pci_init(void);
|
||||||
void knl_uncore_cpu_init(void);
|
void knl_uncore_cpu_init(void);
|
||||||
int skx_uncore_pci_init(void);
|
int skx_uncore_pci_init(void);
|
||||||
void skx_uncore_cpu_init(void);
|
void skx_uncore_cpu_init(void);
|
||||||
|
int snr_uncore_pci_init(void);
|
||||||
|
void snr_uncore_cpu_init(void);
|
||||||
|
void snr_uncore_mmio_init(void);
|
||||||
|
|
||||||
/* uncore_nhmex.c */
|
/* uncore_nhmex.c */
|
||||||
void nhmex_uncore_cpu_init(void);
|
void nhmex_uncore_cpu_init(void);
|
||||||
|
|
|
@ -3,27 +3,29 @@
|
||||||
#include "uncore.h"
|
#include "uncore.h"
|
||||||
|
|
||||||
/* Uncore IMC PCI IDs */
|
/* Uncore IMC PCI IDs */
|
||||||
#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100
|
#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100
|
||||||
#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154
|
#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154
|
||||||
#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
|
#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
|
||||||
#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00
|
#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00
|
||||||
#define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04
|
#define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04
|
||||||
#define PCI_DEVICE_ID_INTEL_BDW_IMC 0x1604
|
#define PCI_DEVICE_ID_INTEL_BDW_IMC 0x1604
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_U_IMC 0x1904
|
#define PCI_DEVICE_ID_INTEL_SKL_U_IMC 0x1904
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_Y_IMC 0x190c
|
#define PCI_DEVICE_ID_INTEL_SKL_Y_IMC 0x190c
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_HD_IMC 0x1900
|
#define PCI_DEVICE_ID_INTEL_SKL_HD_IMC 0x1900
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_HQ_IMC 0x1910
|
#define PCI_DEVICE_ID_INTEL_SKL_HQ_IMC 0x1910
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_SD_IMC 0x190f
|
#define PCI_DEVICE_ID_INTEL_SKL_SD_IMC 0x190f
|
||||||
#define PCI_DEVICE_ID_INTEL_SKL_SQ_IMC 0x191f
|
#define PCI_DEVICE_ID_INTEL_SKL_SQ_IMC 0x191f
|
||||||
#define PCI_DEVICE_ID_INTEL_KBL_Y_IMC 0x590c
|
#define PCI_DEVICE_ID_INTEL_KBL_Y_IMC 0x590c
|
||||||
#define PCI_DEVICE_ID_INTEL_KBL_U_IMC 0x5904
|
#define PCI_DEVICE_ID_INTEL_KBL_U_IMC 0x5904
|
||||||
#define PCI_DEVICE_ID_INTEL_KBL_UQ_IMC 0x5914
|
#define PCI_DEVICE_ID_INTEL_KBL_UQ_IMC 0x5914
|
||||||
#define PCI_DEVICE_ID_INTEL_KBL_SD_IMC 0x590f
|
#define PCI_DEVICE_ID_INTEL_KBL_SD_IMC 0x590f
|
||||||
#define PCI_DEVICE_ID_INTEL_KBL_SQ_IMC 0x591f
|
#define PCI_DEVICE_ID_INTEL_KBL_SQ_IMC 0x591f
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_2U_IMC 0x3ecc
|
#define PCI_DEVICE_ID_INTEL_KBL_HQ_IMC 0x5910
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_4U_IMC 0x3ed0
|
#define PCI_DEVICE_ID_INTEL_KBL_WQ_IMC 0x5918
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_4H_IMC 0x3e10
|
#define PCI_DEVICE_ID_INTEL_CFL_2U_IMC 0x3ecc
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_6H_IMC 0x3ec4
|
#define PCI_DEVICE_ID_INTEL_CFL_4U_IMC 0x3ed0
|
||||||
|
#define PCI_DEVICE_ID_INTEL_CFL_4H_IMC 0x3e10
|
||||||
|
#define PCI_DEVICE_ID_INTEL_CFL_6H_IMC 0x3ec4
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_2S_D_IMC 0x3e0f
|
#define PCI_DEVICE_ID_INTEL_CFL_2S_D_IMC 0x3e0f
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_4S_D_IMC 0x3e1f
|
#define PCI_DEVICE_ID_INTEL_CFL_4S_D_IMC 0x3e1f
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_6S_D_IMC 0x3ec2
|
#define PCI_DEVICE_ID_INTEL_CFL_6S_D_IMC 0x3ec2
|
||||||
|
@ -34,9 +36,15 @@
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_4S_S_IMC 0x3e33
|
#define PCI_DEVICE_ID_INTEL_CFL_4S_S_IMC 0x3e33
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_6S_S_IMC 0x3eca
|
#define PCI_DEVICE_ID_INTEL_CFL_6S_S_IMC 0x3eca
|
||||||
#define PCI_DEVICE_ID_INTEL_CFL_8S_S_IMC 0x3e32
|
#define PCI_DEVICE_ID_INTEL_CFL_8S_S_IMC 0x3e32
|
||||||
|
#define PCI_DEVICE_ID_INTEL_AML_YD_IMC 0x590c
|
||||||
|
#define PCI_DEVICE_ID_INTEL_AML_YQ_IMC 0x590d
|
||||||
|
#define PCI_DEVICE_ID_INTEL_WHL_UQ_IMC 0x3ed0
|
||||||
|
#define PCI_DEVICE_ID_INTEL_WHL_4_UQ_IMC 0x3e34
|
||||||
|
#define PCI_DEVICE_ID_INTEL_WHL_UD_IMC 0x3e35
|
||||||
#define PCI_DEVICE_ID_INTEL_ICL_U_IMC 0x8a02
|
#define PCI_DEVICE_ID_INTEL_ICL_U_IMC 0x8a02
|
||||||
#define PCI_DEVICE_ID_INTEL_ICL_U2_IMC 0x8a12
|
#define PCI_DEVICE_ID_INTEL_ICL_U2_IMC 0x8a12
|
||||||
|
|
||||||
|
|
||||||
/* SNB event control */
|
/* SNB event control */
|
||||||
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
|
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
|
||||||
#define SNB_UNC_CTL_UMASK_MASK 0x0000ff00
|
#define SNB_UNC_CTL_UMASK_MASK 0x0000ff00
|
||||||
|
@ -420,11 +428,6 @@ static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
|
||||||
box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
|
box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snb_uncore_imc_exit_box(struct intel_uncore_box *box)
|
|
||||||
{
|
|
||||||
iounmap(box->io_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
|
static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -437,13 +440,6 @@ static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct per
|
||||||
static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
|
static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
|
|
||||||
{
|
|
||||||
struct hw_perf_event *hwc = &event->hw;
|
|
||||||
|
|
||||||
return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep the custom event_init() function compatible with old event
|
* Keep the custom event_init() function compatible with old event
|
||||||
* encoding for free running counters.
|
* encoding for free running counters.
|
||||||
|
@ -570,13 +566,13 @@ static struct pmu snb_uncore_imc_pmu = {
|
||||||
|
|
||||||
static struct intel_uncore_ops snb_uncore_imc_ops = {
|
static struct intel_uncore_ops snb_uncore_imc_ops = {
|
||||||
.init_box = snb_uncore_imc_init_box,
|
.init_box = snb_uncore_imc_init_box,
|
||||||
.exit_box = snb_uncore_imc_exit_box,
|
.exit_box = uncore_mmio_exit_box,
|
||||||
.enable_box = snb_uncore_imc_enable_box,
|
.enable_box = snb_uncore_imc_enable_box,
|
||||||
.disable_box = snb_uncore_imc_disable_box,
|
.disable_box = snb_uncore_imc_disable_box,
|
||||||
.disable_event = snb_uncore_imc_disable_event,
|
.disable_event = snb_uncore_imc_disable_event,
|
||||||
.enable_event = snb_uncore_imc_enable_event,
|
.enable_event = snb_uncore_imc_enable_event,
|
||||||
.hw_config = snb_uncore_imc_hw_config,
|
.hw_config = snb_uncore_imc_hw_config,
|
||||||
.read_counter = snb_uncore_imc_read_counter,
|
.read_counter = uncore_mmio_read_counter,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct intel_uncore_type snb_uncore_imc = {
|
static struct intel_uncore_type snb_uncore_imc = {
|
||||||
|
@ -681,6 +677,14 @@ static const struct pci_device_id skl_uncore_pci_ids[] = {
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBL_SQ_IMC),
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBL_SQ_IMC),
|
||||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
},
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBL_HQ_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBL_WQ_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
{ /* IMC */
|
{ /* IMC */
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CFL_2U_IMC),
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CFL_2U_IMC),
|
||||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
@ -737,6 +741,26 @@ static const struct pci_device_id skl_uncore_pci_ids[] = {
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CFL_8S_S_IMC),
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CFL_8S_S_IMC),
|
||||||
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
},
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AML_YD_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AML_YQ_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WHL_UQ_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WHL_4_UQ_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
|
{ /* IMC */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WHL_UD_IMC),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
|
||||||
|
},
|
||||||
{ /* end: all zeroes */ },
|
{ /* end: all zeroes */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -807,6 +831,8 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
|
||||||
IMC_DEV(KBL_UQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core U Quad Core */
|
IMC_DEV(KBL_UQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core U Quad Core */
|
||||||
IMC_DEV(KBL_SD_IMC, &skl_uncore_pci_driver), /* 7th Gen Core S Dual Core */
|
IMC_DEV(KBL_SD_IMC, &skl_uncore_pci_driver), /* 7th Gen Core S Dual Core */
|
||||||
IMC_DEV(KBL_SQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core S Quad Core */
|
IMC_DEV(KBL_SQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core S Quad Core */
|
||||||
|
IMC_DEV(KBL_HQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core H Quad Core */
|
||||||
|
IMC_DEV(KBL_WQ_IMC, &skl_uncore_pci_driver), /* 7th Gen Core S 4 cores Work Station */
|
||||||
IMC_DEV(CFL_2U_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U 2 Cores */
|
IMC_DEV(CFL_2U_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U 2 Cores */
|
||||||
IMC_DEV(CFL_4U_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U 4 Cores */
|
IMC_DEV(CFL_4U_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U 4 Cores */
|
||||||
IMC_DEV(CFL_4H_IMC, &skl_uncore_pci_driver), /* 8th Gen Core H 4 Cores */
|
IMC_DEV(CFL_4H_IMC, &skl_uncore_pci_driver), /* 8th Gen Core H 4 Cores */
|
||||||
|
@ -821,6 +847,11 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
|
||||||
IMC_DEV(CFL_4S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 4 Cores Server */
|
IMC_DEV(CFL_4S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 4 Cores Server */
|
||||||
IMC_DEV(CFL_6S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 6 Cores Server */
|
IMC_DEV(CFL_6S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 6 Cores Server */
|
||||||
IMC_DEV(CFL_8S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 8 Cores Server */
|
IMC_DEV(CFL_8S_S_IMC, &skl_uncore_pci_driver), /* 8th Gen Core S 8 Cores Server */
|
||||||
|
IMC_DEV(AML_YD_IMC, &skl_uncore_pci_driver), /* 8th Gen Core Y Mobile Dual Core */
|
||||||
|
IMC_DEV(AML_YQ_IMC, &skl_uncore_pci_driver), /* 8th Gen Core Y Mobile Quad Core */
|
||||||
|
IMC_DEV(WHL_UQ_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U Mobile Quad Core */
|
||||||
|
IMC_DEV(WHL_4_UQ_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U Mobile Quad Core */
|
||||||
|
IMC_DEV(WHL_UD_IMC, &skl_uncore_pci_driver), /* 8th Gen Core U Mobile Dual Core */
|
||||||
IMC_DEV(ICL_U_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
|
IMC_DEV(ICL_U_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
|
||||||
IMC_DEV(ICL_U2_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
|
IMC_DEV(ICL_U2_IMC, &icl_uncore_pci_driver), /* 10th Gen Core Mobile */
|
||||||
{ /* end marker */ }
|
{ /* end marker */ }
|
||||||
|
|
|
@ -324,12 +324,77 @@
|
||||||
#define SKX_M2M_PCI_PMON_CTR0 0x200
|
#define SKX_M2M_PCI_PMON_CTR0 0x200
|
||||||
#define SKX_M2M_PCI_PMON_BOX_CTL 0x258
|
#define SKX_M2M_PCI_PMON_BOX_CTL 0x258
|
||||||
|
|
||||||
|
/* SNR Ubox */
|
||||||
|
#define SNR_U_MSR_PMON_CTR0 0x1f98
|
||||||
|
#define SNR_U_MSR_PMON_CTL0 0x1f91
|
||||||
|
#define SNR_U_MSR_PMON_UCLK_FIXED_CTL 0x1f93
|
||||||
|
#define SNR_U_MSR_PMON_UCLK_FIXED_CTR 0x1f94
|
||||||
|
|
||||||
|
/* SNR CHA */
|
||||||
|
#define SNR_CHA_RAW_EVENT_MASK_EXT 0x3ffffff
|
||||||
|
#define SNR_CHA_MSR_PMON_CTL0 0x1c01
|
||||||
|
#define SNR_CHA_MSR_PMON_CTR0 0x1c08
|
||||||
|
#define SNR_CHA_MSR_PMON_BOX_CTL 0x1c00
|
||||||
|
#define SNR_C0_MSR_PMON_BOX_FILTER0 0x1c05
|
||||||
|
|
||||||
|
|
||||||
|
/* SNR IIO */
|
||||||
|
#define SNR_IIO_MSR_PMON_CTL0 0x1e08
|
||||||
|
#define SNR_IIO_MSR_PMON_CTR0 0x1e01
|
||||||
|
#define SNR_IIO_MSR_PMON_BOX_CTL 0x1e00
|
||||||
|
#define SNR_IIO_MSR_OFFSET 0x10
|
||||||
|
#define SNR_IIO_PMON_RAW_EVENT_MASK_EXT 0x7ffff
|
||||||
|
|
||||||
|
/* SNR IRP */
|
||||||
|
#define SNR_IRP0_MSR_PMON_CTL0 0x1ea8
|
||||||
|
#define SNR_IRP0_MSR_PMON_CTR0 0x1ea1
|
||||||
|
#define SNR_IRP0_MSR_PMON_BOX_CTL 0x1ea0
|
||||||
|
#define SNR_IRP_MSR_OFFSET 0x10
|
||||||
|
|
||||||
|
/* SNR M2PCIE */
|
||||||
|
#define SNR_M2PCIE_MSR_PMON_CTL0 0x1e58
|
||||||
|
#define SNR_M2PCIE_MSR_PMON_CTR0 0x1e51
|
||||||
|
#define SNR_M2PCIE_MSR_PMON_BOX_CTL 0x1e50
|
||||||
|
#define SNR_M2PCIE_MSR_OFFSET 0x10
|
||||||
|
|
||||||
|
/* SNR PCU */
|
||||||
|
#define SNR_PCU_MSR_PMON_CTL0 0x1ef1
|
||||||
|
#define SNR_PCU_MSR_PMON_CTR0 0x1ef8
|
||||||
|
#define SNR_PCU_MSR_PMON_BOX_CTL 0x1ef0
|
||||||
|
#define SNR_PCU_MSR_PMON_BOX_FILTER 0x1efc
|
||||||
|
|
||||||
|
/* SNR M2M */
|
||||||
|
#define SNR_M2M_PCI_PMON_CTL0 0x468
|
||||||
|
#define SNR_M2M_PCI_PMON_CTR0 0x440
|
||||||
|
#define SNR_M2M_PCI_PMON_BOX_CTL 0x438
|
||||||
|
#define SNR_M2M_PCI_PMON_UMASK_EXT 0xff
|
||||||
|
|
||||||
|
/* SNR PCIE3 */
|
||||||
|
#define SNR_PCIE3_PCI_PMON_CTL0 0x508
|
||||||
|
#define SNR_PCIE3_PCI_PMON_CTR0 0x4e8
|
||||||
|
#define SNR_PCIE3_PCI_PMON_BOX_CTL 0x4e4
|
||||||
|
|
||||||
|
/* SNR IMC */
|
||||||
|
#define SNR_IMC_MMIO_PMON_FIXED_CTL 0x54
|
||||||
|
#define SNR_IMC_MMIO_PMON_FIXED_CTR 0x38
|
||||||
|
#define SNR_IMC_MMIO_PMON_CTL0 0x40
|
||||||
|
#define SNR_IMC_MMIO_PMON_CTR0 0x8
|
||||||
|
#define SNR_IMC_MMIO_PMON_BOX_CTL 0x22800
|
||||||
|
#define SNR_IMC_MMIO_OFFSET 0x4000
|
||||||
|
#define SNR_IMC_MMIO_SIZE 0x4000
|
||||||
|
#define SNR_IMC_MMIO_BASE_OFFSET 0xd0
|
||||||
|
#define SNR_IMC_MMIO_BASE_MASK 0x1FFFFFFF
|
||||||
|
#define SNR_IMC_MMIO_MEM0_OFFSET 0xd8
|
||||||
|
#define SNR_IMC_MMIO_MEM0_MASK 0x7FF
|
||||||
|
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
|
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
|
DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
|
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
|
DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
|
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-43,45-55");
|
DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-43,45-55");
|
||||||
|
DEFINE_UNCORE_FORMAT_ATTR(umask_ext2, umask, "config:8-15,32-57");
|
||||||
|
DEFINE_UNCORE_FORMAT_ATTR(umask_ext3, umask, "config:8-15,32-39");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
|
DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
|
DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
|
DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
|
||||||
|
@ -343,11 +408,14 @@ DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
|
DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
|
DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(ch_mask, ch_mask, "config:36-43");
|
DEFINE_UNCORE_FORMAT_ATTR(ch_mask, ch_mask, "config:36-43");
|
||||||
|
DEFINE_UNCORE_FORMAT_ATTR(ch_mask2, ch_mask, "config:36-47");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(fc_mask, fc_mask, "config:44-46");
|
DEFINE_UNCORE_FORMAT_ATTR(fc_mask, fc_mask, "config:44-46");
|
||||||
|
DEFINE_UNCORE_FORMAT_ATTR(fc_mask2, fc_mask, "config:48-50");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_tid4, filter_tid, "config1:0-8");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_tid4, filter_tid, "config1:0-8");
|
||||||
|
DEFINE_UNCORE_FORMAT_ATTR(filter_tid5, filter_tid, "config1:0-9");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
|
||||||
DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
|
DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
|
||||||
|
@ -1058,8 +1126,8 @@ static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_eve
|
||||||
|
|
||||||
if (reg1->idx != EXTRA_REG_NONE) {
|
if (reg1->idx != EXTRA_REG_NONE) {
|
||||||
int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
|
int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
|
||||||
int pkg = box->pkgid;
|
int die = box->dieid;
|
||||||
struct pci_dev *filter_pdev = uncore_extra_pci_dev[pkg].dev[idx];
|
struct pci_dev *filter_pdev = uncore_extra_pci_dev[die].dev[idx];
|
||||||
|
|
||||||
if (filter_pdev) {
|
if (filter_pdev) {
|
||||||
pci_write_config_dword(filter_pdev, reg1->reg,
|
pci_write_config_dword(filter_pdev, reg1->reg,
|
||||||
|
@ -3585,6 +3653,7 @@ static struct uncore_event_desc skx_uncore_iio_freerunning_events[] = {
|
||||||
|
|
||||||
static struct intel_uncore_ops skx_uncore_iio_freerunning_ops = {
|
static struct intel_uncore_ops skx_uncore_iio_freerunning_ops = {
|
||||||
.read_counter = uncore_msr_read_counter,
|
.read_counter = uncore_msr_read_counter,
|
||||||
|
.hw_config = uncore_freerunning_hw_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute *skx_uncore_iio_freerunning_formats_attr[] = {
|
static struct attribute *skx_uncore_iio_freerunning_formats_attr[] = {
|
||||||
|
@ -3967,3 +4036,535 @@ int skx_uncore_pci_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of SKX uncore support */
|
/* end of SKX uncore support */
|
||||||
|
|
||||||
|
/* SNR uncore support */
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_ubox = {
|
||||||
|
.name = "ubox",
|
||||||
|
.num_counters = 2,
|
||||||
|
.num_boxes = 1,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.fixed_ctr_bits = 48,
|
||||||
|
.perf_ctr = SNR_U_MSR_PMON_CTR0,
|
||||||
|
.event_ctl = SNR_U_MSR_PMON_CTL0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.fixed_ctr = SNR_U_MSR_PMON_UCLK_FIXED_CTR,
|
||||||
|
.fixed_ctl = SNR_U_MSR_PMON_UCLK_FIXED_CTL,
|
||||||
|
.ops = &ivbep_uncore_msr_ops,
|
||||||
|
.format_group = &ivbep_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *snr_uncore_cha_formats_attr[] = {
|
||||||
|
&format_attr_event.attr,
|
||||||
|
&format_attr_umask_ext2.attr,
|
||||||
|
&format_attr_edge.attr,
|
||||||
|
&format_attr_tid_en.attr,
|
||||||
|
&format_attr_inv.attr,
|
||||||
|
&format_attr_thresh8.attr,
|
||||||
|
&format_attr_filter_tid5.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
static const struct attribute_group snr_uncore_chabox_format_group = {
|
||||||
|
.name = "format",
|
||||||
|
.attrs = snr_uncore_cha_formats_attr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int snr_cha_hw_config(struct intel_uncore_box *box, struct perf_event *event)
|
||||||
|
{
|
||||||
|
struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
|
||||||
|
|
||||||
|
reg1->reg = SNR_C0_MSR_PMON_BOX_FILTER0 +
|
||||||
|
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||||
|
reg1->config = event->attr.config1 & SKX_CHA_MSR_PMON_BOX_FILTER_TID;
|
||||||
|
reg1->idx = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_cha_enable_event(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event)
|
||||||
|
{
|
||||||
|
struct hw_perf_event *hwc = &event->hw;
|
||||||
|
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||||
|
|
||||||
|
if (reg1->idx != EXTRA_REG_NONE)
|
||||||
|
wrmsrl(reg1->reg, reg1->config);
|
||||||
|
|
||||||
|
wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_uncore_ops snr_uncore_chabox_ops = {
|
||||||
|
.init_box = ivbep_uncore_msr_init_box,
|
||||||
|
.disable_box = snbep_uncore_msr_disable_box,
|
||||||
|
.enable_box = snbep_uncore_msr_enable_box,
|
||||||
|
.disable_event = snbep_uncore_msr_disable_event,
|
||||||
|
.enable_event = snr_cha_enable_event,
|
||||||
|
.read_counter = uncore_msr_read_counter,
|
||||||
|
.hw_config = snr_cha_hw_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_chabox = {
|
||||||
|
.name = "cha",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 6,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.event_ctl = SNR_CHA_MSR_PMON_CTL0,
|
||||||
|
.perf_ctr = SNR_CHA_MSR_PMON_CTR0,
|
||||||
|
.box_ctl = SNR_CHA_MSR_PMON_BOX_CTL,
|
||||||
|
.msr_offset = HSWEP_CBO_MSR_OFFSET,
|
||||||
|
.event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
|
||||||
|
.event_mask_ext = SNR_CHA_RAW_EVENT_MASK_EXT,
|
||||||
|
.ops = &snr_uncore_chabox_ops,
|
||||||
|
.format_group = &snr_uncore_chabox_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *snr_uncore_iio_formats_attr[] = {
|
||||||
|
&format_attr_event.attr,
|
||||||
|
&format_attr_umask.attr,
|
||||||
|
&format_attr_edge.attr,
|
||||||
|
&format_attr_inv.attr,
|
||||||
|
&format_attr_thresh9.attr,
|
||||||
|
&format_attr_ch_mask2.attr,
|
||||||
|
&format_attr_fc_mask2.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group snr_uncore_iio_format_group = {
|
||||||
|
.name = "format",
|
||||||
|
.attrs = snr_uncore_iio_formats_attr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_iio = {
|
||||||
|
.name = "iio",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 5,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.event_ctl = SNR_IIO_MSR_PMON_CTL0,
|
||||||
|
.perf_ctr = SNR_IIO_MSR_PMON_CTR0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.event_mask_ext = SNR_IIO_PMON_RAW_EVENT_MASK_EXT,
|
||||||
|
.box_ctl = SNR_IIO_MSR_PMON_BOX_CTL,
|
||||||
|
.msr_offset = SNR_IIO_MSR_OFFSET,
|
||||||
|
.ops = &ivbep_uncore_msr_ops,
|
||||||
|
.format_group = &snr_uncore_iio_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_irp = {
|
||||||
|
.name = "irp",
|
||||||
|
.num_counters = 2,
|
||||||
|
.num_boxes = 5,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.event_ctl = SNR_IRP0_MSR_PMON_CTL0,
|
||||||
|
.perf_ctr = SNR_IRP0_MSR_PMON_CTR0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.box_ctl = SNR_IRP0_MSR_PMON_BOX_CTL,
|
||||||
|
.msr_offset = SNR_IRP_MSR_OFFSET,
|
||||||
|
.ops = &ivbep_uncore_msr_ops,
|
||||||
|
.format_group = &ivbep_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_m2pcie = {
|
||||||
|
.name = "m2pcie",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 5,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.event_ctl = SNR_M2PCIE_MSR_PMON_CTL0,
|
||||||
|
.perf_ctr = SNR_M2PCIE_MSR_PMON_CTR0,
|
||||||
|
.box_ctl = SNR_M2PCIE_MSR_PMON_BOX_CTL,
|
||||||
|
.msr_offset = SNR_M2PCIE_MSR_OFFSET,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.ops = &ivbep_uncore_msr_ops,
|
||||||
|
.format_group = &ivbep_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int snr_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
|
||||||
|
{
|
||||||
|
struct hw_perf_event *hwc = &event->hw;
|
||||||
|
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
|
||||||
|
int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
|
||||||
|
|
||||||
|
if (ev_sel >= 0xb && ev_sel <= 0xe) {
|
||||||
|
reg1->reg = SNR_PCU_MSR_PMON_BOX_FILTER;
|
||||||
|
reg1->idx = ev_sel - 0xb;
|
||||||
|
reg1->config = event->attr.config1 & (0xff << reg1->idx);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_uncore_ops snr_uncore_pcu_ops = {
|
||||||
|
IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
|
||||||
|
.hw_config = snr_pcu_hw_config,
|
||||||
|
.get_constraint = snbep_pcu_get_constraint,
|
||||||
|
.put_constraint = snbep_pcu_put_constraint,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_pcu = {
|
||||||
|
.name = "pcu",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 1,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.perf_ctr = SNR_PCU_MSR_PMON_CTR0,
|
||||||
|
.event_ctl = SNR_PCU_MSR_PMON_CTL0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.box_ctl = SNR_PCU_MSR_PMON_BOX_CTL,
|
||||||
|
.num_shared_regs = 1,
|
||||||
|
.ops = &snr_uncore_pcu_ops,
|
||||||
|
.format_group = &skx_uncore_pcu_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum perf_uncore_snr_iio_freerunning_type_id {
|
||||||
|
SNR_IIO_MSR_IOCLK,
|
||||||
|
SNR_IIO_MSR_BW_IN,
|
||||||
|
|
||||||
|
SNR_IIO_FREERUNNING_TYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct freerunning_counters snr_iio_freerunning[] = {
|
||||||
|
[SNR_IIO_MSR_IOCLK] = { 0x1eac, 0x1, 0x10, 1, 48 },
|
||||||
|
[SNR_IIO_MSR_BW_IN] = { 0x1f00, 0x1, 0x10, 8, 48 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct uncore_event_desc snr_uncore_iio_freerunning_events[] = {
|
||||||
|
/* Free-Running IIO CLOCKS Counter */
|
||||||
|
INTEL_UNCORE_EVENT_DESC(ioclk, "event=0xff,umask=0x10"),
|
||||||
|
/* Free-Running IIO BANDWIDTH IN Counters */
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port0, "event=0xff,umask=0x20"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port0.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port0.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port1, "event=0xff,umask=0x21"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port1.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port1.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port2, "event=0xff,umask=0x22"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port2.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port2.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port3, "event=0xff,umask=0x23"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port3.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port3.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port4, "event=0xff,umask=0x24"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port4.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port4.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port5, "event=0xff,umask=0x25"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port5.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port5.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port6, "event=0xff,umask=0x26"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port6.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port6.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port7, "event=0xff,umask=0x27"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port7.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(bw_in_port7.unit, "MiB"),
|
||||||
|
{ /* end: all zeroes */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_iio_free_running = {
|
||||||
|
.name = "iio_free_running",
|
||||||
|
.num_counters = 9,
|
||||||
|
.num_boxes = 5,
|
||||||
|
.num_freerunning_types = SNR_IIO_FREERUNNING_TYPE_MAX,
|
||||||
|
.freerunning = snr_iio_freerunning,
|
||||||
|
.ops = &skx_uncore_iio_freerunning_ops,
|
||||||
|
.event_descs = snr_uncore_iio_freerunning_events,
|
||||||
|
.format_group = &skx_uncore_iio_freerunning_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type *snr_msr_uncores[] = {
|
||||||
|
&snr_uncore_ubox,
|
||||||
|
&snr_uncore_chabox,
|
||||||
|
&snr_uncore_iio,
|
||||||
|
&snr_uncore_irp,
|
||||||
|
&snr_uncore_m2pcie,
|
||||||
|
&snr_uncore_pcu,
|
||||||
|
&snr_uncore_iio_free_running,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void snr_uncore_cpu_init(void)
|
||||||
|
{
|
||||||
|
uncore_msr_uncores = snr_msr_uncores;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_m2m_uncore_pci_init_box(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
struct pci_dev *pdev = box->pci_dev;
|
||||||
|
int box_ctl = uncore_pci_box_ctl(box);
|
||||||
|
|
||||||
|
__set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags);
|
||||||
|
pci_write_config_dword(pdev, box_ctl, IVBEP_PMON_BOX_CTL_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_uncore_ops snr_m2m_uncore_pci_ops = {
|
||||||
|
.init_box = snr_m2m_uncore_pci_init_box,
|
||||||
|
.disable_box = snbep_uncore_pci_disable_box,
|
||||||
|
.enable_box = snbep_uncore_pci_enable_box,
|
||||||
|
.disable_event = snbep_uncore_pci_disable_event,
|
||||||
|
.enable_event = snbep_uncore_pci_enable_event,
|
||||||
|
.read_counter = snbep_uncore_pci_read_counter,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute *snr_m2m_uncore_formats_attr[] = {
|
||||||
|
&format_attr_event.attr,
|
||||||
|
&format_attr_umask_ext3.attr,
|
||||||
|
&format_attr_edge.attr,
|
||||||
|
&format_attr_inv.attr,
|
||||||
|
&format_attr_thresh8.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group snr_m2m_uncore_format_group = {
|
||||||
|
.name = "format",
|
||||||
|
.attrs = snr_m2m_uncore_formats_attr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_m2m = {
|
||||||
|
.name = "m2m",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 1,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.perf_ctr = SNR_M2M_PCI_PMON_CTR0,
|
||||||
|
.event_ctl = SNR_M2M_PCI_PMON_CTL0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.event_mask_ext = SNR_M2M_PCI_PMON_UMASK_EXT,
|
||||||
|
.box_ctl = SNR_M2M_PCI_PMON_BOX_CTL,
|
||||||
|
.ops = &snr_m2m_uncore_pci_ops,
|
||||||
|
.format_group = &snr_m2m_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_pcie3 = {
|
||||||
|
.name = "pcie3",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 1,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.perf_ctr = SNR_PCIE3_PCI_PMON_CTR0,
|
||||||
|
.event_ctl = SNR_PCIE3_PCI_PMON_CTL0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.box_ctl = SNR_PCIE3_PCI_PMON_BOX_CTL,
|
||||||
|
.ops = &ivbep_uncore_pci_ops,
|
||||||
|
.format_group = &ivbep_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SNR_PCI_UNCORE_M2M,
|
||||||
|
SNR_PCI_UNCORE_PCIE3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type *snr_pci_uncores[] = {
|
||||||
|
[SNR_PCI_UNCORE_M2M] = &snr_uncore_m2m,
|
||||||
|
[SNR_PCI_UNCORE_PCIE3] = &snr_uncore_pcie3,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_device_id snr_uncore_pci_ids[] = {
|
||||||
|
{ /* M2M */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x344a),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_FULL_DATA(12, 0, SNR_PCI_UNCORE_M2M, 0),
|
||||||
|
},
|
||||||
|
{ /* PCIe3 */
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x334a),
|
||||||
|
.driver_data = UNCORE_PCI_DEV_FULL_DATA(4, 0, SNR_PCI_UNCORE_PCIE3, 0),
|
||||||
|
},
|
||||||
|
{ /* end: all zeroes */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pci_driver snr_uncore_pci_driver = {
|
||||||
|
.name = "snr_uncore",
|
||||||
|
.id_table = snr_uncore_pci_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
int snr_uncore_pci_init(void)
|
||||||
|
{
|
||||||
|
/* SNR UBOX DID */
|
||||||
|
int ret = snbep_pci2phy_map_init(0x3460, SKX_CPUNODEID,
|
||||||
|
SKX_GIDNIDMAP, true);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
uncore_pci_uncores = snr_pci_uncores;
|
||||||
|
uncore_pci_driver = &snr_uncore_pci_driver;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_dev *snr_uncore_get_mc_dev(int id)
|
||||||
|
{
|
||||||
|
struct pci_dev *mc_dev = NULL;
|
||||||
|
int phys_id, pkg;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
mc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3451, mc_dev);
|
||||||
|
if (!mc_dev)
|
||||||
|
break;
|
||||||
|
phys_id = uncore_pcibus_to_physid(mc_dev->bus);
|
||||||
|
if (phys_id < 0)
|
||||||
|
continue;
|
||||||
|
pkg = topology_phys_to_logical_pkg(phys_id);
|
||||||
|
if (pkg < 0)
|
||||||
|
continue;
|
||||||
|
else if (pkg == id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mc_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_uncore_mmio_init_box(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
struct pci_dev *pdev = snr_uncore_get_mc_dev(box->dieid);
|
||||||
|
unsigned int box_ctl = uncore_mmio_box_ctl(box);
|
||||||
|
resource_size_t addr;
|
||||||
|
u32 pci_dword;
|
||||||
|
|
||||||
|
if (!pdev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_read_config_dword(pdev, SNR_IMC_MMIO_BASE_OFFSET, &pci_dword);
|
||||||
|
addr = (pci_dword & SNR_IMC_MMIO_BASE_MASK) << 23;
|
||||||
|
|
||||||
|
pci_read_config_dword(pdev, SNR_IMC_MMIO_MEM0_OFFSET, &pci_dword);
|
||||||
|
addr |= (pci_dword & SNR_IMC_MMIO_MEM0_MASK) << 12;
|
||||||
|
|
||||||
|
addr += box_ctl;
|
||||||
|
|
||||||
|
box->io_addr = ioremap(addr, SNR_IMC_MMIO_SIZE);
|
||||||
|
if (!box->io_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writel(IVBEP_PMON_BOX_CTL_INT, box->io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_uncore_mmio_disable_box(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
u32 config;
|
||||||
|
|
||||||
|
if (!box->io_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
config = readl(box->io_addr);
|
||||||
|
config |= SNBEP_PMON_BOX_CTL_FRZ;
|
||||||
|
writel(config, box->io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_uncore_mmio_enable_box(struct intel_uncore_box *box)
|
||||||
|
{
|
||||||
|
u32 config;
|
||||||
|
|
||||||
|
if (!box->io_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
config = readl(box->io_addr);
|
||||||
|
config &= ~SNBEP_PMON_BOX_CTL_FRZ;
|
||||||
|
writel(config, box->io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_uncore_mmio_enable_event(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event)
|
||||||
|
{
|
||||||
|
struct hw_perf_event *hwc = &event->hw;
|
||||||
|
|
||||||
|
if (!box->io_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writel(hwc->config | SNBEP_PMON_CTL_EN,
|
||||||
|
box->io_addr + hwc->config_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void snr_uncore_mmio_disable_event(struct intel_uncore_box *box,
|
||||||
|
struct perf_event *event)
|
||||||
|
{
|
||||||
|
struct hw_perf_event *hwc = &event->hw;
|
||||||
|
|
||||||
|
if (!box->io_addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
writel(hwc->config, box->io_addr + hwc->config_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_uncore_ops snr_uncore_mmio_ops = {
|
||||||
|
.init_box = snr_uncore_mmio_init_box,
|
||||||
|
.exit_box = uncore_mmio_exit_box,
|
||||||
|
.disable_box = snr_uncore_mmio_disable_box,
|
||||||
|
.enable_box = snr_uncore_mmio_enable_box,
|
||||||
|
.disable_event = snr_uncore_mmio_disable_event,
|
||||||
|
.enable_event = snr_uncore_mmio_enable_event,
|
||||||
|
.read_counter = uncore_mmio_read_counter,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct uncore_event_desc snr_uncore_imc_events[] = {
|
||||||
|
INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x00,umask=0x00"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x0f"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x30"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),
|
||||||
|
{ /* end: all zeroes */ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_imc = {
|
||||||
|
.name = "imc",
|
||||||
|
.num_counters = 4,
|
||||||
|
.num_boxes = 2,
|
||||||
|
.perf_ctr_bits = 48,
|
||||||
|
.fixed_ctr_bits = 48,
|
||||||
|
.fixed_ctr = SNR_IMC_MMIO_PMON_FIXED_CTR,
|
||||||
|
.fixed_ctl = SNR_IMC_MMIO_PMON_FIXED_CTL,
|
||||||
|
.event_descs = snr_uncore_imc_events,
|
||||||
|
.perf_ctr = SNR_IMC_MMIO_PMON_CTR0,
|
||||||
|
.event_ctl = SNR_IMC_MMIO_PMON_CTL0,
|
||||||
|
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
|
||||||
|
.box_ctl = SNR_IMC_MMIO_PMON_BOX_CTL,
|
||||||
|
.mmio_offset = SNR_IMC_MMIO_OFFSET,
|
||||||
|
.ops = &snr_uncore_mmio_ops,
|
||||||
|
.format_group = &skx_uncore_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum perf_uncore_snr_imc_freerunning_type_id {
|
||||||
|
SNR_IMC_DCLK,
|
||||||
|
SNR_IMC_DDR,
|
||||||
|
|
||||||
|
SNR_IMC_FREERUNNING_TYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct freerunning_counters snr_imc_freerunning[] = {
|
||||||
|
[SNR_IMC_DCLK] = { 0x22b0, 0x0, 0, 1, 48 },
|
||||||
|
[SNR_IMC_DDR] = { 0x2290, 0x8, 0, 2, 48 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct uncore_event_desc snr_uncore_imc_freerunning_events[] = {
|
||||||
|
INTEL_UNCORE_EVENT_DESC(dclk, "event=0xff,umask=0x10"),
|
||||||
|
|
||||||
|
INTEL_UNCORE_EVENT_DESC(read, "event=0xff,umask=0x20"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(read.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(read.unit, "MiB"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(write, "event=0xff,umask=0x21"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(write.scale, "3.814697266e-6"),
|
||||||
|
INTEL_UNCORE_EVENT_DESC(write.unit, "MiB"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_ops snr_uncore_imc_freerunning_ops = {
|
||||||
|
.init_box = snr_uncore_mmio_init_box,
|
||||||
|
.exit_box = uncore_mmio_exit_box,
|
||||||
|
.read_counter = uncore_mmio_read_counter,
|
||||||
|
.hw_config = uncore_freerunning_hw_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type snr_uncore_imc_free_running = {
|
||||||
|
.name = "imc_free_running",
|
||||||
|
.num_counters = 3,
|
||||||
|
.num_boxes = 1,
|
||||||
|
.num_freerunning_types = SNR_IMC_FREERUNNING_TYPE_MAX,
|
||||||
|
.freerunning = snr_imc_freerunning,
|
||||||
|
.ops = &snr_uncore_imc_freerunning_ops,
|
||||||
|
.event_descs = snr_uncore_imc_freerunning_events,
|
||||||
|
.format_group = &skx_uncore_iio_freerunning_format_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intel_uncore_type *snr_mmio_uncores[] = {
|
||||||
|
&snr_uncore_imc,
|
||||||
|
&snr_uncore_imc_free_running,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void snr_uncore_mmio_init(void)
|
||||||
|
{
|
||||||
|
uncore_mmio_uncores = snr_mmio_uncores;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of SNR uncore support */
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
#include <linux/nospec.h>
|
#include <linux/nospec.h>
|
||||||
#include <asm/intel-family.h>
|
#include <asm/intel-family.h>
|
||||||
|
#include "probe.h"
|
||||||
|
|
||||||
enum perf_msr_id {
|
enum perf_msr_id {
|
||||||
PERF_MSR_TSC = 0,
|
PERF_MSR_TSC = 0,
|
||||||
|
@ -12,32 +14,30 @@ enum perf_msr_id {
|
||||||
PERF_MSR_PTSC = 5,
|
PERF_MSR_PTSC = 5,
|
||||||
PERF_MSR_IRPERF = 6,
|
PERF_MSR_IRPERF = 6,
|
||||||
PERF_MSR_THERM = 7,
|
PERF_MSR_THERM = 7,
|
||||||
PERF_MSR_THERM_SNAP = 8,
|
|
||||||
PERF_MSR_THERM_UNIT = 9,
|
|
||||||
PERF_MSR_EVENT_MAX,
|
PERF_MSR_EVENT_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool test_aperfmperf(int idx)
|
static bool test_aperfmperf(int idx, void *data)
|
||||||
{
|
{
|
||||||
return boot_cpu_has(X86_FEATURE_APERFMPERF);
|
return boot_cpu_has(X86_FEATURE_APERFMPERF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_ptsc(int idx)
|
static bool test_ptsc(int idx, void *data)
|
||||||
{
|
{
|
||||||
return boot_cpu_has(X86_FEATURE_PTSC);
|
return boot_cpu_has(X86_FEATURE_PTSC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_irperf(int idx)
|
static bool test_irperf(int idx, void *data)
|
||||||
{
|
{
|
||||||
return boot_cpu_has(X86_FEATURE_IRPERF);
|
return boot_cpu_has(X86_FEATURE_IRPERF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_therm_status(int idx)
|
static bool test_therm_status(int idx, void *data)
|
||||||
{
|
{
|
||||||
return boot_cpu_has(X86_FEATURE_DTHERM);
|
return boot_cpu_has(X86_FEATURE_DTHERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_intel(int idx)
|
static bool test_intel(int idx, void *data)
|
||||||
{
|
{
|
||||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
|
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
|
||||||
boot_cpu_data.x86 != 6)
|
boot_cpu_data.x86 != 6)
|
||||||
|
@ -98,37 +98,51 @@ static bool test_intel(int idx)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perf_msr {
|
PMU_EVENT_ATTR_STRING(tsc, attr_tsc, "event=0x00" );
|
||||||
u64 msr;
|
PMU_EVENT_ATTR_STRING(aperf, attr_aperf, "event=0x01" );
|
||||||
struct perf_pmu_events_attr *attr;
|
PMU_EVENT_ATTR_STRING(mperf, attr_mperf, "event=0x02" );
|
||||||
bool (*test)(int idx);
|
PMU_EVENT_ATTR_STRING(pperf, attr_pperf, "event=0x03" );
|
||||||
|
PMU_EVENT_ATTR_STRING(smi, attr_smi, "event=0x04" );
|
||||||
|
PMU_EVENT_ATTR_STRING(ptsc, attr_ptsc, "event=0x05" );
|
||||||
|
PMU_EVENT_ATTR_STRING(irperf, attr_irperf, "event=0x06" );
|
||||||
|
PMU_EVENT_ATTR_STRING(cpu_thermal_margin, attr_therm, "event=0x07" );
|
||||||
|
PMU_EVENT_ATTR_STRING(cpu_thermal_margin.snapshot, attr_therm_snap, "1" );
|
||||||
|
PMU_EVENT_ATTR_STRING(cpu_thermal_margin.unit, attr_therm_unit, "C" );
|
||||||
|
|
||||||
|
static unsigned long msr_mask;
|
||||||
|
|
||||||
|
PMU_EVENT_GROUP(events, aperf);
|
||||||
|
PMU_EVENT_GROUP(events, mperf);
|
||||||
|
PMU_EVENT_GROUP(events, pperf);
|
||||||
|
PMU_EVENT_GROUP(events, smi);
|
||||||
|
PMU_EVENT_GROUP(events, ptsc);
|
||||||
|
PMU_EVENT_GROUP(events, irperf);
|
||||||
|
|
||||||
|
static struct attribute *attrs_therm[] = {
|
||||||
|
&attr_therm.attr.attr,
|
||||||
|
&attr_therm_snap.attr.attr,
|
||||||
|
&attr_therm_unit.attr.attr,
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
PMU_EVENT_ATTR_STRING(tsc, evattr_tsc, "event=0x00" );
|
static struct attribute_group group_therm = {
|
||||||
PMU_EVENT_ATTR_STRING(aperf, evattr_aperf, "event=0x01" );
|
.name = "events",
|
||||||
PMU_EVENT_ATTR_STRING(mperf, evattr_mperf, "event=0x02" );
|
.attrs = attrs_therm,
|
||||||
PMU_EVENT_ATTR_STRING(pperf, evattr_pperf, "event=0x03" );
|
};
|
||||||
PMU_EVENT_ATTR_STRING(smi, evattr_smi, "event=0x04" );
|
|
||||||
PMU_EVENT_ATTR_STRING(ptsc, evattr_ptsc, "event=0x05" );
|
|
||||||
PMU_EVENT_ATTR_STRING(irperf, evattr_irperf, "event=0x06" );
|
|
||||||
PMU_EVENT_ATTR_STRING(cpu_thermal_margin, evattr_therm, "event=0x07" );
|
|
||||||
PMU_EVENT_ATTR_STRING(cpu_thermal_margin.snapshot, evattr_therm_snap, "1" );
|
|
||||||
PMU_EVENT_ATTR_STRING(cpu_thermal_margin.unit, evattr_therm_unit, "C" );
|
|
||||||
|
|
||||||
static struct perf_msr msr[] = {
|
static struct perf_msr msr[] = {
|
||||||
[PERF_MSR_TSC] = { 0, &evattr_tsc, NULL, },
|
[PERF_MSR_TSC] = { .no_check = true, },
|
||||||
[PERF_MSR_APERF] = { MSR_IA32_APERF, &evattr_aperf, test_aperfmperf, },
|
[PERF_MSR_APERF] = { MSR_IA32_APERF, &group_aperf, test_aperfmperf, },
|
||||||
[PERF_MSR_MPERF] = { MSR_IA32_MPERF, &evattr_mperf, test_aperfmperf, },
|
[PERF_MSR_MPERF] = { MSR_IA32_MPERF, &group_mperf, test_aperfmperf, },
|
||||||
[PERF_MSR_PPERF] = { MSR_PPERF, &evattr_pperf, test_intel, },
|
[PERF_MSR_PPERF] = { MSR_PPERF, &group_pperf, test_intel, },
|
||||||
[PERF_MSR_SMI] = { MSR_SMI_COUNT, &evattr_smi, test_intel, },
|
[PERF_MSR_SMI] = { MSR_SMI_COUNT, &group_smi, test_intel, },
|
||||||
[PERF_MSR_PTSC] = { MSR_F15H_PTSC, &evattr_ptsc, test_ptsc, },
|
[PERF_MSR_PTSC] = { MSR_F15H_PTSC, &group_ptsc, test_ptsc, },
|
||||||
[PERF_MSR_IRPERF] = { MSR_F17H_IRPERF, &evattr_irperf, test_irperf, },
|
[PERF_MSR_IRPERF] = { MSR_F17H_IRPERF, &group_irperf, test_irperf, },
|
||||||
[PERF_MSR_THERM] = { MSR_IA32_THERM_STATUS, &evattr_therm, test_therm_status, },
|
[PERF_MSR_THERM] = { MSR_IA32_THERM_STATUS, &group_therm, test_therm_status, },
|
||||||
[PERF_MSR_THERM_SNAP] = { MSR_IA32_THERM_STATUS, &evattr_therm_snap, test_therm_status, },
|
|
||||||
[PERF_MSR_THERM_UNIT] = { MSR_IA32_THERM_STATUS, &evattr_therm_unit, test_therm_status, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute *events_attrs[PERF_MSR_EVENT_MAX + 1] = {
|
static struct attribute *events_attrs[] = {
|
||||||
|
&attr_tsc.attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,6 +167,17 @@ static const struct attribute_group *attr_groups[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct attribute_group *attr_update[] = {
|
||||||
|
&group_aperf,
|
||||||
|
&group_mperf,
|
||||||
|
&group_pperf,
|
||||||
|
&group_smi,
|
||||||
|
&group_ptsc,
|
||||||
|
&group_irperf,
|
||||||
|
&group_therm,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
static int msr_event_init(struct perf_event *event)
|
static int msr_event_init(struct perf_event *event)
|
||||||
{
|
{
|
||||||
u64 cfg = event->attr.config;
|
u64 cfg = event->attr.config;
|
||||||
|
@ -169,7 +194,7 @@ static int msr_event_init(struct perf_event *event)
|
||||||
|
|
||||||
cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
|
cfg = array_index_nospec((unsigned long)cfg, PERF_MSR_EVENT_MAX);
|
||||||
|
|
||||||
if (!msr[cfg].attr)
|
if (!(msr_mask & (1 << cfg)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
event->hw.idx = -1;
|
event->hw.idx = -1;
|
||||||
|
@ -252,32 +277,17 @@ static struct pmu pmu_msr = {
|
||||||
.stop = msr_event_stop,
|
.stop = msr_event_stop,
|
||||||
.read = msr_event_update,
|
.read = msr_event_update,
|
||||||
.capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
|
.capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE,
|
||||||
|
.attr_update = attr_update,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init msr_init(void)
|
static int __init msr_init(void)
|
||||||
{
|
{
|
||||||
int i, j = 0;
|
|
||||||
|
|
||||||
if (!boot_cpu_has(X86_FEATURE_TSC)) {
|
if (!boot_cpu_has(X86_FEATURE_TSC)) {
|
||||||
pr_cont("no MSR PMU driver.\n");
|
pr_cont("no MSR PMU driver.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe the MSRs. */
|
msr_mask = perf_msr_probe(msr, PERF_MSR_EVENT_MAX, true, NULL);
|
||||||
for (i = PERF_MSR_TSC + 1; i < PERF_MSR_EVENT_MAX; i++) {
|
|
||||||
u64 val;
|
|
||||||
|
|
||||||
/* Virt sucks; you cannot tell if a R/O MSR is present :/ */
|
|
||||||
if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val))
|
|
||||||
msr[i].attr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List remaining MSRs in the sysfs attrs. */
|
|
||||||
for (i = 0; i < PERF_MSR_EVENT_MAX; i++) {
|
|
||||||
if (msr[i].attr)
|
|
||||||
events_attrs[j++] = &msr[i].attr->attr.attr;
|
|
||||||
}
|
|
||||||
events_attrs[j] = NULL;
|
|
||||||
|
|
||||||
perf_pmu_register(&pmu_msr, "msr", -1);
|
perf_pmu_register(&pmu_msr, "msr", -1);
|
||||||
|
|
||||||
|
|
|
@ -613,14 +613,11 @@ struct x86_pmu {
|
||||||
int attr_rdpmc_broken;
|
int attr_rdpmc_broken;
|
||||||
int attr_rdpmc;
|
int attr_rdpmc;
|
||||||
struct attribute **format_attrs;
|
struct attribute **format_attrs;
|
||||||
struct attribute **event_attrs;
|
|
||||||
struct attribute **caps_attrs;
|
|
||||||
|
|
||||||
ssize_t (*events_sysfs_show)(char *page, u64 config);
|
ssize_t (*events_sysfs_show)(char *page, u64 config);
|
||||||
struct attribute **cpu_events;
|
const struct attribute_group **attr_update;
|
||||||
|
|
||||||
unsigned long attr_freeze_on_smi;
|
unsigned long attr_freeze_on_smi;
|
||||||
struct attribute **attrs;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CPU Hotplug hooks
|
* CPU Hotplug hooks
|
||||||
|
@ -886,8 +883,6 @@ static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip)
|
||||||
ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event);
|
ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event);
|
||||||
ssize_t intel_event_sysfs_show(char *page, u64 config);
|
ssize_t intel_event_sysfs_show(char *page, u64 config);
|
||||||
|
|
||||||
struct attribute **merge_attr(struct attribute **a, struct attribute **b);
|
|
||||||
|
|
||||||
ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
|
ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *page);
|
char *page);
|
||||||
ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr,
|
ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
45
arch/x86/events/probe.c
Normal file
45
arch/x86/events/probe.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include "probe.h"
|
||||||
|
|
||||||
|
static umode_t
|
||||||
|
not_visible(struct kobject *kobj, struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
perf_msr_probe(struct perf_msr *msr, int cnt, bool zero, void *data)
|
||||||
|
{
|
||||||
|
unsigned long avail = 0;
|
||||||
|
unsigned int bit;
|
||||||
|
u64 val;
|
||||||
|
|
||||||
|
if (cnt >= BITS_PER_LONG)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (bit = 0; bit < cnt; bit++) {
|
||||||
|
if (!msr[bit].no_check) {
|
||||||
|
struct attribute_group *grp = msr[bit].grp;
|
||||||
|
|
||||||
|
grp->is_visible = not_visible;
|
||||||
|
|
||||||
|
if (msr[bit].test && !msr[bit].test(bit, data))
|
||||||
|
continue;
|
||||||
|
/* Virt sucks; you cannot tell if a R/O MSR is present :/ */
|
||||||
|
if (rdmsrl_safe(msr[bit].msr, &val))
|
||||||
|
continue;
|
||||||
|
/* Disable zero counters if requested. */
|
||||||
|
if (!zero && !val)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
grp->is_visible = NULL;
|
||||||
|
}
|
||||||
|
avail |= BIT(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return avail;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(perf_msr_probe);
|
29
arch/x86/events/probe.h
Normal file
29
arch/x86/events/probe.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef __ARCH_X86_EVENTS_PROBE_H__
|
||||||
|
#define __ARCH_X86_EVENTS_PROBE_H__
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
|
||||||
|
struct perf_msr {
|
||||||
|
u64 msr;
|
||||||
|
struct attribute_group *grp;
|
||||||
|
bool (*test)(int idx, void *data);
|
||||||
|
bool no_check;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
perf_msr_probe(struct perf_msr *msr, int cnt, bool no_zero, void *data);
|
||||||
|
|
||||||
|
#define __PMU_EVENT_GROUP(_name) \
|
||||||
|
static struct attribute *attrs_##_name[] = { \
|
||||||
|
&attr_##_name.attr.attr, \
|
||||||
|
NULL, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PMU_EVENT_GROUP(_grp, _name) \
|
||||||
|
__PMU_EVENT_GROUP(_name); \
|
||||||
|
static struct attribute_group group_##_name = { \
|
||||||
|
.name = #_grp, \
|
||||||
|
.attrs = attrs_##_name, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ARCH_X86_EVENTS_PROBE_H__ */
|
|
@ -22,8 +22,8 @@ enum cpuid_leafs
|
||||||
CPUID_LNX_3,
|
CPUID_LNX_3,
|
||||||
CPUID_7_0_EBX,
|
CPUID_7_0_EBX,
|
||||||
CPUID_D_1_EAX,
|
CPUID_D_1_EAX,
|
||||||
CPUID_F_0_EDX,
|
CPUID_LNX_4,
|
||||||
CPUID_F_1_EDX,
|
CPUID_7_1_EAX,
|
||||||
CPUID_8000_0008_EBX,
|
CPUID_8000_0008_EBX,
|
||||||
CPUID_6_EAX,
|
CPUID_6_EAX,
|
||||||
CPUID_8000_000A_EDX,
|
CPUID_8000_000A_EDX,
|
||||||
|
|
|
@ -239,12 +239,14 @@
|
||||||
#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */
|
#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */
|
||||||
#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */
|
#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */
|
||||||
#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */
|
#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */
|
||||||
|
#define X86_FEATURE_FDP_EXCPTN_ONLY ( 9*32+ 6) /* "" FPU data pointer updated only on x87 exceptions */
|
||||||
#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */
|
#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */
|
||||||
#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */
|
#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */
|
||||||
#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */
|
#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */
|
||||||
#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */
|
#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */
|
||||||
#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */
|
#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */
|
||||||
#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */
|
#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */
|
||||||
|
#define X86_FEATURE_ZERO_FCS_FDS ( 9*32+13) /* "" Zero out FPU CS and FPU DS */
|
||||||
#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */
|
#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */
|
||||||
#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */
|
#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */
|
||||||
#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */
|
#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */
|
||||||
|
@ -269,13 +271,19 @@
|
||||||
#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */
|
#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */
|
||||||
#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */
|
#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */
|
||||||
|
|
||||||
/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */
|
/*
|
||||||
#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */
|
* Extended auxiliary flags: Linux defined - for features scattered in various
|
||||||
|
* CPUID levels like 0xf, etc.
|
||||||
|
*
|
||||||
|
* Reuse free bits when adding new feature flags!
|
||||||
|
*/
|
||||||
|
#define X86_FEATURE_CQM_LLC (11*32+ 0) /* LLC QoS if 1 */
|
||||||
|
#define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */
|
||||||
|
#define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */
|
||||||
|
#define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */
|
||||||
|
|
||||||
/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */
|
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
|
||||||
#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring */
|
#define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */
|
||||||
#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */
|
|
||||||
#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */
|
|
||||||
|
|
||||||
/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
|
/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
|
||||||
#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */
|
#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */
|
||||||
|
@ -322,6 +330,7 @@
|
||||||
#define X86_FEATURE_UMIP (16*32+ 2) /* User Mode Instruction Protection */
|
#define X86_FEATURE_UMIP (16*32+ 2) /* User Mode Instruction Protection */
|
||||||
#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */
|
#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */
|
||||||
#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */
|
#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */
|
||||||
|
#define X86_FEATURE_WAITPKG (16*32+ 5) /* UMONITOR/UMWAIT/TPAUSE Instructions */
|
||||||
#define X86_FEATURE_AVX512_VBMI2 (16*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */
|
#define X86_FEATURE_AVX512_VBMI2 (16*32+ 6) /* Additional AVX512 Vector Bit Manipulation Instructions */
|
||||||
#define X86_FEATURE_GFNI (16*32+ 8) /* Galois Field New Instructions */
|
#define X86_FEATURE_GFNI (16*32+ 8) /* Galois Field New Instructions */
|
||||||
#define X86_FEATURE_VAES (16*32+ 9) /* Vector AES */
|
#define X86_FEATURE_VAES (16*32+ 9) /* Vector AES */
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#define INTEL_FAM6_ICELAKE_XEON_D 0x6C
|
#define INTEL_FAM6_ICELAKE_XEON_D 0x6C
|
||||||
#define INTEL_FAM6_ICELAKE_DESKTOP 0x7D
|
#define INTEL_FAM6_ICELAKE_DESKTOP 0x7D
|
||||||
#define INTEL_FAM6_ICELAKE_MOBILE 0x7E
|
#define INTEL_FAM6_ICELAKE_MOBILE 0x7E
|
||||||
|
#define INTEL_FAM6_ICELAKE_NNPI 0x9D
|
||||||
|
|
||||||
/* "Small Core" Processors (Atom) */
|
/* "Small Core" Processors (Atom) */
|
||||||
|
|
||||||
|
@ -76,6 +77,7 @@
|
||||||
#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */
|
#define INTEL_FAM6_ATOM_GOLDMONT 0x5C /* Apollo Lake */
|
||||||
#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */
|
#define INTEL_FAM6_ATOM_GOLDMONT_X 0x5F /* Denverton */
|
||||||
#define INTEL_FAM6_ATOM_GOLDMONT_PLUS 0x7A /* Gemini Lake */
|
#define INTEL_FAM6_ATOM_GOLDMONT_PLUS 0x7A /* Gemini Lake */
|
||||||
|
|
||||||
#define INTEL_FAM6_ATOM_TREMONT_X 0x86 /* Jacobsville */
|
#define INTEL_FAM6_ATOM_TREMONT_X 0x86 /* Jacobsville */
|
||||||
|
|
||||||
/* Xeon Phi */
|
/* Xeon Phi */
|
||||||
|
|
|
@ -61,6 +61,15 @@
|
||||||
#define MSR_PLATFORM_INFO_CPUID_FAULT_BIT 31
|
#define MSR_PLATFORM_INFO_CPUID_FAULT_BIT 31
|
||||||
#define MSR_PLATFORM_INFO_CPUID_FAULT BIT_ULL(MSR_PLATFORM_INFO_CPUID_FAULT_BIT)
|
#define MSR_PLATFORM_INFO_CPUID_FAULT BIT_ULL(MSR_PLATFORM_INFO_CPUID_FAULT_BIT)
|
||||||
|
|
||||||
|
#define MSR_IA32_UMWAIT_CONTROL 0xe1
|
||||||
|
#define MSR_IA32_UMWAIT_CONTROL_C02_DISABLE BIT(0)
|
||||||
|
#define MSR_IA32_UMWAIT_CONTROL_RESERVED BIT(1)
|
||||||
|
/*
|
||||||
|
* The time field is bit[31:2], but representing a 32bit value with
|
||||||
|
* bit[1:0] zero.
|
||||||
|
*/
|
||||||
|
#define MSR_IA32_UMWAIT_CONTROL_TIME_MASK (~0x03U)
|
||||||
|
|
||||||
#define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2
|
#define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2
|
||||||
#define NHM_C3_AUTO_DEMOTE (1UL << 25)
|
#define NHM_C3_AUTO_DEMOTE (1UL << 25)
|
||||||
#define NHM_C1_AUTO_DEMOTE (1UL << 26)
|
#define NHM_C1_AUTO_DEMOTE (1UL << 26)
|
||||||
|
|
|
@ -105,7 +105,7 @@ struct cpuinfo_x86 {
|
||||||
int x86_power;
|
int x86_power;
|
||||||
unsigned long loops_per_jiffy;
|
unsigned long loops_per_jiffy;
|
||||||
/* cpuid returned max cores value: */
|
/* cpuid returned max cores value: */
|
||||||
u16 x86_max_cores;
|
u16 x86_max_cores;
|
||||||
u16 apicid;
|
u16 apicid;
|
||||||
u16 initial_apicid;
|
u16 initial_apicid;
|
||||||
u16 x86_clflush_size;
|
u16 x86_clflush_size;
|
||||||
|
@ -117,6 +117,8 @@ struct cpuinfo_x86 {
|
||||||
u16 logical_proc_id;
|
u16 logical_proc_id;
|
||||||
/* Core id: */
|
/* Core id: */
|
||||||
u16 cpu_core_id;
|
u16 cpu_core_id;
|
||||||
|
u16 cpu_die_id;
|
||||||
|
u16 logical_die_id;
|
||||||
/* Index into per_cpu list: */
|
/* Index into per_cpu list: */
|
||||||
u16 cpu_index;
|
u16 cpu_index;
|
||||||
u32 microcode;
|
u32 microcode;
|
||||||
|
@ -144,7 +146,8 @@ enum cpuid_regs_idx {
|
||||||
#define X86_VENDOR_TRANSMETA 7
|
#define X86_VENDOR_TRANSMETA 7
|
||||||
#define X86_VENDOR_NSC 8
|
#define X86_VENDOR_NSC 8
|
||||||
#define X86_VENDOR_HYGON 9
|
#define X86_VENDOR_HYGON 9
|
||||||
#define X86_VENDOR_NUM 10
|
#define X86_VENDOR_ZHAOXIN 10
|
||||||
|
#define X86_VENDOR_NUM 11
|
||||||
|
|
||||||
#define X86_VENDOR_UNKNOWN 0xff
|
#define X86_VENDOR_UNKNOWN 0xff
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern unsigned int num_processors;
|
||||||
|
|
||||||
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
|
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
|
||||||
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
|
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
|
||||||
|
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_die_map);
|
||||||
/* cpus sharing the last level cache: */
|
/* cpus sharing the last level cache: */
|
||||||
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
|
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
|
||||||
DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id);
|
DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id);
|
||||||
|
|
|
@ -106,15 +106,25 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||||
|
|
||||||
#define topology_logical_package_id(cpu) (cpu_data(cpu).logical_proc_id)
|
#define topology_logical_package_id(cpu) (cpu_data(cpu).logical_proc_id)
|
||||||
#define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id)
|
#define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id)
|
||||||
|
#define topology_logical_die_id(cpu) (cpu_data(cpu).logical_die_id)
|
||||||
|
#define topology_die_id(cpu) (cpu_data(cpu).cpu_die_id)
|
||||||
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
|
#define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id)
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
#define topology_die_cpumask(cpu) (per_cpu(cpu_die_map, cpu))
|
||||||
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
|
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
|
||||||
#define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
|
#define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
|
||||||
|
|
||||||
extern unsigned int __max_logical_packages;
|
extern unsigned int __max_logical_packages;
|
||||||
#define topology_max_packages() (__max_logical_packages)
|
#define topology_max_packages() (__max_logical_packages)
|
||||||
|
|
||||||
|
extern unsigned int __max_die_per_package;
|
||||||
|
|
||||||
|
static inline int topology_max_die_per_package(void)
|
||||||
|
{
|
||||||
|
return __max_die_per_package;
|
||||||
|
}
|
||||||
|
|
||||||
extern int __max_smt_threads;
|
extern int __max_smt_threads;
|
||||||
|
|
||||||
static inline int topology_max_smt_threads(void)
|
static inline int topology_max_smt_threads(void)
|
||||||
|
@ -123,14 +133,21 @@ static inline int topology_max_smt_threads(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int topology_update_package_map(unsigned int apicid, unsigned int cpu);
|
int topology_update_package_map(unsigned int apicid, unsigned int cpu);
|
||||||
|
int topology_update_die_map(unsigned int dieid, unsigned int cpu);
|
||||||
int topology_phys_to_logical_pkg(unsigned int pkg);
|
int topology_phys_to_logical_pkg(unsigned int pkg);
|
||||||
|
int topology_phys_to_logical_die(unsigned int die, unsigned int cpu);
|
||||||
bool topology_is_primary_thread(unsigned int cpu);
|
bool topology_is_primary_thread(unsigned int cpu);
|
||||||
bool topology_smt_supported(void);
|
bool topology_smt_supported(void);
|
||||||
#else
|
#else
|
||||||
#define topology_max_packages() (1)
|
#define topology_max_packages() (1)
|
||||||
static inline int
|
static inline int
|
||||||
topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; }
|
topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; }
|
||||||
|
static inline int
|
||||||
|
topology_update_die_map(unsigned int dieid, unsigned int cpu) { return 0; }
|
||||||
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
|
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
|
||||||
|
static inline int topology_phys_to_logical_die(unsigned int die,
|
||||||
|
unsigned int cpu) { return 0; }
|
||||||
|
static inline int topology_max_die_per_package(void) { return 1; }
|
||||||
static inline int topology_max_smt_threads(void) { return 1; }
|
static inline int topology_max_smt_threads(void) { return 1; }
|
||||||
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
|
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
|
||||||
static inline bool topology_smt_supported(void) { return false; }
|
static inline bool topology_smt_supported(void) { return false; }
|
||||||
|
|
|
@ -64,6 +64,21 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
||||||
c->x86_stepping >= 0x0e))
|
c->x86_stepping >= 0x0e))
|
||||||
flags->bm_check = 1;
|
flags->bm_check = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->x86_vendor == X86_VENDOR_ZHAOXIN) {
|
||||||
|
/*
|
||||||
|
* All Zhaoxin CPUs that support C3 share cache.
|
||||||
|
* And caches should not be flushed by software while
|
||||||
|
* entering C3 type state.
|
||||||
|
*/
|
||||||
|
flags->bm_check = 1;
|
||||||
|
/*
|
||||||
|
* On all recent Zhaoxin platforms, ARB_DISABLE is a nop.
|
||||||
|
* So, set bm_control to zero to indicate that ARB_DISABLE
|
||||||
|
* is not required while entering C3 type state.
|
||||||
|
*/
|
||||||
|
flags->bm_control = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
|
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ obj-y += match.o
|
||||||
obj-y += bugs.o
|
obj-y += bugs.o
|
||||||
obj-y += aperfmperf.o
|
obj-y += aperfmperf.o
|
||||||
obj-y += cpuid-deps.o
|
obj-y += cpuid-deps.o
|
||||||
|
obj-y += umwait.o
|
||||||
|
|
||||||
obj-$(CONFIG_PROC_FS) += proc.o
|
obj-$(CONFIG_PROC_FS) += proc.o
|
||||||
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
||||||
|
@ -38,6 +39,7 @@ obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||||
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
|
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
|
||||||
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
|
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
|
||||||
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
|
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
|
||||||
|
obj-$(CONFIG_CPU_SUP_ZHAOXIN) += zhaoxin.o
|
||||||
|
|
||||||
obj-$(CONFIG_X86_MCE) += mce/
|
obj-$(CONFIG_X86_MCE) += mce/
|
||||||
obj-$(CONFIG_MTRR) += mtrr/
|
obj-$(CONFIG_MTRR) += mtrr/
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/percpu.h>
|
#include <linux/percpu.h>
|
||||||
#include <linux/cpufreq.h>
|
#include <linux/cpufreq.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
#include <linux/sched/isolation.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
|
@ -85,6 +86,9 @@ unsigned int aperfmperf_get_khz(int cpu)
|
||||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||||
|
return 0;
|
||||||
|
|
||||||
aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
|
aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
|
||||||
return per_cpu(samples.khz, cpu);
|
return per_cpu(samples.khz, cpu);
|
||||||
}
|
}
|
||||||
|
@ -101,9 +105,12 @@ void arch_freq_prepare_all(void)
|
||||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_online_cpu(cpu)
|
for_each_online_cpu(cpu) {
|
||||||
|
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||||
|
continue;
|
||||||
if (!aperfmperf_snapshot_cpu(cpu, now, false))
|
if (!aperfmperf_snapshot_cpu(cpu, now, false))
|
||||||
wait = true;
|
wait = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (wait)
|
if (wait)
|
||||||
msleep(APERFMPERF_REFRESH_DELAY_MS);
|
msleep(APERFMPERF_REFRESH_DELAY_MS);
|
||||||
|
@ -117,6 +124,9 @@ unsigned int arch_freq_get_on_cpu(int cpu)
|
||||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
|
if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
|
||||||
return per_cpu(samples.khz, cpu);
|
return per_cpu(samples.khz, cpu);
|
||||||
|
|
||||||
|
|
|
@ -658,8 +658,7 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
|
||||||
if (c->x86 < 0x17) {
|
if (c->x86 < 0x17) {
|
||||||
/* LLC is at the node level. */
|
/* LLC is at the node level. */
|
||||||
per_cpu(cpu_llc_id, cpu) = node_id;
|
per_cpu(cpu_llc_id, cpu) = node_id;
|
||||||
} else if (c->x86 == 0x17 &&
|
} else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
|
||||||
c->x86_model >= 0 && c->x86_model <= 0x1F) {
|
|
||||||
/*
|
/*
|
||||||
* LLC is at the core complex level.
|
* LLC is at the core complex level.
|
||||||
* Core complex ID is ApicId[3] for these processors.
|
* Core complex ID is ApicId[3] for these processors.
|
||||||
|
|
|
@ -801,6 +801,30 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_cqm(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
||||||
|
c->x86_cache_max_rmid = -1;
|
||||||
|
c->x86_cache_occ_scale = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* will be overridden if occupancy monitoring exists */
|
||||||
|
c->x86_cache_max_rmid = cpuid_ebx(0xf);
|
||||||
|
|
||||||
|
if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
|
||||||
|
cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
|
||||||
|
cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
|
||||||
|
u32 eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
||||||
|
cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
c->x86_cache_max_rmid = ecx;
|
||||||
|
c->x86_cache_occ_scale = ebx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void get_cpu_cap(struct cpuinfo_x86 *c)
|
void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||||
{
|
{
|
||||||
u32 eax, ebx, ecx, edx;
|
u32 eax, ebx, ecx, edx;
|
||||||
|
@ -823,6 +847,12 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||||
c->x86_capability[CPUID_7_0_EBX] = ebx;
|
c->x86_capability[CPUID_7_0_EBX] = ebx;
|
||||||
c->x86_capability[CPUID_7_ECX] = ecx;
|
c->x86_capability[CPUID_7_ECX] = ecx;
|
||||||
c->x86_capability[CPUID_7_EDX] = edx;
|
c->x86_capability[CPUID_7_EDX] = edx;
|
||||||
|
|
||||||
|
/* Check valid sub-leaf index before accessing it */
|
||||||
|
if (eax >= 1) {
|
||||||
|
cpuid_count(0x00000007, 1, &eax, &ebx, &ecx, &edx);
|
||||||
|
c->x86_capability[CPUID_7_1_EAX] = eax;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extended state features: level 0x0000000d */
|
/* Extended state features: level 0x0000000d */
|
||||||
|
@ -832,33 +862,6 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||||
c->x86_capability[CPUID_D_1_EAX] = eax;
|
c->x86_capability[CPUID_D_1_EAX] = eax;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Additional Intel-defined flags: level 0x0000000F */
|
|
||||||
if (c->cpuid_level >= 0x0000000F) {
|
|
||||||
|
|
||||||
/* QoS sub-leaf, EAX=0Fh, ECX=0 */
|
|
||||||
cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
|
|
||||||
c->x86_capability[CPUID_F_0_EDX] = edx;
|
|
||||||
|
|
||||||
if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
|
||||||
/* will be overridden if occupancy monitoring exists */
|
|
||||||
c->x86_cache_max_rmid = ebx;
|
|
||||||
|
|
||||||
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
|
||||||
cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
|
|
||||||
c->x86_capability[CPUID_F_1_EDX] = edx;
|
|
||||||
|
|
||||||
if ((cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) ||
|
|
||||||
((cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL)) ||
|
|
||||||
(cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)))) {
|
|
||||||
c->x86_cache_max_rmid = ecx;
|
|
||||||
c->x86_cache_occ_scale = ebx;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c->x86_cache_max_rmid = -1;
|
|
||||||
c->x86_cache_occ_scale = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* AMD-defined flags: level 0x80000001 */
|
/* AMD-defined flags: level 0x80000001 */
|
||||||
eax = cpuid_eax(0x80000000);
|
eax = cpuid_eax(0x80000000);
|
||||||
c->extended_cpuid_level = eax;
|
c->extended_cpuid_level = eax;
|
||||||
|
@ -889,6 +892,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||||
|
|
||||||
init_scattered_cpuid_features(c);
|
init_scattered_cpuid_features(c);
|
||||||
init_speculation_control(c);
|
init_speculation_control(c);
|
||||||
|
init_cqm(c);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear/Set all flags overridden by options, after probe.
|
* Clear/Set all flags overridden by options, after probe.
|
||||||
|
@ -1299,6 +1303,7 @@ static void validate_apic_and_package_id(struct cpuinfo_x86 *c)
|
||||||
cpu, apicid, c->initial_apicid);
|
cpu, apicid, c->initial_apicid);
|
||||||
}
|
}
|
||||||
BUG_ON(topology_update_package_map(c->phys_proc_id, cpu));
|
BUG_ON(topology_update_package_map(c->phys_proc_id, cpu));
|
||||||
|
BUG_ON(topology_update_die_map(c->cpu_die_id, cpu));
|
||||||
#else
|
#else
|
||||||
c->logical_proc_id = 0;
|
c->logical_proc_id = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,6 +59,10 @@ static const struct cpuid_dep cpuid_deps[] = {
|
||||||
{ X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
|
{ X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
|
||||||
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
|
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
|
||||||
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
|
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
|
||||||
|
{ X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC },
|
||||||
|
{ X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC },
|
||||||
|
{ X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC },
|
||||||
|
{ X86_FEATURE_AVX512_BF16, X86_FEATURE_AVX512VL },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,32 @@ void check_mpx_erratum(struct cpuinfo_x86 *c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Processors which have self-snooping capability can handle conflicting
|
||||||
|
* memory type across CPUs by snooping its own cache. However, there exists
|
||||||
|
* CPU models in which having conflicting memory types still leads to
|
||||||
|
* unpredictable behavior, machine check errors, or hangs. Clear this
|
||||||
|
* feature to prevent its use on machines with known erratas.
|
||||||
|
*/
|
||||||
|
static void check_memory_type_self_snoop_errata(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
switch (c->x86_model) {
|
||||||
|
case INTEL_FAM6_CORE_YONAH:
|
||||||
|
case INTEL_FAM6_CORE2_MEROM:
|
||||||
|
case INTEL_FAM6_CORE2_MEROM_L:
|
||||||
|
case INTEL_FAM6_CORE2_PENRYN:
|
||||||
|
case INTEL_FAM6_CORE2_DUNNINGTON:
|
||||||
|
case INTEL_FAM6_NEHALEM:
|
||||||
|
case INTEL_FAM6_NEHALEM_G:
|
||||||
|
case INTEL_FAM6_NEHALEM_EP:
|
||||||
|
case INTEL_FAM6_NEHALEM_EX:
|
||||||
|
case INTEL_FAM6_WESTMERE:
|
||||||
|
case INTEL_FAM6_WESTMERE_EP:
|
||||||
|
case INTEL_FAM6_SANDYBRIDGE:
|
||||||
|
setup_clear_cpu_cap(X86_FEATURE_SELFSNOOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool ring3mwait_disabled __read_mostly;
|
static bool ring3mwait_disabled __read_mostly;
|
||||||
|
|
||||||
static int __init ring3mwait_disable(char *__unused)
|
static int __init ring3mwait_disable(char *__unused)
|
||||||
|
@ -304,6 +330,7 @@ static void early_init_intel(struct cpuinfo_x86 *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
check_mpx_erratum(c);
|
check_mpx_erratum(c);
|
||||||
|
check_memory_type_self_snoop_errata(c);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the number of SMT siblings early from the extended topology
|
* Get the number of SMT siblings early from the extended topology
|
||||||
|
|
|
@ -743,7 +743,15 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
|
||||||
/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
|
/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
|
||||||
cr0 = read_cr0() | X86_CR0_CD;
|
cr0 = read_cr0() | X86_CR0_CD;
|
||||||
write_cr0(cr0);
|
write_cr0(cr0);
|
||||||
wbinvd();
|
|
||||||
|
/*
|
||||||
|
* Cache flushing is the most time-consuming step when programming
|
||||||
|
* the MTRRs. Fortunately, as per the Intel Software Development
|
||||||
|
* Manual, we can skip it if the processor supports cache self-
|
||||||
|
* snooping.
|
||||||
|
*/
|
||||||
|
if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
|
||||||
|
wbinvd();
|
||||||
|
|
||||||
/* Save value of CR4 and clear Page Global Enable (bit 7) */
|
/* Save value of CR4 and clear Page Global Enable (bit 7) */
|
||||||
if (boot_cpu_has(X86_FEATURE_PGE)) {
|
if (boot_cpu_has(X86_FEATURE_PGE)) {
|
||||||
|
@ -760,7 +768,10 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
|
||||||
|
|
||||||
/* Disable MTRRs, and set the default type to uncached */
|
/* Disable MTRRs, and set the default type to uncached */
|
||||||
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
|
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
|
||||||
wbinvd();
|
|
||||||
|
/* Again, only flush caches if we have to. */
|
||||||
|
if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
|
||||||
|
wbinvd();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void post_set(void) __releases(set_atomicity_lock)
|
static void post_set(void) __releases(set_atomicity_lock)
|
||||||
|
|
|
@ -26,6 +26,10 @@ struct cpuid_bit {
|
||||||
static const struct cpuid_bit cpuid_bits[] = {
|
static const struct cpuid_bit cpuid_bits[] = {
|
||||||
{ X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 },
|
{ X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 },
|
||||||
{ X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 },
|
{ X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 },
|
||||||
|
{ X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 },
|
||||||
|
{ X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 },
|
||||||
|
{ X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 },
|
||||||
|
{ X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 },
|
||||||
{ X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 },
|
{ X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 },
|
||||||
{ X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 },
|
{ X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 },
|
||||||
{ X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 },
|
{ X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 },
|
||||||
|
|
|
@ -15,33 +15,66 @@
|
||||||
/* leaf 0xb SMT level */
|
/* leaf 0xb SMT level */
|
||||||
#define SMT_LEVEL 0
|
#define SMT_LEVEL 0
|
||||||
|
|
||||||
/* leaf 0xb sub-leaf types */
|
/* extended topology sub-leaf types */
|
||||||
#define INVALID_TYPE 0
|
#define INVALID_TYPE 0
|
||||||
#define SMT_TYPE 1
|
#define SMT_TYPE 1
|
||||||
#define CORE_TYPE 2
|
#define CORE_TYPE 2
|
||||||
|
#define DIE_TYPE 5
|
||||||
|
|
||||||
#define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
|
#define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
|
||||||
#define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
|
#define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
|
||||||
#define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
|
#define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
unsigned int __max_die_per_package __read_mostly = 1;
|
||||||
|
EXPORT_SYMBOL(__max_die_per_package);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if given CPUID extended toplogy "leaf" is implemented
|
||||||
|
*/
|
||||||
|
static int check_extended_topology_leaf(int leaf)
|
||||||
|
{
|
||||||
|
unsigned int eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Return best CPUID Extended Toplogy Leaf supported
|
||||||
|
*/
|
||||||
|
static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
if (c->cpuid_level >= 0x1f) {
|
||||||
|
if (check_extended_topology_leaf(0x1f) == 0)
|
||||||
|
return 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->cpuid_level >= 0xb) {
|
||||||
|
if (check_extended_topology_leaf(0xb) == 0)
|
||||||
|
return 0xb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int detect_extended_topology_early(struct cpuinfo_x86 *c)
|
int detect_extended_topology_early(struct cpuinfo_x86 *c)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
unsigned int eax, ebx, ecx, edx;
|
unsigned int eax, ebx, ecx, edx;
|
||||||
|
int leaf;
|
||||||
|
|
||||||
if (c->cpuid_level < 0xb)
|
leaf = detect_extended_topology_leaf(c);
|
||||||
return -1;
|
if (leaf < 0)
|
||||||
|
|
||||||
cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check if the cpuid leaf 0xb is actually implemented.
|
|
||||||
*/
|
|
||||||
if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
|
set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
|
||||||
|
|
||||||
|
cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
||||||
/*
|
/*
|
||||||
* initial apic id, which also represents 32-bit extended x2apic id.
|
* initial apic id, which also represents 32-bit extended x2apic id.
|
||||||
*/
|
*/
|
||||||
|
@ -52,7 +85,7 @@ int detect_extended_topology_early(struct cpuinfo_x86 *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for extended topology enumeration cpuid leaf 0xb and if it
|
* Check for extended topology enumeration cpuid leaf, and if it
|
||||||
* exists, use it for populating initial_apicid and cpu topology
|
* exists, use it for populating initial_apicid and cpu topology
|
||||||
* detection.
|
* detection.
|
||||||
*/
|
*/
|
||||||
|
@ -60,22 +93,28 @@ int detect_extended_topology(struct cpuinfo_x86 *c)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
unsigned int eax, ebx, ecx, edx, sub_index;
|
unsigned int eax, ebx, ecx, edx, sub_index;
|
||||||
unsigned int ht_mask_width, core_plus_mask_width;
|
unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
|
||||||
unsigned int core_select_mask, core_level_siblings;
|
unsigned int core_select_mask, core_level_siblings;
|
||||||
|
unsigned int die_select_mask, die_level_siblings;
|
||||||
|
int leaf;
|
||||||
|
|
||||||
if (detect_extended_topology_early(c) < 0)
|
leaf = detect_extended_topology_leaf(c);
|
||||||
|
if (leaf < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate HT related information from sub-leaf level 0.
|
* Populate HT related information from sub-leaf level 0.
|
||||||
*/
|
*/
|
||||||
cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
|
||||||
|
c->initial_apicid = edx;
|
||||||
core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
||||||
core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
||||||
|
die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
||||||
|
die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
||||||
|
|
||||||
sub_index = 1;
|
sub_index = 1;
|
||||||
do {
|
do {
|
||||||
cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
|
cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for the Core type in the implemented sub leaves.
|
* Check for the Core type in the implemented sub leaves.
|
||||||
|
@ -83,23 +122,34 @@ int detect_extended_topology(struct cpuinfo_x86 *c)
|
||||||
if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
|
if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
|
||||||
core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
||||||
core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
||||||
break;
|
die_level_siblings = core_level_siblings;
|
||||||
|
die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
||||||
|
}
|
||||||
|
if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
|
||||||
|
die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
|
||||||
|
die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_index++;
|
sub_index++;
|
||||||
} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
|
} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
|
||||||
|
|
||||||
core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
|
core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
|
||||||
|
die_select_mask = (~(-1 << die_plus_mask_width)) >>
|
||||||
|
core_plus_mask_width;
|
||||||
|
|
||||||
c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
|
c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
|
||||||
& core_select_mask;
|
ht_mask_width) & core_select_mask;
|
||||||
c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
|
c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
|
||||||
|
core_plus_mask_width) & die_select_mask;
|
||||||
|
c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
|
||||||
|
die_plus_mask_width);
|
||||||
/*
|
/*
|
||||||
* Reinit the apicid, now that we have extended initial_apicid.
|
* Reinit the apicid, now that we have extended initial_apicid.
|
||||||
*/
|
*/
|
||||||
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
|
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
|
||||||
|
|
||||||
c->x86_max_cores = (core_level_siblings / smp_num_siblings);
|
c->x86_max_cores = (core_level_siblings / smp_num_siblings);
|
||||||
|
__max_die_per_package = (die_level_siblings / core_level_siblings);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
200
arch/x86/kernel/cpu/umwait.c
Normal file
200
arch/x86/kernel/cpu/umwait.c
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
|
||||||
|
#include <asm/msr.h>
|
||||||
|
|
||||||
|
#define UMWAIT_C02_ENABLE 0
|
||||||
|
|
||||||
|
#define UMWAIT_CTRL_VAL(max_time, c02_disable) \
|
||||||
|
(((max_time) & MSR_IA32_UMWAIT_CONTROL_TIME_MASK) | \
|
||||||
|
((c02_disable) & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cache IA32_UMWAIT_CONTROL MSR. This is a systemwide control. By default,
|
||||||
|
* umwait max time is 100000 in TSC-quanta and C0.2 is enabled
|
||||||
|
*/
|
||||||
|
static u32 umwait_control_cached = UMWAIT_CTRL_VAL(100000, UMWAIT_C02_ENABLE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize access to umwait_control_cached and IA32_UMWAIT_CONTROL MSR in
|
||||||
|
* the sysfs write functions.
|
||||||
|
*/
|
||||||
|
static DEFINE_MUTEX(umwait_lock);
|
||||||
|
|
||||||
|
static void umwait_update_control_msr(void * unused)
|
||||||
|
{
|
||||||
|
lockdep_assert_irqs_disabled();
|
||||||
|
wrmsr(MSR_IA32_UMWAIT_CONTROL, READ_ONCE(umwait_control_cached), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CPU hotplug callback sets the control MSR to the global control
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* Disable interrupts so the read of umwait_control_cached and the WRMSR
|
||||||
|
* are protected against a concurrent sysfs write. Otherwise the sysfs
|
||||||
|
* write could update the cached value after it had been read on this CPU
|
||||||
|
* and issue the IPI before the old value had been written. The IPI would
|
||||||
|
* interrupt, write the new value and after return from IPI the previous
|
||||||
|
* value would be written by this CPU.
|
||||||
|
*
|
||||||
|
* With interrupts disabled the upcoming CPU either sees the new control
|
||||||
|
* value or the IPI is updating this CPU to the new control value after
|
||||||
|
* interrupts have been reenabled.
|
||||||
|
*/
|
||||||
|
static int umwait_cpu_online(unsigned int cpu)
|
||||||
|
{
|
||||||
|
local_irq_disable();
|
||||||
|
umwait_update_control_msr(NULL);
|
||||||
|
local_irq_enable();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On resume, restore IA32_UMWAIT_CONTROL MSR on the boot processor which
|
||||||
|
* is the only active CPU at this time. The MSR is set up on the APs via the
|
||||||
|
* CPU hotplug callback.
|
||||||
|
*
|
||||||
|
* This function is invoked on resume from suspend and hibernation. On
|
||||||
|
* resume from suspend the restore should be not required, but we neither
|
||||||
|
* trust the firmware nor does it matter if the same value is written
|
||||||
|
* again.
|
||||||
|
*/
|
||||||
|
static void umwait_syscore_resume(void)
|
||||||
|
{
|
||||||
|
umwait_update_control_msr(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops umwait_syscore_ops = {
|
||||||
|
.resume = umwait_syscore_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sysfs interface */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When bit 0 in IA32_UMWAIT_CONTROL MSR is 1, C0.2 is disabled.
|
||||||
|
* Otherwise, C0.2 is enabled.
|
||||||
|
*/
|
||||||
|
static inline bool umwait_ctrl_c02_enabled(u32 ctrl)
|
||||||
|
{
|
||||||
|
return !(ctrl & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 umwait_ctrl_max_time(u32 ctrl)
|
||||||
|
{
|
||||||
|
return ctrl & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void umwait_update_control(u32 maxtime, bool c02_enable)
|
||||||
|
{
|
||||||
|
u32 ctrl = maxtime & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
|
||||||
|
|
||||||
|
if (!c02_enable)
|
||||||
|
ctrl |= MSR_IA32_UMWAIT_CONTROL_C02_DISABLE;
|
||||||
|
|
||||||
|
WRITE_ONCE(umwait_control_cached, ctrl);
|
||||||
|
/* Propagate to all CPUs */
|
||||||
|
on_each_cpu(umwait_update_control_msr, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
enable_c02_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
u32 ctrl = READ_ONCE(umwait_control_cached);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", umwait_ctrl_c02_enabled(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t enable_c02_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
bool c02_enable;
|
||||||
|
u32 ctrl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtobool(buf, &c02_enable);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mutex_lock(&umwait_lock);
|
||||||
|
|
||||||
|
ctrl = READ_ONCE(umwait_control_cached);
|
||||||
|
if (c02_enable != umwait_ctrl_c02_enabled(ctrl))
|
||||||
|
umwait_update_control(ctrl, c02_enable);
|
||||||
|
|
||||||
|
mutex_unlock(&umwait_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RW(enable_c02);
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
max_time_show(struct device *kobj, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
u32 ctrl = READ_ONCE(umwait_control_cached);
|
||||||
|
|
||||||
|
return sprintf(buf, "%u\n", umwait_ctrl_max_time(ctrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t max_time_store(struct device *kobj,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
u32 max_time, ctrl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtou32(buf, 0, &max_time);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* bits[1:0] must be zero */
|
||||||
|
if (max_time & ~MSR_IA32_UMWAIT_CONTROL_TIME_MASK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&umwait_lock);
|
||||||
|
|
||||||
|
ctrl = READ_ONCE(umwait_control_cached);
|
||||||
|
if (max_time != umwait_ctrl_max_time(ctrl))
|
||||||
|
umwait_update_control(max_time, umwait_ctrl_c02_enabled(ctrl));
|
||||||
|
|
||||||
|
mutex_unlock(&umwait_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RW(max_time);
|
||||||
|
|
||||||
|
static struct attribute *umwait_attrs[] = {
|
||||||
|
&dev_attr_enable_c02.attr,
|
||||||
|
&dev_attr_max_time.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group umwait_attr_group = {
|
||||||
|
.attrs = umwait_attrs,
|
||||||
|
.name = "umwait_control",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init umwait_init(void)
|
||||||
|
{
|
||||||
|
struct device *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!boot_cpu_has(X86_FEATURE_WAITPKG))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "umwait:online",
|
||||||
|
umwait_cpu_online, NULL);
|
||||||
|
|
||||||
|
register_syscore_ops(&umwait_syscore_ops);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add umwait control interface. Ignore failure, so at least the
|
||||||
|
* default values are set up in case the machine manages to boot.
|
||||||
|
*/
|
||||||
|
dev = cpu_subsys.dev_root;
|
||||||
|
return sysfs_create_group(&dev->kobj, &umwait_attr_group);
|
||||||
|
}
|
||||||
|
device_initcall(umwait_init);
|
167
arch/x86/kernel/cpu/zhaoxin.c
Normal file
167
arch/x86/kernel/cpu/zhaoxin.c
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/sched/clock.h>
|
||||||
|
|
||||||
|
#include <asm/cpufeature.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#define MSR_ZHAOXIN_FCR57 0x00001257
|
||||||
|
|
||||||
|
#define ACE_PRESENT (1 << 6)
|
||||||
|
#define ACE_ENABLED (1 << 7)
|
||||||
|
#define ACE_FCR (1 << 7) /* MSR_ZHAOXIN_FCR */
|
||||||
|
|
||||||
|
#define RNG_PRESENT (1 << 2)
|
||||||
|
#define RNG_ENABLED (1 << 3)
|
||||||
|
#define RNG_ENABLE (1 << 8) /* MSR_ZHAOXIN_RNG */
|
||||||
|
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW 0x00200000
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS_VNMI 0x00400000
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS 0x80000000
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC 0x00000001
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS2_EPT 0x00000002
|
||||||
|
#define X86_VMX_FEATURE_PROC_CTLS2_VPID 0x00000020
|
||||||
|
|
||||||
|
static void init_zhaoxin_cap(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
u32 lo, hi;
|
||||||
|
|
||||||
|
/* Test for Extended Feature Flags presence */
|
||||||
|
if (cpuid_eax(0xC0000000) >= 0xC0000001) {
|
||||||
|
u32 tmp = cpuid_edx(0xC0000001);
|
||||||
|
|
||||||
|
/* Enable ACE unit, if present and disabled */
|
||||||
|
if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
|
||||||
|
rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||||
|
/* Enable ACE unit */
|
||||||
|
lo |= ACE_FCR;
|
||||||
|
wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||||
|
pr_info("CPU: Enabled ACE h/w crypto\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable RNG unit, if present and disabled */
|
||||||
|
if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
|
||||||
|
rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||||
|
/* Enable RNG unit */
|
||||||
|
lo |= RNG_ENABLE;
|
||||||
|
wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||||
|
pr_info("CPU: Enabled h/w RNG\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store Extended Feature Flags as word 5 of the CPU
|
||||||
|
* capability bit array
|
||||||
|
*/
|
||||||
|
c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->x86 >= 0x6)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
|
||||||
|
|
||||||
|
cpu_detect_cache_sizes(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void early_init_zhaoxin(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
if (c->x86 >= 0x6)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
set_cpu_cap(c, X86_FEATURE_SYSENTER32);
|
||||||
|
#endif
|
||||||
|
if (c->x86_power & (1 << 8)) {
|
||||||
|
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||||
|
set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->cpuid_level >= 0x00000001) {
|
||||||
|
u32 eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
|
||||||
|
/*
|
||||||
|
* If HTT (EDX[28]) is set EBX[16:23] contain the number of
|
||||||
|
* apicids which are reserved per package. Store the resulting
|
||||||
|
* shift value for the package management code.
|
||||||
|
*/
|
||||||
|
if (edx & (1U << 28))
|
||||||
|
c->x86_coreid_bits = get_count_order((ebx >> 16) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zhaoxin_detect_vmx_virtcap(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
u32 vmx_msr_low, vmx_msr_high, msr_ctl, msr_ctl2;
|
||||||
|
|
||||||
|
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, vmx_msr_low, vmx_msr_high);
|
||||||
|
msr_ctl = vmx_msr_high | vmx_msr_low;
|
||||||
|
|
||||||
|
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
|
||||||
|
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_VNMI)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_VNMI);
|
||||||
|
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS) {
|
||||||
|
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2,
|
||||||
|
vmx_msr_low, vmx_msr_high);
|
||||||
|
msr_ctl2 = vmx_msr_high | vmx_msr_low;
|
||||||
|
if ((msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC) &&
|
||||||
|
(msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW))
|
||||||
|
set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
|
||||||
|
if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_EPT)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_EPT);
|
||||||
|
if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VPID)
|
||||||
|
set_cpu_cap(c, X86_FEATURE_VPID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_zhaoxin(struct cpuinfo_x86 *c)
|
||||||
|
{
|
||||||
|
early_init_zhaoxin(c);
|
||||||
|
init_intel_cacheinfo(c);
|
||||||
|
detect_num_cpu_cores(c);
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
detect_ht(c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (c->cpuid_level > 9) {
|
||||||
|
unsigned int eax = cpuid_eax(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for version and the number of counters
|
||||||
|
* Version(eax[7:0]) can't be 0;
|
||||||
|
* Counters(eax[15:8]) should be greater than 1;
|
||||||
|
*/
|
||||||
|
if ((eax & 0xff) && (((eax >> 8) & 0xff) > 1))
|
||||||
|
set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->x86 >= 0x6)
|
||||||
|
init_zhaoxin_cap(c);
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cpu_has(c, X86_FEATURE_VMX))
|
||||||
|
zhaoxin_detect_vmx_virtcap(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
static unsigned int
|
||||||
|
zhaoxin_size_cache(struct cpuinfo_x86 *c, unsigned int size)
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct cpu_dev zhaoxin_cpu_dev = {
|
||||||
|
.c_vendor = "zhaoxin",
|
||||||
|
.c_ident = { " Shanghai " },
|
||||||
|
.c_early_init = early_init_zhaoxin,
|
||||||
|
.c_init = init_zhaoxin,
|
||||||
|
#ifdef CONFIG_X86_32
|
||||||
|
.legacy_cache_size = zhaoxin_size_cache,
|
||||||
|
#endif
|
||||||
|
.c_x86_vendor = X86_VENDOR_ZHAOXIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu_dev_register(zhaoxin_cpu_dev);
|
|
@ -397,22 +397,12 @@ static int putreg(struct task_struct *child,
|
||||||
case offsetof(struct user_regs_struct,fs_base):
|
case offsetof(struct user_regs_struct,fs_base):
|
||||||
if (value >= TASK_SIZE_MAX)
|
if (value >= TASK_SIZE_MAX)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
/*
|
x86_fsbase_write_task(child, value);
|
||||||
* When changing the FS base, use do_arch_prctl_64()
|
|
||||||
* to set the index to zero and to set the base
|
|
||||||
* as requested.
|
|
||||||
*/
|
|
||||||
if (child->thread.fsbase != value)
|
|
||||||
return do_arch_prctl_64(child, ARCH_SET_FS, value);
|
|
||||||
return 0;
|
return 0;
|
||||||
case offsetof(struct user_regs_struct,gs_base):
|
case offsetof(struct user_regs_struct,gs_base):
|
||||||
/*
|
|
||||||
* Exactly the same here as the %fs handling above.
|
|
||||||
*/
|
|
||||||
if (value >= TASK_SIZE_MAX)
|
if (value >= TASK_SIZE_MAX)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (child->thread.gsbase != value)
|
x86_gsbase_write_task(child, value);
|
||||||
return do_arch_prctl_64(child, ARCH_SET_GS, value);
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,10 @@ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
|
||||||
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
|
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
|
||||||
EXPORT_PER_CPU_SYMBOL(cpu_core_map);
|
EXPORT_PER_CPU_SYMBOL(cpu_core_map);
|
||||||
|
|
||||||
|
/* representing HT, core, and die siblings of each logical CPU */
|
||||||
|
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_die_map);
|
||||||
|
EXPORT_PER_CPU_SYMBOL(cpu_die_map);
|
||||||
|
|
||||||
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
|
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
|
||||||
|
|
||||||
/* Per CPU bogomips and other parameters */
|
/* Per CPU bogomips and other parameters */
|
||||||
|
@ -99,6 +103,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
|
||||||
unsigned int __max_logical_packages __read_mostly;
|
unsigned int __max_logical_packages __read_mostly;
|
||||||
EXPORT_SYMBOL(__max_logical_packages);
|
EXPORT_SYMBOL(__max_logical_packages);
|
||||||
static unsigned int logical_packages __read_mostly;
|
static unsigned int logical_packages __read_mostly;
|
||||||
|
static unsigned int logical_die __read_mostly;
|
||||||
|
|
||||||
/* Maximum number of SMT threads on any online core */
|
/* Maximum number of SMT threads on any online core */
|
||||||
int __read_mostly __max_smt_threads = 1;
|
int __read_mostly __max_smt_threads = 1;
|
||||||
|
@ -300,6 +305,26 @@ int topology_phys_to_logical_pkg(unsigned int phys_pkg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(topology_phys_to_logical_pkg);
|
EXPORT_SYMBOL(topology_phys_to_logical_pkg);
|
||||||
|
/**
|
||||||
|
* topology_phys_to_logical_die - Map a physical die id to logical
|
||||||
|
*
|
||||||
|
* Returns logical die id or -1 if not found
|
||||||
|
*/
|
||||||
|
int topology_phys_to_logical_die(unsigned int die_id, unsigned int cur_cpu)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
int proc_id = cpu_data(cur_cpu).phys_proc_id;
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
|
|
||||||
|
if (c->initialized && c->cpu_die_id == die_id &&
|
||||||
|
c->phys_proc_id == proc_id)
|
||||||
|
return c->logical_die_id;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(topology_phys_to_logical_die);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* topology_update_package_map - Update the physical to logical package map
|
* topology_update_package_map - Update the physical to logical package map
|
||||||
|
@ -324,6 +349,29 @@ int topology_update_package_map(unsigned int pkg, unsigned int cpu)
|
||||||
cpu_data(cpu).logical_proc_id = new;
|
cpu_data(cpu).logical_proc_id = new;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* topology_update_die_map - Update the physical to logical die map
|
||||||
|
* @die: The die id as retrieved via CPUID
|
||||||
|
* @cpu: The cpu for which this is updated
|
||||||
|
*/
|
||||||
|
int topology_update_die_map(unsigned int die, unsigned int cpu)
|
||||||
|
{
|
||||||
|
int new;
|
||||||
|
|
||||||
|
/* Already available somewhere? */
|
||||||
|
new = topology_phys_to_logical_die(die, cpu);
|
||||||
|
if (new >= 0)
|
||||||
|
goto found;
|
||||||
|
|
||||||
|
new = logical_die++;
|
||||||
|
if (new != die) {
|
||||||
|
pr_info("CPU %u Converting physical %u to logical die %u\n",
|
||||||
|
cpu, die, new);
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
cpu_data(cpu).logical_die_id = new;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void __init smp_store_boot_cpu_info(void)
|
void __init smp_store_boot_cpu_info(void)
|
||||||
{
|
{
|
||||||
|
@ -333,6 +381,7 @@ void __init smp_store_boot_cpu_info(void)
|
||||||
*c = boot_cpu_data;
|
*c = boot_cpu_data;
|
||||||
c->cpu_index = id;
|
c->cpu_index = id;
|
||||||
topology_update_package_map(c->phys_proc_id, id);
|
topology_update_package_map(c->phys_proc_id, id);
|
||||||
|
topology_update_die_map(c->cpu_die_id, id);
|
||||||
c->initialized = true;
|
c->initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +436,7 @@ static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
|
||||||
int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
|
int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
|
||||||
|
|
||||||
if (c->phys_proc_id == o->phys_proc_id &&
|
if (c->phys_proc_id == o->phys_proc_id &&
|
||||||
|
c->cpu_die_id == o->cpu_die_id &&
|
||||||
per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2)) {
|
per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2)) {
|
||||||
if (c->cpu_core_id == o->cpu_core_id)
|
if (c->cpu_core_id == o->cpu_core_id)
|
||||||
return topology_sane(c, o, "smt");
|
return topology_sane(c, o, "smt");
|
||||||
|
@ -398,6 +448,7 @@ static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (c->phys_proc_id == o->phys_proc_id &&
|
} else if (c->phys_proc_id == o->phys_proc_id &&
|
||||||
|
c->cpu_die_id == o->cpu_die_id &&
|
||||||
c->cpu_core_id == o->cpu_core_id) {
|
c->cpu_core_id == o->cpu_core_id) {
|
||||||
return topology_sane(c, o, "smt");
|
return topology_sane(c, o, "smt");
|
||||||
}
|
}
|
||||||
|
@ -460,6 +511,15 @@ static bool match_pkg(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool match_die(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
|
||||||
|
{
|
||||||
|
if ((c->phys_proc_id == o->phys_proc_id) &&
|
||||||
|
(c->cpu_die_id == o->cpu_die_id))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(CONFIG_SCHED_SMT) || defined(CONFIG_SCHED_MC)
|
#if defined(CONFIG_SCHED_SMT) || defined(CONFIG_SCHED_MC)
|
||||||
static inline int x86_sched_itmt_flags(void)
|
static inline int x86_sched_itmt_flags(void)
|
||||||
{
|
{
|
||||||
|
@ -522,6 +582,7 @@ void set_cpu_sibling_map(int cpu)
|
||||||
cpumask_set_cpu(cpu, topology_sibling_cpumask(cpu));
|
cpumask_set_cpu(cpu, topology_sibling_cpumask(cpu));
|
||||||
cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
|
cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
|
||||||
cpumask_set_cpu(cpu, topology_core_cpumask(cpu));
|
cpumask_set_cpu(cpu, topology_core_cpumask(cpu));
|
||||||
|
cpumask_set_cpu(cpu, topology_die_cpumask(cpu));
|
||||||
c->booted_cores = 1;
|
c->booted_cores = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -570,6 +631,9 @@ void set_cpu_sibling_map(int cpu)
|
||||||
}
|
}
|
||||||
if (match_pkg(c, o) && !topology_same_node(c, o))
|
if (match_pkg(c, o) && !topology_same_node(c, o))
|
||||||
x86_has_numa_in_package = true;
|
x86_has_numa_in_package = true;
|
||||||
|
|
||||||
|
if ((i == cpu) || (has_mp && match_die(c, o)))
|
||||||
|
link_mask(topology_die_cpumask, cpu, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
threads = cpumask_weight(topology_sibling_cpumask(cpu));
|
threads = cpumask_weight(topology_sibling_cpumask(cpu));
|
||||||
|
@ -1174,6 +1238,7 @@ static __init void disable_smp(void)
|
||||||
physid_set_mask_of_physid(0, &phys_cpu_present_map);
|
physid_set_mask_of_physid(0, &phys_cpu_present_map);
|
||||||
cpumask_set_cpu(0, topology_sibling_cpumask(0));
|
cpumask_set_cpu(0, topology_sibling_cpumask(0));
|
||||||
cpumask_set_cpu(0, topology_core_cpumask(0));
|
cpumask_set_cpu(0, topology_core_cpumask(0));
|
||||||
|
cpumask_set_cpu(0, topology_die_cpumask(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1269,6 +1334,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
for_each_possible_cpu(i) {
|
for_each_possible_cpu(i) {
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
|
||||||
|
zalloc_cpumask_var(&per_cpu(cpu_die_map, i), GFP_KERNEL);
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1489,6 +1555,8 @@ static void remove_siblinginfo(int cpu)
|
||||||
cpu_data(sibling).booted_cores--;
|
cpu_data(sibling).booted_cores--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for_each_cpu(sibling, topology_die_cpumask(cpu))
|
||||||
|
cpumask_clear_cpu(cpu, topology_die_cpumask(sibling));
|
||||||
for_each_cpu(sibling, topology_sibling_cpumask(cpu))
|
for_each_cpu(sibling, topology_sibling_cpumask(cpu))
|
||||||
cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
|
cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
|
||||||
for_each_cpu(sibling, cpu_llc_shared_mask(cpu))
|
for_each_cpu(sibling, cpu_llc_shared_mask(cpu))
|
||||||
|
@ -1496,6 +1564,7 @@ static void remove_siblinginfo(int cpu)
|
||||||
cpumask_clear(cpu_llc_shared_mask(cpu));
|
cpumask_clear(cpu_llc_shared_mask(cpu));
|
||||||
cpumask_clear(topology_sibling_cpumask(cpu));
|
cpumask_clear(topology_sibling_cpumask(cpu));
|
||||||
cpumask_clear(topology_core_cpumask(cpu));
|
cpumask_clear(topology_core_cpumask(cpu));
|
||||||
|
cpumask_clear(topology_die_cpumask(cpu));
|
||||||
c->cpu_core_id = 0;
|
c->cpu_core_id = 0;
|
||||||
c->booted_cores = 0;
|
c->booted_cores = 0;
|
||||||
cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
|
cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
|
||||||
|
|
|
@ -47,8 +47,6 @@ static const struct cpuid_reg reverse_cpuid[] = {
|
||||||
[CPUID_8000_0001_ECX] = {0x80000001, 0, CPUID_ECX},
|
[CPUID_8000_0001_ECX] = {0x80000001, 0, CPUID_ECX},
|
||||||
[CPUID_7_0_EBX] = { 7, 0, CPUID_EBX},
|
[CPUID_7_0_EBX] = { 7, 0, CPUID_EBX},
|
||||||
[CPUID_D_1_EAX] = { 0xd, 1, CPUID_EAX},
|
[CPUID_D_1_EAX] = { 0xd, 1, CPUID_EAX},
|
||||||
[CPUID_F_0_EDX] = { 0xf, 0, CPUID_EDX},
|
|
||||||
[CPUID_F_1_EDX] = { 0xf, 1, CPUID_EDX},
|
|
||||||
[CPUID_8000_0008_EBX] = {0x80000008, 0, CPUID_EBX},
|
[CPUID_8000_0008_EBX] = {0x80000008, 0, CPUID_EBX},
|
||||||
[CPUID_6_EAX] = { 6, 0, CPUID_EAX},
|
[CPUID_6_EAX] = { 6, 0, CPUID_EAX},
|
||||||
[CPUID_8000_000A_EDX] = {0x8000000a, 0, CPUID_EDX},
|
[CPUID_8000_000A_EDX] = {0x8000000a, 0, CPUID_EDX},
|
||||||
|
|
|
@ -251,6 +251,7 @@ static void __init xen_pv_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
for_each_possible_cpu(i) {
|
for_each_possible_cpu(i) {
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
|
||||||
|
zalloc_cpumask_var(&per_cpu(cpu_die_map, i), GFP_KERNEL);
|
||||||
zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
|
zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
|
||||||
}
|
}
|
||||||
set_cpu_sibling_map(0);
|
set_cpu_sibling_map(0);
|
||||||
|
|
|
@ -934,6 +934,13 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct elevator_type *e = q->elevator->type;
|
struct elevator_type *e = q->elevator->type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the parent directory has not been created yet, return, we will be
|
||||||
|
* called again later on and the directory/files will be created then.
|
||||||
|
*/
|
||||||
|
if (!q->debugfs_dir)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!e->queue_debugfs_attrs)
|
if (!e->queue_debugfs_attrs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ static void power_saving_mwait_init(void)
|
||||||
case X86_VENDOR_HYGON:
|
case X86_VENDOR_HYGON:
|
||||||
case X86_VENDOR_AMD:
|
case X86_VENDOR_AMD:
|
||||||
case X86_VENDOR_INTEL:
|
case X86_VENDOR_INTEL:
|
||||||
|
case X86_VENDOR_ZHAOXIN:
|
||||||
/*
|
/*
|
||||||
* AMD Fam10h TSC will tick in all
|
* AMD Fam10h TSC will tick in all
|
||||||
* C/P/S0/S1 states when this bit is set.
|
* C/P/S0/S1 states when this bit is set.
|
||||||
|
|
|
@ -196,6 +196,7 @@ static void tsc_check_state(int state)
|
||||||
case X86_VENDOR_AMD:
|
case X86_VENDOR_AMD:
|
||||||
case X86_VENDOR_INTEL:
|
case X86_VENDOR_INTEL:
|
||||||
case X86_VENDOR_CENTAUR:
|
case X86_VENDOR_CENTAUR:
|
||||||
|
case X86_VENDOR_ZHAOXIN:
|
||||||
/*
|
/*
|
||||||
* AMD Fam10h TSC will tick in all
|
* AMD Fam10h TSC will tick in all
|
||||||
* C/P/S0/S1 states when this bit is set.
|
* C/P/S0/S1 states when this bit is set.
|
||||||
|
|
|
@ -43,6 +43,9 @@ static ssize_t name##_list_show(struct device *dev, \
|
||||||
define_id_show_func(physical_package_id);
|
define_id_show_func(physical_package_id);
|
||||||
static DEVICE_ATTR_RO(physical_package_id);
|
static DEVICE_ATTR_RO(physical_package_id);
|
||||||
|
|
||||||
|
define_id_show_func(die_id);
|
||||||
|
static DEVICE_ATTR_RO(die_id);
|
||||||
|
|
||||||
define_id_show_func(core_id);
|
define_id_show_func(core_id);
|
||||||
static DEVICE_ATTR_RO(core_id);
|
static DEVICE_ATTR_RO(core_id);
|
||||||
|
|
||||||
|
@ -50,10 +53,22 @@ define_siblings_show_func(thread_siblings, sibling_cpumask);
|
||||||
static DEVICE_ATTR_RO(thread_siblings);
|
static DEVICE_ATTR_RO(thread_siblings);
|
||||||
static DEVICE_ATTR_RO(thread_siblings_list);
|
static DEVICE_ATTR_RO(thread_siblings_list);
|
||||||
|
|
||||||
|
define_siblings_show_func(core_cpus, sibling_cpumask);
|
||||||
|
static DEVICE_ATTR_RO(core_cpus);
|
||||||
|
static DEVICE_ATTR_RO(core_cpus_list);
|
||||||
|
|
||||||
define_siblings_show_func(core_siblings, core_cpumask);
|
define_siblings_show_func(core_siblings, core_cpumask);
|
||||||
static DEVICE_ATTR_RO(core_siblings);
|
static DEVICE_ATTR_RO(core_siblings);
|
||||||
static DEVICE_ATTR_RO(core_siblings_list);
|
static DEVICE_ATTR_RO(core_siblings_list);
|
||||||
|
|
||||||
|
define_siblings_show_func(die_cpus, die_cpumask);
|
||||||
|
static DEVICE_ATTR_RO(die_cpus);
|
||||||
|
static DEVICE_ATTR_RO(die_cpus_list);
|
||||||
|
|
||||||
|
define_siblings_show_func(package_cpus, core_cpumask);
|
||||||
|
static DEVICE_ATTR_RO(package_cpus);
|
||||||
|
static DEVICE_ATTR_RO(package_cpus_list);
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_BOOK
|
#ifdef CONFIG_SCHED_BOOK
|
||||||
define_id_show_func(book_id);
|
define_id_show_func(book_id);
|
||||||
static DEVICE_ATTR_RO(book_id);
|
static DEVICE_ATTR_RO(book_id);
|
||||||
|
@ -72,11 +87,18 @@ static DEVICE_ATTR_RO(drawer_siblings_list);
|
||||||
|
|
||||||
static struct attribute *default_attrs[] = {
|
static struct attribute *default_attrs[] = {
|
||||||
&dev_attr_physical_package_id.attr,
|
&dev_attr_physical_package_id.attr,
|
||||||
|
&dev_attr_die_id.attr,
|
||||||
&dev_attr_core_id.attr,
|
&dev_attr_core_id.attr,
|
||||||
&dev_attr_thread_siblings.attr,
|
&dev_attr_thread_siblings.attr,
|
||||||
&dev_attr_thread_siblings_list.attr,
|
&dev_attr_thread_siblings_list.attr,
|
||||||
|
&dev_attr_core_cpus.attr,
|
||||||
|
&dev_attr_core_cpus_list.attr,
|
||||||
&dev_attr_core_siblings.attr,
|
&dev_attr_core_siblings.attr,
|
||||||
&dev_attr_core_siblings_list.attr,
|
&dev_attr_core_siblings_list.attr,
|
||||||
|
&dev_attr_die_cpus.attr,
|
||||||
|
&dev_attr_die_cpus_list.attr,
|
||||||
|
&dev_attr_package_cpus.attr,
|
||||||
|
&dev_attr_package_cpus_list.attr,
|
||||||
#ifdef CONFIG_SCHED_BOOK
|
#ifdef CONFIG_SCHED_BOOK
|
||||||
&dev_attr_book_id.attr,
|
&dev_attr_book_id.attr,
|
||||||
&dev_attr_book_siblings.attr,
|
&dev_attr_book_siblings.attr,
|
||||||
|
|
|
@ -718,12 +718,13 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct jz4780_dma_dev *jzdma = data;
|
struct jz4780_dma_dev *jzdma = data;
|
||||||
unsigned int nb_channels = jzdma->soc_data->nb_channels;
|
unsigned int nb_channels = jzdma->soc_data->nb_channels;
|
||||||
uint32_t pending, dmac;
|
unsigned long pending;
|
||||||
|
uint32_t dmac;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
|
pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
|
||||||
|
|
||||||
for_each_set_bit(i, (unsigned long *)&pending, nb_channels) {
|
for_each_set_bit(i, &pending, nb_channels) {
|
||||||
if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]))
|
if (jz4780_dma_chan_irq(jzdma, &jzdma->chan[i]))
|
||||||
pending &= ~BIT(i);
|
pending &= ~BIT(i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -703,7 +703,7 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
|
||||||
spin_lock_irqsave(&sdma->channel_0_lock, flags);
|
spin_lock_irqsave(&sdma->channel_0_lock, flags);
|
||||||
|
|
||||||
bd0->mode.command = C0_SETPM;
|
bd0->mode.command = C0_SETPM;
|
||||||
bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
|
bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
|
||||||
bd0->mode.count = size / 2;
|
bd0->mode.count = size / 2;
|
||||||
bd0->buffer_addr = buf_phys;
|
bd0->buffer_addr = buf_phys;
|
||||||
bd0->ext_buffer_addr = address;
|
bd0->ext_buffer_addr = address;
|
||||||
|
@ -1025,7 +1025,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
|
||||||
context->gReg[7] = sdmac->watermark_level;
|
context->gReg[7] = sdmac->watermark_level;
|
||||||
|
|
||||||
bd0->mode.command = C0_SETDM;
|
bd0->mode.command = C0_SETDM;
|
||||||
bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
|
bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
|
||||||
bd0->mode.count = sizeof(*context) / 4;
|
bd0->mode.count = sizeof(*context) / 4;
|
||||||
bd0->buffer_addr = sdma->context_phys;
|
bd0->buffer_addr = sdma->context_phys;
|
||||||
bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
|
bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
|
||||||
|
@ -2096,27 +2096,6 @@ static int sdma_probe(struct platform_device *pdev)
|
||||||
if (pdata && pdata->script_addrs)
|
if (pdata && pdata->script_addrs)
|
||||||
sdma_add_scripts(sdma, pdata->script_addrs);
|
sdma_add_scripts(sdma, pdata->script_addrs);
|
||||||
|
|
||||||
if (pdata) {
|
|
||||||
ret = sdma_get_firmware(sdma, pdata->fw_name);
|
|
||||||
if (ret)
|
|
||||||
dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Because that device tree does not encode ROM script address,
|
|
||||||
* the RAM script in firmware is mandatory for device tree
|
|
||||||
* probe, otherwise it fails.
|
|
||||||
*/
|
|
||||||
ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
|
|
||||||
&fw_name);
|
|
||||||
if (ret)
|
|
||||||
dev_warn(&pdev->dev, "failed to get firmware name\n");
|
|
||||||
else {
|
|
||||||
ret = sdma_get_firmware(sdma, fw_name);
|
|
||||||
if (ret)
|
|
||||||
dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sdma->dma_device.dev = &pdev->dev;
|
sdma->dma_device.dev = &pdev->dev;
|
||||||
|
|
||||||
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
|
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
|
||||||
|
@ -2161,6 +2140,33 @@ static int sdma_probe(struct platform_device *pdev)
|
||||||
of_node_put(spba_bus);
|
of_node_put(spba_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kick off firmware loading as the very last step:
|
||||||
|
* attempt to load firmware only if we're not on the error path, because
|
||||||
|
* the firmware callback requires a fully functional and allocated sdma
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
|
if (pdata) {
|
||||||
|
ret = sdma_get_firmware(sdma, pdata->fw_name);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Because that device tree does not encode ROM script address,
|
||||||
|
* the RAM script in firmware is mandatory for device tree
|
||||||
|
* probe, otherwise it fails.
|
||||||
|
*/
|
||||||
|
ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
|
||||||
|
&fw_name);
|
||||||
|
if (ret) {
|
||||||
|
dev_warn(&pdev->dev, "failed to get firmware name\n");
|
||||||
|
} else {
|
||||||
|
ret = sdma_get_firmware(sdma, fw_name);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_register:
|
err_register:
|
||||||
|
|
|
@ -799,6 +799,9 @@ static u32 process_channel_irqs(struct bam_device *bdev)
|
||||||
/* Number of bytes available to read */
|
/* Number of bytes available to read */
|
||||||
avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1);
|
avail = CIRC_CNT(offset, bchan->head, MAX_DESCRIPTORS + 1);
|
||||||
|
|
||||||
|
if (offset < bchan->head)
|
||||||
|
avail--;
|
||||||
|
|
||||||
list_for_each_entry_safe(async_desc, tmp,
|
list_for_each_entry_safe(async_desc, tmp,
|
||||||
&bchan->desc_list, desc_node) {
|
&bchan->desc_list, desc_node) {
|
||||||
/* Not enough data to read */
|
/* Not enough data to read */
|
||||||
|
|
|
@ -96,10 +96,10 @@ struct platform_data {
|
||||||
struct device_attribute name_attr;
|
struct device_attribute name_attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keep track of how many package pointers we allocated in init() */
|
/* Keep track of how many zone pointers we allocated in init() */
|
||||||
static int max_packages __read_mostly;
|
static int max_zones __read_mostly;
|
||||||
/* Array of package pointers. Serialized by cpu hotplug lock */
|
/* Array of zone pointers. Serialized by cpu hotplug lock */
|
||||||
static struct platform_device **pkg_devices;
|
static struct platform_device **zone_devices;
|
||||||
|
|
||||||
static ssize_t show_label(struct device *dev,
|
static ssize_t show_label(struct device *dev,
|
||||||
struct device_attribute *devattr, char *buf)
|
struct device_attribute *devattr, char *buf)
|
||||||
|
@ -422,10 +422,10 @@ static int chk_ucode_version(unsigned int cpu)
|
||||||
|
|
||||||
static struct platform_device *coretemp_get_pdev(unsigned int cpu)
|
static struct platform_device *coretemp_get_pdev(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int pkgid = topology_logical_package_id(cpu);
|
int id = topology_logical_die_id(cpu);
|
||||||
|
|
||||||
if (pkgid >= 0 && pkgid < max_packages)
|
if (id >= 0 && id < max_zones)
|
||||||
return pkg_devices[pkgid];
|
return zone_devices[id];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ static int coretemp_probe(struct platform_device *pdev)
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct platform_data *pdata;
|
struct platform_data *pdata;
|
||||||
|
|
||||||
/* Initialize the per-package data structures */
|
/* Initialize the per-zone data structures */
|
||||||
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
|
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -566,13 +566,13 @@ static struct platform_driver coretemp_driver = {
|
||||||
|
|
||||||
static struct platform_device *coretemp_device_add(unsigned int cpu)
|
static struct platform_device *coretemp_device_add(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int err, pkgid = topology_logical_package_id(cpu);
|
int err, zoneid = topology_logical_die_id(cpu);
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
||||||
if (pkgid < 0)
|
if (zoneid < 0)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
pdev = platform_device_alloc(DRVNAME, pkgid);
|
pdev = platform_device_alloc(DRVNAME, zoneid);
|
||||||
if (!pdev)
|
if (!pdev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ static struct platform_device *coretemp_device_add(unsigned int cpu)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg_devices[pkgid] = pdev;
|
zone_devices[zoneid] = pdev;
|
||||||
return pdev;
|
return pdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,7 +690,7 @@ static int coretemp_cpu_offline(unsigned int cpu)
|
||||||
* the rest.
|
* the rest.
|
||||||
*/
|
*/
|
||||||
if (cpumask_empty(&pd->cpumask)) {
|
if (cpumask_empty(&pd->cpumask)) {
|
||||||
pkg_devices[topology_logical_package_id(cpu)] = NULL;
|
zone_devices[topology_logical_die_id(cpu)] = NULL;
|
||||||
platform_device_unregister(pdev);
|
platform_device_unregister(pdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -728,10 +728,10 @@ static int __init coretemp_init(void)
|
||||||
if (!x86_match_cpu(coretemp_ids))
|
if (!x86_match_cpu(coretemp_ids))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
max_packages = topology_max_packages();
|
max_zones = topology_max_packages() * topology_max_die_per_package();
|
||||||
pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *),
|
zone_devices = kcalloc(max_zones, sizeof(struct platform_device *),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!pkg_devices)
|
if (!zone_devices)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = platform_driver_register(&coretemp_driver);
|
err = platform_driver_register(&coretemp_driver);
|
||||||
|
@ -747,7 +747,7 @@ static int __init coretemp_init(void)
|
||||||
|
|
||||||
outdrv:
|
outdrv:
|
||||||
platform_driver_unregister(&coretemp_driver);
|
platform_driver_unregister(&coretemp_driver);
|
||||||
kfree(pkg_devices);
|
kfree(zone_devices);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
module_init(coretemp_init)
|
module_init(coretemp_init)
|
||||||
|
@ -756,7 +756,7 @@ static void __exit coretemp_exit(void)
|
||||||
{
|
{
|
||||||
cpuhp_remove_state(coretemp_hp_online);
|
cpuhp_remove_state(coretemp_hp_online);
|
||||||
platform_driver_unregister(&coretemp_driver);
|
platform_driver_unregister(&coretemp_driver);
|
||||||
kfree(pkg_devices);
|
kfree(zone_devices);
|
||||||
}
|
}
|
||||||
module_exit(coretemp_exit)
|
module_exit(coretemp_exit)
|
||||||
|
|
||||||
|
|
|
@ -166,12 +166,15 @@ struct rapl_domain {
|
||||||
#define power_zone_to_rapl_domain(_zone) \
|
#define power_zone_to_rapl_domain(_zone) \
|
||||||
container_of(_zone, struct rapl_domain, power_zone)
|
container_of(_zone, struct rapl_domain, power_zone)
|
||||||
|
|
||||||
|
/* maximum rapl package domain name: package-%d-die-%d */
|
||||||
|
#define PACKAGE_DOMAIN_NAME_LENGTH 30
|
||||||
|
|
||||||
/* Each physical package contains multiple domains, these are the common
|
|
||||||
|
/* Each rapl package contains multiple domains, these are the common
|
||||||
* data across RAPL domains within a package.
|
* data across RAPL domains within a package.
|
||||||
*/
|
*/
|
||||||
struct rapl_package {
|
struct rapl_package {
|
||||||
unsigned int id; /* physical package/socket id */
|
unsigned int id; /* logical die id, equals physical 1-die systems */
|
||||||
unsigned int nr_domains;
|
unsigned int nr_domains;
|
||||||
unsigned long domain_map; /* bit map of active domains */
|
unsigned long domain_map; /* bit map of active domains */
|
||||||
unsigned int power_unit;
|
unsigned int power_unit;
|
||||||
|
@ -186,6 +189,7 @@ struct rapl_package {
|
||||||
int lead_cpu; /* one active cpu per package for access */
|
int lead_cpu; /* one active cpu per package for access */
|
||||||
/* Track active cpus */
|
/* Track active cpus */
|
||||||
struct cpumask cpumask;
|
struct cpumask cpumask;
|
||||||
|
char name[PACKAGE_DOMAIN_NAME_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rapl_defaults {
|
struct rapl_defaults {
|
||||||
|
@ -252,8 +256,9 @@ static struct powercap_control_type *control_type; /* PowerCap Controller */
|
||||||
static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */
|
static struct rapl_domain *platform_rapl_domain; /* Platform (PSys) domain */
|
||||||
|
|
||||||
/* caller to ensure CPU hotplug lock is held */
|
/* caller to ensure CPU hotplug lock is held */
|
||||||
static struct rapl_package *find_package_by_id(int id)
|
static struct rapl_package *rapl_find_package_domain(int cpu)
|
||||||
{
|
{
|
||||||
|
int id = topology_logical_die_id(cpu);
|
||||||
struct rapl_package *rp;
|
struct rapl_package *rp;
|
||||||
|
|
||||||
list_for_each_entry(rp, &rapl_packages, plist) {
|
list_for_each_entry(rp, &rapl_packages, plist) {
|
||||||
|
@ -913,8 +918,8 @@ static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
|
||||||
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
|
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
|
||||||
rp->time_unit = 1000000 / (1 << value);
|
rp->time_unit = 1000000 / (1 << value);
|
||||||
|
|
||||||
pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n",
|
pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n",
|
||||||
rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
|
rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -938,8 +943,8 @@ static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
|
||||||
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
|
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
|
||||||
rp->time_unit = 1000000 / (1 << value);
|
rp->time_unit = 1000000 / (1 << value);
|
||||||
|
|
||||||
pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n",
|
pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n",
|
||||||
rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
|
rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1168,7 +1173,7 @@ static void rapl_update_domain_data(struct rapl_package *rp)
|
||||||
u64 val;
|
u64 val;
|
||||||
|
|
||||||
for (dmn = 0; dmn < rp->nr_domains; dmn++) {
|
for (dmn = 0; dmn < rp->nr_domains; dmn++) {
|
||||||
pr_debug("update package %d domain %s data\n", rp->id,
|
pr_debug("update %s domain %s data\n", rp->name,
|
||||||
rp->domains[dmn].name);
|
rp->domains[dmn].name);
|
||||||
/* exclude non-raw primitives */
|
/* exclude non-raw primitives */
|
||||||
for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) {
|
for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) {
|
||||||
|
@ -1193,7 +1198,6 @@ static void rapl_unregister_powercap(void)
|
||||||
static int rapl_package_register_powercap(struct rapl_package *rp)
|
static int rapl_package_register_powercap(struct rapl_package *rp)
|
||||||
{
|
{
|
||||||
struct rapl_domain *rd;
|
struct rapl_domain *rd;
|
||||||
char dev_name[17]; /* max domain name = 7 + 1 + 8 for int + 1 for null*/
|
|
||||||
struct powercap_zone *power_zone = NULL;
|
struct powercap_zone *power_zone = NULL;
|
||||||
int nr_pl, ret;
|
int nr_pl, ret;
|
||||||
|
|
||||||
|
@ -1204,20 +1208,16 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
|
||||||
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
|
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
|
||||||
if (rd->id == RAPL_DOMAIN_PACKAGE) {
|
if (rd->id == RAPL_DOMAIN_PACKAGE) {
|
||||||
nr_pl = find_nr_power_limit(rd);
|
nr_pl = find_nr_power_limit(rd);
|
||||||
pr_debug("register socket %d package domain %s\n",
|
pr_debug("register package domain %s\n", rp->name);
|
||||||
rp->id, rd->name);
|
|
||||||
memset(dev_name, 0, sizeof(dev_name));
|
|
||||||
snprintf(dev_name, sizeof(dev_name), "%s-%d",
|
|
||||||
rd->name, rp->id);
|
|
||||||
power_zone = powercap_register_zone(&rd->power_zone,
|
power_zone = powercap_register_zone(&rd->power_zone,
|
||||||
control_type,
|
control_type,
|
||||||
dev_name, NULL,
|
rp->name, NULL,
|
||||||
&zone_ops[rd->id],
|
&zone_ops[rd->id],
|
||||||
nr_pl,
|
nr_pl,
|
||||||
&constraint_ops);
|
&constraint_ops);
|
||||||
if (IS_ERR(power_zone)) {
|
if (IS_ERR(power_zone)) {
|
||||||
pr_debug("failed to register package, %d\n",
|
pr_debug("failed to register power zone %s\n",
|
||||||
rp->id);
|
rp->name);
|
||||||
return PTR_ERR(power_zone);
|
return PTR_ERR(power_zone);
|
||||||
}
|
}
|
||||||
/* track parent zone in per package/socket data */
|
/* track parent zone in per package/socket data */
|
||||||
|
@ -1243,8 +1243,8 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
|
||||||
&constraint_ops);
|
&constraint_ops);
|
||||||
|
|
||||||
if (IS_ERR(power_zone)) {
|
if (IS_ERR(power_zone)) {
|
||||||
pr_debug("failed to register power_zone, %d:%s:%s\n",
|
pr_debug("failed to register power_zone, %s:%s\n",
|
||||||
rp->id, rd->name, dev_name);
|
rp->name, rd->name);
|
||||||
ret = PTR_ERR(power_zone);
|
ret = PTR_ERR(power_zone);
|
||||||
goto err_cleanup;
|
goto err_cleanup;
|
||||||
}
|
}
|
||||||
|
@ -1257,7 +1257,7 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
|
||||||
* failed after the first domain setup.
|
* failed after the first domain setup.
|
||||||
*/
|
*/
|
||||||
while (--rd >= rp->domains) {
|
while (--rd >= rp->domains) {
|
||||||
pr_debug("unregister package %d domain %s\n", rp->id, rd->name);
|
pr_debug("unregister %s domain %s\n", rp->name, rd->name);
|
||||||
powercap_unregister_zone(control_type, &rd->power_zone);
|
powercap_unregister_zone(control_type, &rd->power_zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1288,7 +1288,7 @@ static int __init rapl_register_psys(void)
|
||||||
rd->rpl[0].name = pl1_name;
|
rd->rpl[0].name = pl1_name;
|
||||||
rd->rpl[1].prim_id = PL2_ENABLE;
|
rd->rpl[1].prim_id = PL2_ENABLE;
|
||||||
rd->rpl[1].name = pl2_name;
|
rd->rpl[1].name = pl2_name;
|
||||||
rd->rp = find_package_by_id(0);
|
rd->rp = rapl_find_package_domain(0);
|
||||||
|
|
||||||
power_zone = powercap_register_zone(&rd->power_zone, control_type,
|
power_zone = powercap_register_zone(&rd->power_zone, control_type,
|
||||||
"psys", NULL,
|
"psys", NULL,
|
||||||
|
@ -1367,8 +1367,8 @@ static void rapl_detect_powerlimit(struct rapl_domain *rd)
|
||||||
/* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
|
/* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
|
||||||
if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
|
if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
|
||||||
if (val64) {
|
if (val64) {
|
||||||
pr_info("RAPL package %d domain %s locked by BIOS\n",
|
pr_info("RAPL %s domain %s locked by BIOS\n",
|
||||||
rd->rp->id, rd->name);
|
rd->rp->name, rd->name);
|
||||||
rd->state |= DOMAIN_STATE_BIOS_LOCKED;
|
rd->state |= DOMAIN_STATE_BIOS_LOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1397,10 +1397,10 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
|
||||||
}
|
}
|
||||||
rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
|
rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
|
||||||
if (!rp->nr_domains) {
|
if (!rp->nr_domains) {
|
||||||
pr_debug("no valid rapl domains found in package %d\n", rp->id);
|
pr_debug("no valid rapl domains found in %s\n", rp->name);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
pr_debug("found %d domains on package %d\n", rp->nr_domains, rp->id);
|
pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
|
||||||
|
|
||||||
rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
|
rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
@ -1433,8 +1433,8 @@ static void rapl_remove_package(struct rapl_package *rp)
|
||||||
rd_package = rd;
|
rd_package = rd;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pr_debug("remove package, undo power limit on %d: %s\n",
|
pr_debug("remove package, undo power limit on %s: %s\n",
|
||||||
rp->id, rd->name);
|
rp->name, rd->name);
|
||||||
powercap_unregister_zone(control_type, &rd->power_zone);
|
powercap_unregister_zone(control_type, &rd->power_zone);
|
||||||
}
|
}
|
||||||
/* do parent zone last */
|
/* do parent zone last */
|
||||||
|
@ -1444,9 +1444,11 @@ static void rapl_remove_package(struct rapl_package *rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called from CPU hotplug notifier, hotplug lock held */
|
/* called from CPU hotplug notifier, hotplug lock held */
|
||||||
static struct rapl_package *rapl_add_package(int cpu, int pkgid)
|
static struct rapl_package *rapl_add_package(int cpu)
|
||||||
{
|
{
|
||||||
|
int id = topology_logical_die_id(cpu);
|
||||||
struct rapl_package *rp;
|
struct rapl_package *rp;
|
||||||
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
|
rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
|
||||||
|
@ -1454,9 +1456,16 @@ static struct rapl_package *rapl_add_package(int cpu, int pkgid)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
/* add the new package to the list */
|
/* add the new package to the list */
|
||||||
rp->id = pkgid;
|
rp->id = id;
|
||||||
rp->lead_cpu = cpu;
|
rp->lead_cpu = cpu;
|
||||||
|
|
||||||
|
if (topology_max_die_per_package() > 1)
|
||||||
|
snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH,
|
||||||
|
"package-%d-die-%d", c->phys_proc_id, c->cpu_die_id);
|
||||||
|
else
|
||||||
|
snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d",
|
||||||
|
c->phys_proc_id);
|
||||||
|
|
||||||
/* check if the package contains valid domains */
|
/* check if the package contains valid domains */
|
||||||
if (rapl_detect_domains(rp, cpu) ||
|
if (rapl_detect_domains(rp, cpu) ||
|
||||||
rapl_defaults->check_unit(rp, cpu)) {
|
rapl_defaults->check_unit(rp, cpu)) {
|
||||||
|
@ -1485,12 +1494,11 @@ static struct rapl_package *rapl_add_package(int cpu, int pkgid)
|
||||||
*/
|
*/
|
||||||
static int rapl_cpu_online(unsigned int cpu)
|
static int rapl_cpu_online(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int pkgid = topology_physical_package_id(cpu);
|
|
||||||
struct rapl_package *rp;
|
struct rapl_package *rp;
|
||||||
|
|
||||||
rp = find_package_by_id(pkgid);
|
rp = rapl_find_package_domain(cpu);
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
rp = rapl_add_package(cpu, pkgid);
|
rp = rapl_add_package(cpu);
|
||||||
if (IS_ERR(rp))
|
if (IS_ERR(rp))
|
||||||
return PTR_ERR(rp);
|
return PTR_ERR(rp);
|
||||||
}
|
}
|
||||||
|
@ -1500,11 +1508,10 @@ static int rapl_cpu_online(unsigned int cpu)
|
||||||
|
|
||||||
static int rapl_cpu_down_prep(unsigned int cpu)
|
static int rapl_cpu_down_prep(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int pkgid = topology_physical_package_id(cpu);
|
|
||||||
struct rapl_package *rp;
|
struct rapl_package *rp;
|
||||||
int lead_cpu;
|
int lead_cpu;
|
||||||
|
|
||||||
rp = find_package_by_id(pkgid);
|
rp = rapl_find_package_domain(cpu);
|
||||||
if (!rp)
|
if (!rp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,12 @@ static int chap_check_algorithm(const char *a_str)
|
||||||
return CHAP_DIGEST_UNKNOWN;
|
return CHAP_DIGEST_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void chap_close(struct iscsi_conn *conn)
|
||||||
|
{
|
||||||
|
kfree(conn->auth_protocol);
|
||||||
|
conn->auth_protocol = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct iscsi_chap *chap_server_open(
|
static struct iscsi_chap *chap_server_open(
|
||||||
struct iscsi_conn *conn,
|
struct iscsi_conn *conn,
|
||||||
struct iscsi_node_auth *auth,
|
struct iscsi_node_auth *auth,
|
||||||
|
@ -118,7 +124,7 @@ static struct iscsi_chap *chap_server_open(
|
||||||
case CHAP_DIGEST_UNKNOWN:
|
case CHAP_DIGEST_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
pr_err("Unsupported CHAP_A value\n");
|
pr_err("Unsupported CHAP_A value\n");
|
||||||
kfree(conn->auth_protocol);
|
chap_close(conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,19 +139,13 @@ static struct iscsi_chap *chap_server_open(
|
||||||
* Generate Challenge.
|
* Generate Challenge.
|
||||||
*/
|
*/
|
||||||
if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
|
if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
|
||||||
kfree(conn->auth_protocol);
|
chap_close(conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chap;
|
return chap;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chap_close(struct iscsi_conn *conn)
|
|
||||||
{
|
|
||||||
kfree(conn->auth_protocol);
|
|
||||||
conn->auth_protocol = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int chap_server_compute_md5(
|
static int chap_server_compute_md5(
|
||||||
struct iscsi_conn *conn,
|
struct iscsi_conn *conn,
|
||||||
struct iscsi_node_auth *auth,
|
struct iscsi_node_auth *auth,
|
||||||
|
|
|
@ -502,7 +502,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
|
||||||
|
|
||||||
/* Always in 512 byte units for Linux/Block */
|
/* Always in 512 byte units for Linux/Block */
|
||||||
block_lba += sg->length >> SECTOR_SHIFT;
|
block_lba += sg->length >> SECTOR_SHIFT;
|
||||||
sectors -= 1;
|
sectors -= sg->length >> SECTOR_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
iblock_submit_bios(&list);
|
iblock_submit_bios(&list);
|
||||||
|
|
|
@ -43,7 +43,7 @@ MODULE_PARM_DESC(notify_delay_ms,
|
||||||
*/
|
*/
|
||||||
#define MAX_NUMBER_OF_TRIPS 2
|
#define MAX_NUMBER_OF_TRIPS 2
|
||||||
|
|
||||||
struct pkg_device {
|
struct zone_device {
|
||||||
int cpu;
|
int cpu;
|
||||||
bool work_scheduled;
|
bool work_scheduled;
|
||||||
u32 tj_max;
|
u32 tj_max;
|
||||||
|
@ -58,10 +58,10 @@ static struct thermal_zone_params pkg_temp_tz_params = {
|
||||||
.no_hwmon = true,
|
.no_hwmon = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keep track of how many package pointers we allocated in init() */
|
/* Keep track of how many zone pointers we allocated in init() */
|
||||||
static int max_packages __read_mostly;
|
static int max_id __read_mostly;
|
||||||
/* Array of package pointers */
|
/* Array of zone pointers */
|
||||||
static struct pkg_device **packages;
|
static struct zone_device **zones;
|
||||||
/* Serializes interrupt notification, work and hotplug */
|
/* Serializes interrupt notification, work and hotplug */
|
||||||
static DEFINE_SPINLOCK(pkg_temp_lock);
|
static DEFINE_SPINLOCK(pkg_temp_lock);
|
||||||
/* Protects zone operation in the work function against hotplug removal */
|
/* Protects zone operation in the work function against hotplug removal */
|
||||||
|
@ -108,12 +108,12 @@ static int pkg_temp_debugfs_init(void)
|
||||||
*
|
*
|
||||||
* - Other callsites: Must hold pkg_temp_lock
|
* - Other callsites: Must hold pkg_temp_lock
|
||||||
*/
|
*/
|
||||||
static struct pkg_device *pkg_temp_thermal_get_dev(unsigned int cpu)
|
static struct zone_device *pkg_temp_thermal_get_dev(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int pkgid = topology_logical_package_id(cpu);
|
int id = topology_logical_die_id(cpu);
|
||||||
|
|
||||||
if (pkgid >= 0 && pkgid < max_packages)
|
if (id >= 0 && id < max_id)
|
||||||
return packages[pkgid];
|
return zones[id];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,12 +138,13 @@ static int get_tj_max(int cpu, u32 *tj_max)
|
||||||
|
|
||||||
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
|
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
|
||||||
{
|
{
|
||||||
struct pkg_device *pkgdev = tzd->devdata;
|
struct zone_device *zonedev = tzd->devdata;
|
||||||
u32 eax, edx;
|
u32 eax, edx;
|
||||||
|
|
||||||
rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_STATUS, &eax, &edx);
|
rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_STATUS,
|
||||||
|
&eax, &edx);
|
||||||
if (eax & 0x80000000) {
|
if (eax & 0x80000000) {
|
||||||
*temp = pkgdev->tj_max - ((eax >> 16) & 0x7f) * 1000;
|
*temp = zonedev->tj_max - ((eax >> 16) & 0x7f) * 1000;
|
||||||
pr_debug("sys_get_curr_temp %d\n", *temp);
|
pr_debug("sys_get_curr_temp %d\n", *temp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +154,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
|
||||||
static int sys_get_trip_temp(struct thermal_zone_device *tzd,
|
static int sys_get_trip_temp(struct thermal_zone_device *tzd,
|
||||||
int trip, int *temp)
|
int trip, int *temp)
|
||||||
{
|
{
|
||||||
struct pkg_device *pkgdev = tzd->devdata;
|
struct zone_device *zonedev = tzd->devdata;
|
||||||
unsigned long thres_reg_value;
|
unsigned long thres_reg_value;
|
||||||
u32 mask, shift, eax, edx;
|
u32 mask, shift, eax, edx;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -169,14 +170,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
|
||||||
shift = THERM_SHIFT_THRESHOLD0;
|
shift = THERM_SHIFT_THRESHOLD0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
||||||
&eax, &edx);
|
&eax, &edx);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
thres_reg_value = (eax & mask) >> shift;
|
thres_reg_value = (eax & mask) >> shift;
|
||||||
if (thres_reg_value)
|
if (thres_reg_value)
|
||||||
*temp = pkgdev->tj_max - thres_reg_value * 1000;
|
*temp = zonedev->tj_max - thres_reg_value * 1000;
|
||||||
else
|
else
|
||||||
*temp = 0;
|
*temp = 0;
|
||||||
pr_debug("sys_get_trip_temp %d\n", *temp);
|
pr_debug("sys_get_trip_temp %d\n", *temp);
|
||||||
|
@ -187,14 +188,14 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
|
||||||
static int
|
static int
|
||||||
sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
|
sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
|
||||||
{
|
{
|
||||||
struct pkg_device *pkgdev = tzd->devdata;
|
struct zone_device *zonedev = tzd->devdata;
|
||||||
u32 l, h, mask, shift, intr;
|
u32 l, h, mask, shift, intr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (trip >= MAX_NUMBER_OF_TRIPS || temp >= pkgdev->tj_max)
|
if (trip >= MAX_NUMBER_OF_TRIPS || temp >= zonedev->tj_max)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = rdmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
ret = rdmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
||||||
&l, &h);
|
&l, &h);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -216,11 +217,12 @@ sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
|
||||||
if (!temp) {
|
if (!temp) {
|
||||||
l &= ~intr;
|
l &= ~intr;
|
||||||
} else {
|
} else {
|
||||||
l |= (pkgdev->tj_max - temp)/1000 << shift;
|
l |= (zonedev->tj_max - temp)/1000 << shift;
|
||||||
l |= intr;
|
l |= intr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrmsr_on_cpu(pkgdev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
|
return wrmsr_on_cpu(zonedev->cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
||||||
|
l, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip,
|
static int sys_get_trip_type(struct thermal_zone_device *thermal, int trip,
|
||||||
|
@ -275,26 +277,26 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct thermal_zone_device *tzone = NULL;
|
struct thermal_zone_device *tzone = NULL;
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
struct pkg_device *pkgdev;
|
struct zone_device *zonedev;
|
||||||
u64 msr_val, wr_val;
|
u64 msr_val, wr_val;
|
||||||
|
|
||||||
mutex_lock(&thermal_zone_mutex);
|
mutex_lock(&thermal_zone_mutex);
|
||||||
spin_lock_irq(&pkg_temp_lock);
|
spin_lock_irq(&pkg_temp_lock);
|
||||||
++pkg_work_cnt;
|
++pkg_work_cnt;
|
||||||
|
|
||||||
pkgdev = pkg_temp_thermal_get_dev(cpu);
|
zonedev = pkg_temp_thermal_get_dev(cpu);
|
||||||
if (!pkgdev) {
|
if (!zonedev) {
|
||||||
spin_unlock_irq(&pkg_temp_lock);
|
spin_unlock_irq(&pkg_temp_lock);
|
||||||
mutex_unlock(&thermal_zone_mutex);
|
mutex_unlock(&thermal_zone_mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pkgdev->work_scheduled = false;
|
zonedev->work_scheduled = false;
|
||||||
|
|
||||||
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
|
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
|
||||||
wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
|
wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
|
||||||
if (wr_val != msr_val) {
|
if (wr_val != msr_val) {
|
||||||
wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val);
|
wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val);
|
||||||
tzone = pkgdev->tzone;
|
tzone = zonedev->tzone;
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_pkg_thres_interrupt();
|
enable_pkg_thres_interrupt();
|
||||||
|
@ -320,7 +322,7 @@ static void pkg_thermal_schedule_work(int cpu, struct delayed_work *work)
|
||||||
static int pkg_thermal_notify(u64 msr_val)
|
static int pkg_thermal_notify(u64 msr_val)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
struct pkg_device *pkgdev;
|
struct zone_device *zonedev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&pkg_temp_lock, flags);
|
spin_lock_irqsave(&pkg_temp_lock, flags);
|
||||||
|
@ -329,10 +331,10 @@ static int pkg_thermal_notify(u64 msr_val)
|
||||||
disable_pkg_thres_interrupt();
|
disable_pkg_thres_interrupt();
|
||||||
|
|
||||||
/* Work is per package, so scheduling it once is enough. */
|
/* Work is per package, so scheduling it once is enough. */
|
||||||
pkgdev = pkg_temp_thermal_get_dev(cpu);
|
zonedev = pkg_temp_thermal_get_dev(cpu);
|
||||||
if (pkgdev && !pkgdev->work_scheduled) {
|
if (zonedev && !zonedev->work_scheduled) {
|
||||||
pkgdev->work_scheduled = true;
|
zonedev->work_scheduled = true;
|
||||||
pkg_thermal_schedule_work(pkgdev->cpu, &pkgdev->work);
|
pkg_thermal_schedule_work(zonedev->cpu, &zonedev->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&pkg_temp_lock, flags);
|
spin_unlock_irqrestore(&pkg_temp_lock, flags);
|
||||||
|
@ -341,12 +343,12 @@ static int pkg_thermal_notify(u64 msr_val)
|
||||||
|
|
||||||
static int pkg_temp_thermal_device_add(unsigned int cpu)
|
static int pkg_temp_thermal_device_add(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int pkgid = topology_logical_package_id(cpu);
|
int id = topology_logical_die_id(cpu);
|
||||||
u32 tj_max, eax, ebx, ecx, edx;
|
u32 tj_max, eax, ebx, ecx, edx;
|
||||||
struct pkg_device *pkgdev;
|
struct zone_device *zonedev;
|
||||||
int thres_count, err;
|
int thres_count, err;
|
||||||
|
|
||||||
if (pkgid >= max_packages)
|
if (id >= max_id)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
cpuid(6, &eax, &ebx, &ecx, &edx);
|
cpuid(6, &eax, &ebx, &ecx, &edx);
|
||||||
|
@ -360,51 +362,51 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
pkgdev = kzalloc(sizeof(*pkgdev), GFP_KERNEL);
|
zonedev = kzalloc(sizeof(*zonedev), GFP_KERNEL);
|
||||||
if (!pkgdev)
|
if (!zonedev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&pkgdev->work, pkg_temp_thermal_threshold_work_fn);
|
INIT_DELAYED_WORK(&zonedev->work, pkg_temp_thermal_threshold_work_fn);
|
||||||
pkgdev->cpu = cpu;
|
zonedev->cpu = cpu;
|
||||||
pkgdev->tj_max = tj_max;
|
zonedev->tj_max = tj_max;
|
||||||
pkgdev->tzone = thermal_zone_device_register("x86_pkg_temp",
|
zonedev->tzone = thermal_zone_device_register("x86_pkg_temp",
|
||||||
thres_count,
|
thres_count,
|
||||||
(thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01,
|
(thres_count == MAX_NUMBER_OF_TRIPS) ? 0x03 : 0x01,
|
||||||
pkgdev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
|
zonedev, &tzone_ops, &pkg_temp_tz_params, 0, 0);
|
||||||
if (IS_ERR(pkgdev->tzone)) {
|
if (IS_ERR(zonedev->tzone)) {
|
||||||
err = PTR_ERR(pkgdev->tzone);
|
err = PTR_ERR(zonedev->tzone);
|
||||||
kfree(pkgdev);
|
kfree(zonedev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
/* Store MSR value for package thermal interrupt, to restore at exit */
|
/* Store MSR value for package thermal interrupt, to restore at exit */
|
||||||
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, pkgdev->msr_pkg_therm_low,
|
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low,
|
||||||
pkgdev->msr_pkg_therm_high);
|
zonedev->msr_pkg_therm_high);
|
||||||
|
|
||||||
cpumask_set_cpu(cpu, &pkgdev->cpumask);
|
cpumask_set_cpu(cpu, &zonedev->cpumask);
|
||||||
spin_lock_irq(&pkg_temp_lock);
|
spin_lock_irq(&pkg_temp_lock);
|
||||||
packages[pkgid] = pkgdev;
|
zones[id] = zonedev;
|
||||||
spin_unlock_irq(&pkg_temp_lock);
|
spin_unlock_irq(&pkg_temp_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pkg_thermal_cpu_offline(unsigned int cpu)
|
static int pkg_thermal_cpu_offline(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu);
|
struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu);
|
||||||
bool lastcpu, was_target;
|
bool lastcpu, was_target;
|
||||||
int target;
|
int target;
|
||||||
|
|
||||||
if (!pkgdev)
|
if (!zonedev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
target = cpumask_any_but(&pkgdev->cpumask, cpu);
|
target = cpumask_any_but(&zonedev->cpumask, cpu);
|
||||||
cpumask_clear_cpu(cpu, &pkgdev->cpumask);
|
cpumask_clear_cpu(cpu, &zonedev->cpumask);
|
||||||
lastcpu = target >= nr_cpu_ids;
|
lastcpu = target >= nr_cpu_ids;
|
||||||
/*
|
/*
|
||||||
* Remove the sysfs files, if this is the last cpu in the package
|
* Remove the sysfs files, if this is the last cpu in the package
|
||||||
* before doing further cleanups.
|
* before doing further cleanups.
|
||||||
*/
|
*/
|
||||||
if (lastcpu) {
|
if (lastcpu) {
|
||||||
struct thermal_zone_device *tzone = pkgdev->tzone;
|
struct thermal_zone_device *tzone = zonedev->tzone;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must protect against a work function calling
|
* We must protect against a work function calling
|
||||||
|
@ -413,7 +415,7 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
|
||||||
* won't try to call.
|
* won't try to call.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&thermal_zone_mutex);
|
mutex_lock(&thermal_zone_mutex);
|
||||||
pkgdev->tzone = NULL;
|
zonedev->tzone = NULL;
|
||||||
mutex_unlock(&thermal_zone_mutex);
|
mutex_unlock(&thermal_zone_mutex);
|
||||||
|
|
||||||
thermal_zone_device_unregister(tzone);
|
thermal_zone_device_unregister(tzone);
|
||||||
|
@ -427,8 +429,8 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
|
||||||
* one. When we drop the lock, then the interrupt notify function
|
* one. When we drop the lock, then the interrupt notify function
|
||||||
* will see the new target.
|
* will see the new target.
|
||||||
*/
|
*/
|
||||||
was_target = pkgdev->cpu == cpu;
|
was_target = zonedev->cpu == cpu;
|
||||||
pkgdev->cpu = target;
|
zonedev->cpu = target;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the last CPU in the package remove the package
|
* If this is the last CPU in the package remove the package
|
||||||
|
@ -437,23 +439,23 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
|
||||||
* worker will see the package anymore.
|
* worker will see the package anymore.
|
||||||
*/
|
*/
|
||||||
if (lastcpu) {
|
if (lastcpu) {
|
||||||
packages[topology_logical_package_id(cpu)] = NULL;
|
zones[topology_logical_die_id(cpu)] = NULL;
|
||||||
/* After this point nothing touches the MSR anymore. */
|
/* After this point nothing touches the MSR anymore. */
|
||||||
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
|
||||||
pkgdev->msr_pkg_therm_low, pkgdev->msr_pkg_therm_high);
|
zonedev->msr_pkg_therm_low, zonedev->msr_pkg_therm_high);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether there is work scheduled and whether the work is
|
* Check whether there is work scheduled and whether the work is
|
||||||
* targeted at the outgoing CPU.
|
* targeted at the outgoing CPU.
|
||||||
*/
|
*/
|
||||||
if (pkgdev->work_scheduled && was_target) {
|
if (zonedev->work_scheduled && was_target) {
|
||||||
/*
|
/*
|
||||||
* To cancel the work we need to drop the lock, otherwise
|
* To cancel the work we need to drop the lock, otherwise
|
||||||
* we might deadlock if the work needs to be flushed.
|
* we might deadlock if the work needs to be flushed.
|
||||||
*/
|
*/
|
||||||
spin_unlock_irq(&pkg_temp_lock);
|
spin_unlock_irq(&pkg_temp_lock);
|
||||||
cancel_delayed_work_sync(&pkgdev->work);
|
cancel_delayed_work_sync(&zonedev->work);
|
||||||
spin_lock_irq(&pkg_temp_lock);
|
spin_lock_irq(&pkg_temp_lock);
|
||||||
/*
|
/*
|
||||||
* If this is not the last cpu in the package and the work
|
* If this is not the last cpu in the package and the work
|
||||||
|
@ -461,21 +463,21 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
|
||||||
* need to reschedule the work, otherwise the interrupt
|
* need to reschedule the work, otherwise the interrupt
|
||||||
* stays disabled forever.
|
* stays disabled forever.
|
||||||
*/
|
*/
|
||||||
if (!lastcpu && pkgdev->work_scheduled)
|
if (!lastcpu && zonedev->work_scheduled)
|
||||||
pkg_thermal_schedule_work(target, &pkgdev->work);
|
pkg_thermal_schedule_work(target, &zonedev->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irq(&pkg_temp_lock);
|
spin_unlock_irq(&pkg_temp_lock);
|
||||||
|
|
||||||
/* Final cleanup if this is the last cpu */
|
/* Final cleanup if this is the last cpu */
|
||||||
if (lastcpu)
|
if (lastcpu)
|
||||||
kfree(pkgdev);
|
kfree(zonedev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pkg_thermal_cpu_online(unsigned int cpu)
|
static int pkg_thermal_cpu_online(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct pkg_device *pkgdev = pkg_temp_thermal_get_dev(cpu);
|
struct zone_device *zonedev = pkg_temp_thermal_get_dev(cpu);
|
||||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
|
|
||||||
/* Paranoia check */
|
/* Paranoia check */
|
||||||
|
@ -483,8 +485,8 @@ static int pkg_thermal_cpu_online(unsigned int cpu)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* If the package exists, nothing to do */
|
/* If the package exists, nothing to do */
|
||||||
if (pkgdev) {
|
if (zonedev) {
|
||||||
cpumask_set_cpu(cpu, &pkgdev->cpumask);
|
cpumask_set_cpu(cpu, &zonedev->cpumask);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return pkg_temp_thermal_device_add(cpu);
|
return pkg_temp_thermal_device_add(cpu);
|
||||||
|
@ -503,10 +505,10 @@ static int __init pkg_temp_thermal_init(void)
|
||||||
if (!x86_match_cpu(pkg_temp_thermal_ids))
|
if (!x86_match_cpu(pkg_temp_thermal_ids))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
max_packages = topology_max_packages();
|
max_id = topology_max_packages() * topology_max_die_per_package();
|
||||||
packages = kcalloc(max_packages, sizeof(struct pkg_device *),
|
zones = kcalloc(max_id, sizeof(struct zone_device *),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!packages)
|
if (!zones)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online",
|
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "thermal/x86_pkg:online",
|
||||||
|
@ -525,7 +527,7 @@ static int __init pkg_temp_thermal_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
kfree(packages);
|
kfree(zones);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
module_init(pkg_temp_thermal_init)
|
module_init(pkg_temp_thermal_init)
|
||||||
|
@ -537,7 +539,7 @@ static void __exit pkg_temp_thermal_exit(void)
|
||||||
|
|
||||||
cpuhp_remove_state(pkg_thermal_hp_state);
|
cpuhp_remove_state(pkg_thermal_hp_state);
|
||||||
debugfs_remove_recursive(debugfs);
|
debugfs_remove_recursive(debugfs);
|
||||||
kfree(packages);
|
kfree(zones);
|
||||||
}
|
}
|
||||||
module_exit(pkg_temp_thermal_exit)
|
module_exit(pkg_temp_thermal_exit)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ config DCACHE_WORD_ACCESS
|
||||||
|
|
||||||
config VALIDATE_FS_PARSER
|
config VALIDATE_FS_PARSER
|
||||||
bool "Validate filesystem parameter description"
|
bool "Validate filesystem parameter description"
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
Enable this to perform validation of the parameter description for a
|
Enable this to perform validation of the parameter description for a
|
||||||
filesystem when it is registered.
|
filesystem when it is registered.
|
||||||
|
|
|
@ -175,6 +175,26 @@ int sysfs_create_group(struct kobject *kobj,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sysfs_create_group);
|
EXPORT_SYMBOL_GPL(sysfs_create_group);
|
||||||
|
|
||||||
|
static int internal_create_groups(struct kobject *kobj, int update,
|
||||||
|
const struct attribute_group **groups)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!groups)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; groups[i]; i++) {
|
||||||
|
error = internal_create_group(kobj, update, groups[i]);
|
||||||
|
if (error) {
|
||||||
|
while (--i >= 0)
|
||||||
|
sysfs_remove_group(kobj, groups[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sysfs_create_groups - given a directory kobject, create a bunch of attribute groups
|
* sysfs_create_groups - given a directory kobject, create a bunch of attribute groups
|
||||||
* @kobj: The kobject to create the group on
|
* @kobj: The kobject to create the group on
|
||||||
|
@ -191,24 +211,28 @@ EXPORT_SYMBOL_GPL(sysfs_create_group);
|
||||||
int sysfs_create_groups(struct kobject *kobj,
|
int sysfs_create_groups(struct kobject *kobj,
|
||||||
const struct attribute_group **groups)
|
const struct attribute_group **groups)
|
||||||
{
|
{
|
||||||
int error = 0;
|
return internal_create_groups(kobj, 0, groups);
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!groups)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; groups[i]; i++) {
|
|
||||||
error = sysfs_create_group(kobj, groups[i]);
|
|
||||||
if (error) {
|
|
||||||
while (--i >= 0)
|
|
||||||
sysfs_remove_group(kobj, groups[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sysfs_create_groups);
|
EXPORT_SYMBOL_GPL(sysfs_create_groups);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sysfs_update_groups - given a directory kobject, create a bunch of attribute groups
|
||||||
|
* @kobj: The kobject to update the group on
|
||||||
|
* @groups: The attribute groups to update, NULL terminated
|
||||||
|
*
|
||||||
|
* This function update a bunch of attribute groups. If an error occurs when
|
||||||
|
* updating a group, all previously updated groups will be removed together
|
||||||
|
* with already existing (not updated) attributes.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or error code from sysfs_update_group on failure.
|
||||||
|
*/
|
||||||
|
int sysfs_update_groups(struct kobject *kobj,
|
||||||
|
const struct attribute_group **groups)
|
||||||
|
{
|
||||||
|
return internal_create_groups(kobj, 1, groups);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sysfs_update_groups);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sysfs_update_group - given a directory kobject, update an attribute group
|
* sysfs_update_group - given a directory kobject, update an attribute group
|
||||||
* @kobj: The kobject to update the group on
|
* @kobj: The kobject to update the group on
|
||||||
|
|
|
@ -256,6 +256,7 @@ struct pmu {
|
||||||
struct module *module;
|
struct module *module;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
const struct attribute_group **attr_groups;
|
const struct attribute_group **attr_groups;
|
||||||
|
const struct attribute_group **attr_update;
|
||||||
const char *name;
|
const char *name;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
@ -749,6 +750,11 @@ struct perf_event_context {
|
||||||
int nr_stat;
|
int nr_stat;
|
||||||
int nr_freq;
|
int nr_freq;
|
||||||
int rotate_disable;
|
int rotate_disable;
|
||||||
|
/*
|
||||||
|
* Set when nr_events != nr_active, except tolerant to events not
|
||||||
|
* necessary to be active due to scheduling constraints, such as cgroups.
|
||||||
|
*/
|
||||||
|
int rotate_necessary;
|
||||||
refcount_t refcount;
|
refcount_t refcount;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,8 @@ int __must_check sysfs_create_group(struct kobject *kobj,
|
||||||
const struct attribute_group *grp);
|
const struct attribute_group *grp);
|
||||||
int __must_check sysfs_create_groups(struct kobject *kobj,
|
int __must_check sysfs_create_groups(struct kobject *kobj,
|
||||||
const struct attribute_group **groups);
|
const struct attribute_group **groups);
|
||||||
|
int __must_check sysfs_update_groups(struct kobject *kobj,
|
||||||
|
const struct attribute_group **groups);
|
||||||
int sysfs_update_group(struct kobject *kobj,
|
int sysfs_update_group(struct kobject *kobj,
|
||||||
const struct attribute_group *grp);
|
const struct attribute_group *grp);
|
||||||
void sysfs_remove_group(struct kobject *kobj,
|
void sysfs_remove_group(struct kobject *kobj,
|
||||||
|
@ -433,6 +435,12 @@ static inline int sysfs_create_groups(struct kobject *kobj,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int sysfs_update_groups(struct kobject *kobj,
|
||||||
|
const struct attribute_group **groups)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int sysfs_update_group(struct kobject *kobj,
|
static inline int sysfs_update_group(struct kobject *kobj,
|
||||||
const struct attribute_group *grp)
|
const struct attribute_group *grp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,6 +184,9 @@ static inline int cpu_to_mem(int cpu)
|
||||||
#ifndef topology_physical_package_id
|
#ifndef topology_physical_package_id
|
||||||
#define topology_physical_package_id(cpu) ((void)(cpu), -1)
|
#define topology_physical_package_id(cpu) ((void)(cpu), -1)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef topology_die_id
|
||||||
|
#define topology_die_id(cpu) ((void)(cpu), -1)
|
||||||
|
#endif
|
||||||
#ifndef topology_core_id
|
#ifndef topology_core_id
|
||||||
#define topology_core_id(cpu) ((void)(cpu), 0)
|
#define topology_core_id(cpu) ((void)(cpu), 0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -193,6 +196,9 @@ static inline int cpu_to_mem(int cpu)
|
||||||
#ifndef topology_core_cpumask
|
#ifndef topology_core_cpumask
|
||||||
#define topology_core_cpumask(cpu) cpumask_of(cpu)
|
#define topology_core_cpumask(cpu) cpumask_of(cpu)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef topology_die_cpumask
|
||||||
|
#define topology_die_cpumask(cpu) cpumask_of(cpu)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_SMT
|
#ifdef CONFIG_SCHED_SMT
|
||||||
static inline const struct cpumask *cpu_smt_mask(int cpu)
|
static inline const struct cpumask *cpu_smt_mask(int cpu)
|
||||||
|
|
|
@ -2952,6 +2952,12 @@ static void ctx_sched_out(struct perf_event_context *ctx,
|
||||||
if (!ctx->nr_active || !(is_active & EVENT_ALL))
|
if (!ctx->nr_active || !(is_active & EVENT_ALL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we had been multiplexing, no rotations are necessary, now no events
|
||||||
|
* are active.
|
||||||
|
*/
|
||||||
|
ctx->rotate_necessary = 0;
|
||||||
|
|
||||||
perf_pmu_disable(ctx->pmu);
|
perf_pmu_disable(ctx->pmu);
|
||||||
if (is_active & EVENT_PINNED) {
|
if (is_active & EVENT_PINNED) {
|
||||||
list_for_each_entry_safe(event, tmp, &ctx->pinned_active, active_list)
|
list_for_each_entry_safe(event, tmp, &ctx->pinned_active, active_list)
|
||||||
|
@ -3319,10 +3325,13 @@ static int flexible_sched_in(struct perf_event *event, void *data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (group_can_go_on(event, sid->cpuctx, sid->can_add_hw)) {
|
if (group_can_go_on(event, sid->cpuctx, sid->can_add_hw)) {
|
||||||
if (!group_sched_in(event, sid->cpuctx, sid->ctx))
|
int ret = group_sched_in(event, sid->cpuctx, sid->ctx);
|
||||||
list_add_tail(&event->active_list, &sid->ctx->flexible_active);
|
if (ret) {
|
||||||
else
|
|
||||||
sid->can_add_hw = 0;
|
sid->can_add_hw = 0;
|
||||||
|
sid->ctx->rotate_necessary = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
list_add_tail(&event->active_list, &sid->ctx->flexible_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3690,24 +3699,17 @@ ctx_first_active(struct perf_event_context *ctx)
|
||||||
static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
|
static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
|
||||||
{
|
{
|
||||||
struct perf_event *cpu_event = NULL, *task_event = NULL;
|
struct perf_event *cpu_event = NULL, *task_event = NULL;
|
||||||
bool cpu_rotate = false, task_rotate = false;
|
struct perf_event_context *task_ctx = NULL;
|
||||||
struct perf_event_context *ctx = NULL;
|
int cpu_rotate, task_rotate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we run this from IRQ context, nobody can install new
|
* Since we run this from IRQ context, nobody can install new
|
||||||
* events, thus the event count values are stable.
|
* events, thus the event count values are stable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cpuctx->ctx.nr_events) {
|
cpu_rotate = cpuctx->ctx.rotate_necessary;
|
||||||
if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
|
task_ctx = cpuctx->task_ctx;
|
||||||
cpu_rotate = true;
|
task_rotate = task_ctx ? task_ctx->rotate_necessary : 0;
|
||||||
}
|
|
||||||
|
|
||||||
ctx = cpuctx->task_ctx;
|
|
||||||
if (ctx && ctx->nr_events) {
|
|
||||||
if (ctx->nr_events != ctx->nr_active)
|
|
||||||
task_rotate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cpu_rotate || task_rotate))
|
if (!(cpu_rotate || task_rotate))
|
||||||
return false;
|
return false;
|
||||||
|
@ -3716,7 +3718,7 @@ static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
|
||||||
perf_pmu_disable(cpuctx->ctx.pmu);
|
perf_pmu_disable(cpuctx->ctx.pmu);
|
||||||
|
|
||||||
if (task_rotate)
|
if (task_rotate)
|
||||||
task_event = ctx_first_active(ctx);
|
task_event = ctx_first_active(task_ctx);
|
||||||
if (cpu_rotate)
|
if (cpu_rotate)
|
||||||
cpu_event = ctx_first_active(&cpuctx->ctx);
|
cpu_event = ctx_first_active(&cpuctx->ctx);
|
||||||
|
|
||||||
|
@ -3724,17 +3726,17 @@ static bool perf_rotate_context(struct perf_cpu_context *cpuctx)
|
||||||
* As per the order given at ctx_resched() first 'pop' task flexible
|
* As per the order given at ctx_resched() first 'pop' task flexible
|
||||||
* and then, if needed CPU flexible.
|
* and then, if needed CPU flexible.
|
||||||
*/
|
*/
|
||||||
if (task_event || (ctx && cpu_event))
|
if (task_event || (task_ctx && cpu_event))
|
||||||
ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE);
|
ctx_sched_out(task_ctx, cpuctx, EVENT_FLEXIBLE);
|
||||||
if (cpu_event)
|
if (cpu_event)
|
||||||
cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
|
cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
|
||||||
|
|
||||||
if (task_event)
|
if (task_event)
|
||||||
rotate_ctx(ctx, task_event);
|
rotate_ctx(task_ctx, task_event);
|
||||||
if (cpu_event)
|
if (cpu_event)
|
||||||
rotate_ctx(&cpuctx->ctx, cpu_event);
|
rotate_ctx(&cpuctx->ctx, cpu_event);
|
||||||
|
|
||||||
perf_event_sched_in(cpuctx, ctx, current);
|
perf_event_sched_in(cpuctx, task_ctx, current);
|
||||||
|
|
||||||
perf_pmu_enable(cpuctx->ctx.pmu);
|
perf_pmu_enable(cpuctx->ctx.pmu);
|
||||||
perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
|
perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
|
||||||
|
@ -8535,9 +8537,9 @@ static int perf_tp_event_match(struct perf_event *event,
|
||||||
if (event->hw.state & PERF_HES_STOPPED)
|
if (event->hw.state & PERF_HES_STOPPED)
|
||||||
return 0;
|
return 0;
|
||||||
/*
|
/*
|
||||||
* All tracepoints are from kernel-space.
|
* If exclude_kernel, only trace user-space tracepoints (uprobes)
|
||||||
*/
|
*/
|
||||||
if (event->attr.exclude_kernel)
|
if (event->attr.exclude_kernel && !user_mode(regs))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!perf_tp_filter_match(event, data))
|
if (!perf_tp_filter_match(event, data))
|
||||||
|
@ -9877,6 +9879,12 @@ static int pmu_dev_alloc(struct pmu *pmu)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto del_dev;
|
goto del_dev;
|
||||||
|
|
||||||
|
if (pmu->attr_update)
|
||||||
|
ret = sysfs_update_groups(&pmu->dev->kobj, pmu->attr_update);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto del_dev;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -1336,7 +1336,7 @@ static inline void init_trace_event_call(struct trace_uprobe *tu,
|
||||||
call->event.funcs = &uprobe_funcs;
|
call->event.funcs = &uprobe_funcs;
|
||||||
call->class->define_fields = uprobe_event_define_fields;
|
call->class->define_fields = uprobe_event_define_fields;
|
||||||
|
|
||||||
call->flags = TRACE_EVENT_FL_UPROBE;
|
call->flags = TRACE_EVENT_FL_UPROBE | TRACE_EVENT_FL_CAP_ANY;
|
||||||
call->class->reg = trace_uprobe_register;
|
call->class->reg = trace_uprobe_register;
|
||||||
call->data = tu;
|
call->data = tu;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ FEATURE_TESTS_BASIC := \
|
||||||
libpython \
|
libpython \
|
||||||
libpython-version \
|
libpython-version \
|
||||||
libslang \
|
libslang \
|
||||||
|
libslang-include-subdir \
|
||||||
libcrypto \
|
libcrypto \
|
||||||
libunwind \
|
libunwind \
|
||||||
pthread-attr-setaffinity-np \
|
pthread-attr-setaffinity-np \
|
||||||
|
@ -114,7 +115,6 @@ FEATURE_DISPLAY ?= \
|
||||||
numa_num_possible_cpus \
|
numa_num_possible_cpus \
|
||||||
libperl \
|
libperl \
|
||||||
libpython \
|
libpython \
|
||||||
libslang \
|
|
||||||
libcrypto \
|
libcrypto \
|
||||||
libunwind \
|
libunwind \
|
||||||
libdw-dwarf-unwind \
|
libdw-dwarf-unwind \
|
||||||
|
|
|
@ -31,6 +31,7 @@ FILES= \
|
||||||
test-libpython.bin \
|
test-libpython.bin \
|
||||||
test-libpython-version.bin \
|
test-libpython-version.bin \
|
||||||
test-libslang.bin \
|
test-libslang.bin \
|
||||||
|
test-libslang-include-subdir.bin \
|
||||||
test-libcrypto.bin \
|
test-libcrypto.bin \
|
||||||
test-libunwind.bin \
|
test-libunwind.bin \
|
||||||
test-libunwind-debug-frame.bin \
|
test-libunwind-debug-frame.bin \
|
||||||
|
@ -182,7 +183,10 @@ $(OUTPUT)test-libaudit.bin:
|
||||||
$(BUILD) -laudit
|
$(BUILD) -laudit
|
||||||
|
|
||||||
$(OUTPUT)test-libslang.bin:
|
$(OUTPUT)test-libslang.bin:
|
||||||
$(BUILD) -I/usr/include/slang -lslang
|
$(BUILD) -lslang
|
||||||
|
|
||||||
|
$(OUTPUT)test-libslang-include-subdir.bin:
|
||||||
|
$(BUILD) -lslang
|
||||||
|
|
||||||
$(OUTPUT)test-libcrypto.bin:
|
$(OUTPUT)test-libcrypto.bin:
|
||||||
$(BUILD) -lcrypto
|
$(BUILD) -lcrypto
|
||||||
|
|
|
@ -186,7 +186,7 @@
|
||||||
# include "test-disassembler-four-args.c"
|
# include "test-disassembler-four-args.c"
|
||||||
#undef main
|
#undef main
|
||||||
|
|
||||||
#define main main_test_zstd
|
#define main main_test_libzstd
|
||||||
# include "test-libzstd.c"
|
# include "test-libzstd.c"
|
||||||
#undef main
|
#undef main
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
7
tools/build/feature/test-libslang-include-subdir.c
Normal file
7
tools/build/feature/test-libslang-include-subdir.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <slang/slang.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return SLsmg_init_smg();
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
|
||||||
|
|
75
tools/include/linux/ctype.h
Normal file
75
tools/include/linux/ctype.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef _LINUX_CTYPE_H
|
||||||
|
#define _LINUX_CTYPE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE! This ctype does not handle EOF like the standard C
|
||||||
|
* library is required to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _U 0x01 /* upper */
|
||||||
|
#define _L 0x02 /* lower */
|
||||||
|
#define _D 0x04 /* digit */
|
||||||
|
#define _C 0x08 /* cntrl */
|
||||||
|
#define _P 0x10 /* punct */
|
||||||
|
#define _S 0x20 /* white space (space/lf/tab) */
|
||||||
|
#define _X 0x40 /* hex digit */
|
||||||
|
#define _SP 0x80 /* hard space (0x20) */
|
||||||
|
|
||||||
|
extern const unsigned char _ctype[];
|
||||||
|
|
||||||
|
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
|
||||||
|
|
||||||
|
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
|
||||||
|
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
|
||||||
|
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
|
||||||
|
static inline int __isdigit(int c)
|
||||||
|
{
|
||||||
|
return '0' <= c && c <= '9';
|
||||||
|
}
|
||||||
|
#define isdigit(c) __isdigit(c)
|
||||||
|
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
|
||||||
|
#define islower(c) ((__ismask(c)&(_L)) != 0)
|
||||||
|
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
|
||||||
|
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
|
||||||
|
/* Note: isspace() must return false for %NUL-terminator */
|
||||||
|
#define isspace(c) ((__ismask(c)&(_S)) != 0)
|
||||||
|
#define isupper(c) ((__ismask(c)&(_U)) != 0)
|
||||||
|
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
|
||||||
|
|
||||||
|
#define isascii(c) (((unsigned char)(c))<=0x7f)
|
||||||
|
#define toascii(c) (((unsigned char)(c))&0x7f)
|
||||||
|
|
||||||
|
static inline unsigned char __tolower(unsigned char c)
|
||||||
|
{
|
||||||
|
if (isupper(c))
|
||||||
|
c -= 'A'-'a';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned char __toupper(unsigned char c)
|
||||||
|
{
|
||||||
|
if (islower(c))
|
||||||
|
c -= 'a'-'A';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define tolower(c) __tolower(c)
|
||||||
|
#define toupper(c) __toupper(c)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fast implementation of tolower() for internal usage. Do not use in your
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
static inline char _tolower(const char c)
|
||||||
|
{
|
||||||
|
return c | 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fast check for octal digit */
|
||||||
|
static inline int isodigit(const char c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '7';
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -102,6 +102,7 @@
|
||||||
|
|
||||||
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
||||||
int scnprintf(char * buf, size_t size, const char * fmt, ...);
|
int scnprintf(char * buf, size_t size, const char * fmt, ...);
|
||||||
|
int scnprintf_pad(char * buf, size_t size, const char * fmt, ...);
|
||||||
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
void *memdup(const void *src, size_t len);
|
void *memdup(const void *src, size_t len);
|
||||||
|
|
||||||
|
char **argv_split(const char *str, int *argcp);
|
||||||
|
void argv_free(char **argv);
|
||||||
|
|
||||||
int strtobool(const char *s, bool *res);
|
int strtobool(const char *s, bool *res);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -19,6 +22,8 @@ extern size_t strlcpy(char *dest, const char *src, size_t size);
|
||||||
|
|
||||||
char *str_error_r(int errnum, char *buf, size_t buflen);
|
char *str_error_r(int errnum, char *buf, size_t buflen);
|
||||||
|
|
||||||
|
char *strreplace(char *s, char old, char new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* strstarts - does @str start with @prefix?
|
* strstarts - does @str start with @prefix?
|
||||||
* @str: string to examine
|
* @str: string to examine
|
||||||
|
@ -29,4 +34,8 @@ static inline bool strstarts(const char *str, const char *prefix)
|
||||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _LINUX_STRING_H_ */
|
extern char * __must_check skip_spaces(const char *);
|
||||||
|
|
||||||
|
extern char *strim(char *);
|
||||||
|
|
||||||
|
#endif /* _TOOLS_LINUX_STRING_H_ */
|
||||||
|
|
100
tools/lib/argv_split.c
Normal file
100
tools/lib/argv_split.c
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Helper function for splitting a string into an argv-like array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
static const char *skip_arg(const char *cp)
|
||||||
|
{
|
||||||
|
while (*cp && !isspace(*cp))
|
||||||
|
cp++;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int count_argc(const char *str)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
str = skip_spaces(str);
|
||||||
|
if (*str) {
|
||||||
|
count++;
|
||||||
|
str = skip_arg(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* argv_free - free an argv
|
||||||
|
* @argv - the argument vector to be freed
|
||||||
|
*
|
||||||
|
* Frees an argv and the strings it points to.
|
||||||
|
*/
|
||||||
|
void argv_free(char **argv)
|
||||||
|
{
|
||||||
|
char **p;
|
||||||
|
for (p = argv; *p; p++) {
|
||||||
|
free(*p);
|
||||||
|
*p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* argv_split - split a string at whitespace, returning an argv
|
||||||
|
* @str: the string to be split
|
||||||
|
* @argcp: returned argument count
|
||||||
|
*
|
||||||
|
* Returns an array of pointers to strings which are split out from
|
||||||
|
* @str. This is performed by strictly splitting on white-space; no
|
||||||
|
* quote processing is performed. Multiple whitespace characters are
|
||||||
|
* considered to be a single argument separator. The returned array
|
||||||
|
* is always NULL-terminated. Returns NULL on memory allocation
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
char **argv_split(const char *str, int *argcp)
|
||||||
|
{
|
||||||
|
int argc = count_argc(str);
|
||||||
|
char **argv = calloc(argc + 1, sizeof(*argv));
|
||||||
|
char **argvp;
|
||||||
|
|
||||||
|
if (argv == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (argcp)
|
||||||
|
*argcp = argc;
|
||||||
|
|
||||||
|
argvp = argv;
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
str = skip_spaces(str);
|
||||||
|
|
||||||
|
if (*str) {
|
||||||
|
const char *p = str;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
str = skip_arg(str);
|
||||||
|
|
||||||
|
t = strndup(p, str-p);
|
||||||
|
if (t == NULL)
|
||||||
|
goto fail;
|
||||||
|
*argvp++ = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*argvp = NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return argv;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
argv_free(argv);
|
||||||
|
return NULL;
|
||||||
|
}
|
35
tools/lib/ctype.c
Normal file
35
tools/lib/ctype.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* linux/lib/ctype.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
|
const unsigned char _ctype[] = {
|
||||||
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
|
||||||
|
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
|
||||||
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
|
||||||
|
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
|
||||||
|
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
|
||||||
|
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
|
||||||
|
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
|
||||||
|
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
|
||||||
|
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
|
||||||
|
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
|
||||||
|
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
|
||||||
|
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
|
||||||
|
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
|
||||||
|
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
|
||||||
|
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
|
||||||
|
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
|
||||||
|
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
|
||||||
|
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
|
||||||
|
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
|
||||||
|
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
|
||||||
|
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
|
||||||
|
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
|
|
@ -17,6 +17,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,3 +107,57 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size)
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* skip_spaces - Removes leading whitespace from @str.
|
||||||
|
* @str: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the first non-whitespace character in @str.
|
||||||
|
*/
|
||||||
|
char *skip_spaces(const char *str)
|
||||||
|
{
|
||||||
|
while (isspace(*str))
|
||||||
|
++str;
|
||||||
|
return (char *)str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strim - Removes leading and trailing whitespace from @s.
|
||||||
|
* @s: The string to be stripped.
|
||||||
|
*
|
||||||
|
* Note that the first trailing whitespace is replaced with a %NUL-terminator
|
||||||
|
* in the given string @s. Returns a pointer to the first non-whitespace
|
||||||
|
* character in @s.
|
||||||
|
*/
|
||||||
|
char *strim(char *s)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
size = strlen(s);
|
||||||
|
if (!size)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
end = s + size - 1;
|
||||||
|
while (end >= s && isspace(*end))
|
||||||
|
end--;
|
||||||
|
*(end + 1) = '\0';
|
||||||
|
|
||||||
|
return skip_spaces(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strreplace - Replace all occurrences of character in string.
|
||||||
|
* @s: The string to operate on.
|
||||||
|
* @old: The character being replaced.
|
||||||
|
* @new: The character @old is replaced with.
|
||||||
|
*
|
||||||
|
* Returns pointer to the nul byte at the end of @s.
|
||||||
|
*/
|
||||||
|
char *strreplace(char *s, char old, char new)
|
||||||
|
{
|
||||||
|
for (; *s; ++s)
|
||||||
|
if (*s == old)
|
||||||
|
*s = new;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <ctype.h>
|
|
||||||
#include "symbol/kallsyms.h"
|
#include "symbol/kallsyms.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -16,6 +15,19 @@ bool kallsyms__is_function(char symbol_type)
|
||||||
return symbol_type == 'T' || symbol_type == 'W';
|
return symbol_type == 'T' || symbol_type == 'W';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While we find nice hex chars, build a long_val.
|
||||||
|
* Return number of chars processed.
|
||||||
|
*/
|
||||||
|
int hex2u64(const char *ptr, u64 *long_val)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
*long_val = strtoull(ptr, &p, 16);
|
||||||
|
|
||||||
|
return p - ptr;
|
||||||
|
}
|
||||||
|
|
||||||
int kallsyms__parse(const char *filename, void *arg,
|
int kallsyms__parse(const char *filename, void *arg,
|
||||||
int (*process_symbol)(void *arg, const char *name,
|
int (*process_symbol)(void *arg, const char *name,
|
||||||
char type, u64 start))
|
char type, u64 start))
|
||||||
|
|
|
@ -18,6 +18,8 @@ static inline u8 kallsyms2elf_binding(char type)
|
||||||
return isupper(type) ? STB_GLOBAL : STB_LOCAL;
|
return isupper(type) ? STB_GLOBAL : STB_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hex2u64(const char *ptr, u64 *long_val);
|
||||||
|
|
||||||
u8 kallsyms2elf_type(char type);
|
u8 kallsyms2elf_type(char type);
|
||||||
|
|
||||||
bool kallsyms__is_function(char symbol_type);
|
bool kallsyms__is_function(char symbol_type);
|
||||||
|
|
|
@ -23,3 +23,22 @@ int scnprintf(char * buf, size_t size, const char * fmt, ...)
|
||||||
|
|
||||||
return (i >= ssize) ? (ssize - 1) : i;
|
return (i >= ssize) ? (ssize - 1) : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int scnprintf_pad(char * buf, size_t size, const char * fmt, ...)
|
||||||
|
{
|
||||||
|
ssize_t ssize = size;
|
||||||
|
va_list args;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
i = vscnprintf(buf, size, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (i < (int) size) {
|
||||||
|
for (; i < (int) size; i++)
|
||||||
|
buf[i] = ' ';
|
||||||
|
buf[i] = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (i >= ssize) ? (ssize - 1) : i;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ objtool-y += special.o
|
||||||
objtool-y += objtool.o
|
objtool-y += objtool.o
|
||||||
|
|
||||||
objtool-y += libstring.o
|
objtool-y += libstring.o
|
||||||
|
objtool-y += libctype.o
|
||||||
objtool-y += str_error_r.o
|
objtool-y += str_error_r.o
|
||||||
|
|
||||||
CFLAGS += -I$(srctree)/tools/lib
|
CFLAGS += -I$(srctree)/tools/lib
|
||||||
|
@ -17,6 +18,10 @@ $(OUTPUT)libstring.o: ../lib/string.c FORCE
|
||||||
$(call rule_mkdir)
|
$(call rule_mkdir)
|
||||||
$(call if_changed_dep,cc_o_c)
|
$(call if_changed_dep,cc_o_c)
|
||||||
|
|
||||||
|
$(OUTPUT)libctype.o: ../lib/ctype.c FORCE
|
||||||
|
$(call rule_mkdir)
|
||||||
|
$(call if_changed_dep,cc_o_c)
|
||||||
|
|
||||||
$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
|
$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
|
||||||
$(call rule_mkdir)
|
$(call rule_mkdir)
|
||||||
$(call if_changed_dep,cc_o_c)
|
$(call if_changed_dep,cc_o_c)
|
||||||
|
|
41
tools/perf/Documentation/db-export.txt
Normal file
41
tools/perf/Documentation/db-export.txt
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
Database Export
|
||||||
|
===============
|
||||||
|
|
||||||
|
perf tool's python scripting engine:
|
||||||
|
|
||||||
|
tools/perf/util/scripting-engines/trace-event-python.c
|
||||||
|
|
||||||
|
supports scripts:
|
||||||
|
|
||||||
|
tools/perf/scripts/python/export-to-sqlite.py
|
||||||
|
tools/perf/scripts/python/export-to-postgresql.py
|
||||||
|
|
||||||
|
which export data to a SQLite3 or PostgreSQL database.
|
||||||
|
|
||||||
|
The export process provides records with unique sequential ids which allows the
|
||||||
|
data to be imported directly to a database and provides the relationships
|
||||||
|
between tables.
|
||||||
|
|
||||||
|
Over time it is possible to continue to expand the export while maintaining
|
||||||
|
backward and forward compatibility, by following some simple rules:
|
||||||
|
|
||||||
|
1. Because of the nature of SQL, existing tables and columns can continue to be
|
||||||
|
used so long as the names and meanings (and to some extent data types) remain
|
||||||
|
the same.
|
||||||
|
|
||||||
|
2. New tables and columns can be added, without affecting existing SQL queries,
|
||||||
|
so long as the new names are unique.
|
||||||
|
|
||||||
|
3. Scripts that use a database (e.g. exported-sql-viewer.py) can maintain
|
||||||
|
backward compatibility by testing for the presence of new tables and columns
|
||||||
|
before using them. e.g. function IsSelectable() in exported-sql-viewer.py
|
||||||
|
|
||||||
|
4. The export scripts themselves maintain forward compatibility (i.e. an existing
|
||||||
|
script will continue to work with new versions of perf) by accepting a variable
|
||||||
|
number of arguments (e.g. def call_return_table(*x)) i.e. perf can pass more
|
||||||
|
arguments which old scripts will ignore.
|
||||||
|
|
||||||
|
5. The scripting engine tests for the existence of script handler functions
|
||||||
|
before calling them. The scripting engine can also test for the support of new
|
||||||
|
or optional features by checking for the existence and value of script global
|
||||||
|
variables.
|
|
@ -88,21 +88,51 @@ smaller.
|
||||||
|
|
||||||
To represent software control flow, "branches" samples are produced. By default
|
To represent software control flow, "branches" samples are produced. By default
|
||||||
a branch sample is synthesized for every single branch. To get an idea what
|
a branch sample is synthesized for every single branch. To get an idea what
|
||||||
data is available you can use the 'perf script' tool with no parameters, which
|
data is available you can use the 'perf script' tool with all itrace sampling
|
||||||
will list all the samples.
|
options, which will list all the samples.
|
||||||
|
|
||||||
perf record -e intel_pt//u ls
|
perf record -e intel_pt//u ls
|
||||||
perf script
|
perf script --itrace=ibxwpe
|
||||||
|
|
||||||
An interesting field that is not printed by default is 'flags' which can be
|
An interesting field that is not printed by default is 'flags' which can be
|
||||||
displayed as follows:
|
displayed as follows:
|
||||||
|
|
||||||
perf script -Fcomm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr,symoff,flags
|
perf script --itrace=ibxwpe -F+flags
|
||||||
|
|
||||||
The flags are "bcrosyiABEx" which stand for branch, call, return, conditional,
|
The flags are "bcrosyiABEx" which stand for branch, call, return, conditional,
|
||||||
system, asynchronous, interrupt, transaction abort, trace begin, trace end, and
|
system, asynchronous, interrupt, transaction abort, trace begin, trace end, and
|
||||||
in transaction, respectively.
|
in transaction, respectively.
|
||||||
|
|
||||||
|
Another interesting field that is not printed by default is 'ipc' which can be
|
||||||
|
displayed as follows:
|
||||||
|
|
||||||
|
perf script --itrace=be -F+ipc
|
||||||
|
|
||||||
|
There are two ways that instructions-per-cycle (IPC) can be calculated depending
|
||||||
|
on the recording.
|
||||||
|
|
||||||
|
If the 'cyc' config term (see config terms section below) was used, then IPC is
|
||||||
|
calculated using the cycle count from CYC packets, otherwise MTC packets are
|
||||||
|
used - refer to the 'mtc' config term. When MTC is used, however, the values
|
||||||
|
are less accurate because the timing is less accurate.
|
||||||
|
|
||||||
|
Because Intel PT does not update the cycle count on every branch or instruction,
|
||||||
|
the values will often be zero. When there are values, they will be the number
|
||||||
|
of instructions and number of cycles since the last update, and thus represent
|
||||||
|
the average IPC since the last IPC for that event type. Note IPC for "branches"
|
||||||
|
events is calculated separately from IPC for "instructions" events.
|
||||||
|
|
||||||
|
Also note that the IPC instruction count may or may not include the current
|
||||||
|
instruction. If the cycle count is associated with an asynchronous branch
|
||||||
|
(e.g. page fault or interrupt), then the instruction count does not include the
|
||||||
|
current instruction, otherwise it does. That is consistent with whether or not
|
||||||
|
that instruction has retired when the cycle count is updated.
|
||||||
|
|
||||||
|
Another note, in the case of "branches" events, non-taken branches are not
|
||||||
|
presently sampled, so IPC values for them do not appear e.g. a CYC packet with a
|
||||||
|
TNT packet that starts with a non-taken branch. To see every possible IPC
|
||||||
|
value, "instructions" events can be used e.g. --itrace=i0ns
|
||||||
|
|
||||||
While it is possible to create scripts to analyze the data, an alternative
|
While it is possible to create scripts to analyze the data, an alternative
|
||||||
approach is available to export the data to a sqlite or postgresql database.
|
approach is available to export the data to a sqlite or postgresql database.
|
||||||
Refer to script export-to-sqlite.py or export-to-postgresql.py for more details,
|
Refer to script export-to-sqlite.py or export-to-postgresql.py for more details,
|
||||||
|
@ -713,7 +743,7 @@ Having no option is the same as
|
||||||
|
|
||||||
which, in turn, is the same as
|
which, in turn, is the same as
|
||||||
|
|
||||||
--itrace=ibxwpe
|
--itrace=cepwx
|
||||||
|
|
||||||
The letters are:
|
The letters are:
|
||||||
|
|
||||||
|
|
|
@ -564,9 +564,12 @@ llvm.*::
|
||||||
llvm.clang-bpf-cmd-template::
|
llvm.clang-bpf-cmd-template::
|
||||||
Cmdline template. Below lines show its default value. Environment
|
Cmdline template. Below lines show its default value. Environment
|
||||||
variable is used to pass options.
|
variable is used to pass options.
|
||||||
"$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS $KERNEL_INC_OPTIONS \
|
"$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
|
||||||
-Wno-unused-value -Wno-pointer-sign -working-directory \
|
"-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
|
||||||
$WORKING_DIR -c $CLANG_SOURCE -target bpf -O2 -o -"
|
"$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
|
||||||
|
"-Wno-unused-value -Wno-pointer-sign " \
|
||||||
|
"-working-directory $WORKING_DIR " \
|
||||||
|
"-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
|
||||||
|
|
||||||
llvm.clang-opt::
|
llvm.clang-opt::
|
||||||
Options passed to clang.
|
Options passed to clang.
|
||||||
|
|
|
@ -90,9 +90,10 @@ OPTIONS
|
||||||
|
|
||||||
-c::
|
-c::
|
||||||
--compute::
|
--compute::
|
||||||
Differential computation selection - delta, ratio, wdiff, delta-abs
|
Differential computation selection - delta, ratio, wdiff, cycles,
|
||||||
(default is delta-abs). Default can be changed using diff.compute
|
delta-abs (default is delta-abs). Default can be changed using
|
||||||
config option. See COMPARISON METHODS section for more info.
|
diff.compute config option. See COMPARISON METHODS section for
|
||||||
|
more info.
|
||||||
|
|
||||||
-p::
|
-p::
|
||||||
--period::
|
--period::
|
||||||
|
@ -142,12 +143,14 @@ OPTIONS
|
||||||
perf diff --time 0%-10%,30%-40%
|
perf diff --time 0%-10%,30%-40%
|
||||||
|
|
||||||
It also supports analyzing samples within a given time window
|
It also supports analyzing samples within a given time window
|
||||||
<start>,<stop>. Times have the format seconds.microseconds. If 'start'
|
<start>,<stop>. Times have the format seconds.nanoseconds. If 'start'
|
||||||
is not given (i.e., time string is ',x.y') then analysis starts at
|
is not given (i.e. time string is ',x.y') then analysis starts at
|
||||||
the beginning of the file. If stop time is not given (i.e, time
|
the beginning of the file. If stop time is not given (i.e. time
|
||||||
string is 'x.y,') then analysis goes to the end of the file. Time string is
|
string is 'x.y,') then analysis goes to the end of the file.
|
||||||
'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different
|
Multiple ranges can be separated by spaces, which requires the argument
|
||||||
perf.data files.
|
to be quoted e.g. --time "1234.567,1234.789 1235,"
|
||||||
|
Time string is'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps
|
||||||
|
for different perf.data files.
|
||||||
|
|
||||||
For example, we get the timestamp information from 'perf script'.
|
For example, we get the timestamp information from 'perf script'.
|
||||||
|
|
||||||
|
@ -278,6 +281,16 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as:
|
||||||
- WEIGHT-A being the weight of the data file
|
- WEIGHT-A being the weight of the data file
|
||||||
- WEIGHT-B being the weight of the baseline data file
|
- WEIGHT-B being the weight of the baseline data file
|
||||||
|
|
||||||
|
cycles
|
||||||
|
~~~~~~
|
||||||
|
If specified the '[Program Block Range] Cycles Diff' column is displayed.
|
||||||
|
It displays the cycles difference of same program basic block amongst
|
||||||
|
two perf.data. The program basic block is the code between two branches.
|
||||||
|
|
||||||
|
'[Program Block Range]' indicates the range of a program basic block.
|
||||||
|
Source line is reported if it can be found otherwise uses symbol+offset
|
||||||
|
instead.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
linkperf:perf-record[1], linkperf:perf-report[1]
|
linkperf:perf-record[1], linkperf:perf-report[1]
|
||||||
|
|
|
@ -490,6 +490,17 @@ Configure all used events to run in kernel space.
|
||||||
--all-user::
|
--all-user::
|
||||||
Configure all used events to run in user space.
|
Configure all used events to run in user space.
|
||||||
|
|
||||||
|
--kernel-callchains::
|
||||||
|
Collect callchains only from kernel space. I.e. this option sets
|
||||||
|
perf_event_attr.exclude_callchain_user to 1.
|
||||||
|
|
||||||
|
--user-callchains::
|
||||||
|
Collect callchains only from user space. I.e. this option sets
|
||||||
|
perf_event_attr.exclude_callchain_kernel to 1.
|
||||||
|
|
||||||
|
Don't use both --kernel-callchains and --user-callchains at the same time or no
|
||||||
|
callchains will be collected.
|
||||||
|
|
||||||
--timestamp-filename
|
--timestamp-filename
|
||||||
Append timestamp to output file name.
|
Append timestamp to output file name.
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ OPTIONS
|
||||||
- socket: processor socket number the task ran at the time of sample
|
- socket: processor socket number the task ran at the time of sample
|
||||||
- srcline: filename and line number executed at the time of sample. The
|
- srcline: filename and line number executed at the time of sample. The
|
||||||
DWARF debugging info must be provided.
|
DWARF debugging info must be provided.
|
||||||
- srcfile: file name of the source file of the same. Requires dwarf
|
- srcfile: file name of the source file of the samples. Requires dwarf
|
||||||
information.
|
information.
|
||||||
- weight: Event specific weight, e.g. memory latency or transaction
|
- weight: Event specific weight, e.g. memory latency or transaction
|
||||||
abort cost. This is the global weight.
|
abort cost. This is the global weight.
|
||||||
|
@ -412,12 +412,13 @@ OPTIONS
|
||||||
|
|
||||||
--time::
|
--time::
|
||||||
Only analyze samples within given time window: <start>,<stop>. Times
|
Only analyze samples within given time window: <start>,<stop>. Times
|
||||||
have the format seconds.microseconds. If start is not given (i.e., time
|
have the format seconds.nanoseconds. If start is not given (i.e. time
|
||||||
string is ',x.y') then analysis starts at the beginning of the file. If
|
string is ',x.y') then analysis starts at the beginning of the file. If
|
||||||
stop time is not given (i.e, time string is 'x.y,') then analysis goes
|
stop time is not given (i.e. time string is 'x.y,') then analysis goes
|
||||||
to end of file.
|
to end of file. Multiple ranges can be separated by spaces, which
|
||||||
|
requires the argument to be quoted e.g. --time "1234.567,1234.789 1235,"
|
||||||
|
|
||||||
Also support time percent with multiple time range. Time string is
|
Also support time percent with multiple time ranges. Time string is
|
||||||
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
|
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
|
@ -117,7 +117,7 @@ OPTIONS
|
||||||
Comma separated list of fields to print. Options are:
|
Comma separated list of fields to print. Options are:
|
||||||
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
|
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
|
||||||
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
|
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
|
||||||
brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode.
|
brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode, ipc.
|
||||||
Field list can be prepended with the type, trace, sw or hw,
|
Field list can be prepended with the type, trace, sw or hw,
|
||||||
to indicate to which event type the field list applies.
|
to indicate to which event type the field list applies.
|
||||||
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
|
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
|
||||||
|
@ -203,6 +203,9 @@ OPTIONS
|
||||||
The synth field is used by synthesized events which may be created when
|
The synth field is used by synthesized events which may be created when
|
||||||
Instruction Trace decoding.
|
Instruction Trace decoding.
|
||||||
|
|
||||||
|
The ipc (instructions per cycle) field is synthesized and may have a value when
|
||||||
|
Instruction Trace decoding.
|
||||||
|
|
||||||
Finally, a user may not set fields to none for all event types.
|
Finally, a user may not set fields to none for all event types.
|
||||||
i.e., -F "" is not allowed.
|
i.e., -F "" is not allowed.
|
||||||
|
|
||||||
|
@ -313,6 +316,9 @@ OPTIONS
|
||||||
--show-round-events
|
--show-round-events
|
||||||
Display finished round events i.e. events of type PERF_RECORD_FINISHED_ROUND.
|
Display finished round events i.e. events of type PERF_RECORD_FINISHED_ROUND.
|
||||||
|
|
||||||
|
--show-bpf-events
|
||||||
|
Display bpf events i.e. events of type PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT.
|
||||||
|
|
||||||
--demangle::
|
--demangle::
|
||||||
Demangle symbol names to human readable form. It's enabled by default,
|
Demangle symbol names to human readable form. It's enabled by default,
|
||||||
disable with --no-demangle.
|
disable with --no-demangle.
|
||||||
|
@ -355,12 +361,13 @@ include::itrace.txt[]
|
||||||
|
|
||||||
--time::
|
--time::
|
||||||
Only analyze samples within given time window: <start>,<stop>. Times
|
Only analyze samples within given time window: <start>,<stop>. Times
|
||||||
have the format seconds.microseconds. If start is not given (i.e., time
|
have the format seconds.nanoseconds. If start is not given (i.e. time
|
||||||
string is ',x.y') then analysis starts at the beginning of the file. If
|
string is ',x.y') then analysis starts at the beginning of the file. If
|
||||||
stop time is not given (i.e, time string is 'x.y,') then analysis goes
|
stop time is not given (i.e. time string is 'x.y,') then analysis goes
|
||||||
to end of file.
|
to end of file. Multiple ranges can be separated by spaces, which
|
||||||
|
requires the argument to be quoted e.g. --time "1234.567,1234.789 1235,"
|
||||||
|
|
||||||
Also support time percent with multipe time range. Time string is
|
Also support time percent with multiple time ranges. Time string is
|
||||||
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
|
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
|
@ -200,6 +200,13 @@ use --per-socket in addition to -a. (system-wide). The output includes the
|
||||||
socket number and the number of online processors on that socket. This is
|
socket number and the number of online processors on that socket. This is
|
||||||
useful to gauge the amount of aggregation.
|
useful to gauge the amount of aggregation.
|
||||||
|
|
||||||
|
--per-die::
|
||||||
|
Aggregate counts per processor die for system-wide mode measurements. This
|
||||||
|
is a useful mode to detect imbalance between dies. To enable this mode,
|
||||||
|
use --per-die in addition to -a. (system-wide). The output includes the
|
||||||
|
die number and the number of online processors on that die. This is
|
||||||
|
useful to gauge the amount of aggregation.
|
||||||
|
|
||||||
--per-core::
|
--per-core::
|
||||||
Aggregate counts per physical processor for system-wide mode measurements. This
|
Aggregate counts per physical processor for system-wide mode measurements. This
|
||||||
is a useful mode to detect imbalance between physical cores. To enable this mode,
|
is a useful mode to detect imbalance between physical cores. To enable this mode,
|
||||||
|
@ -239,6 +246,9 @@ Input file name.
|
||||||
--per-socket::
|
--per-socket::
|
||||||
Aggregate counts per processor socket for system-wide mode measurements.
|
Aggregate counts per processor socket for system-wide mode measurements.
|
||||||
|
|
||||||
|
--per-die::
|
||||||
|
Aggregate counts per processor die for system-wide mode measurements.
|
||||||
|
|
||||||
--per-core::
|
--per-core::
|
||||||
Aggregate counts per physical processor for system-wide mode measurements.
|
Aggregate counts per physical processor for system-wide mode measurements.
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,11 @@ Default is to monitor all CPUS.
|
||||||
The number of threads to run when synthesizing events for existing processes.
|
The number of threads to run when synthesizing events for existing processes.
|
||||||
By default, the number of threads equals to the number of online CPUs.
|
By default, the number of threads equals to the number of online CPUs.
|
||||||
|
|
||||||
|
--namespaces::
|
||||||
|
Record events of type PERF_RECORD_NAMESPACES and display it with the
|
||||||
|
'cgroup_id' sort key.
|
||||||
|
|
||||||
|
|
||||||
INTERACTIVE PROMPTING KEYS
|
INTERACTIVE PROMPTING KEYS
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
@ -151,25 +151,45 @@ struct {
|
||||||
|
|
||||||
HEADER_CPU_TOPOLOGY = 13,
|
HEADER_CPU_TOPOLOGY = 13,
|
||||||
|
|
||||||
String lists defining the core and CPU threads topology.
|
|
||||||
The string lists are followed by a variable length array
|
|
||||||
which contains core_id and socket_id of each cpu.
|
|
||||||
The number of entries can be determined by the size of the
|
|
||||||
section minus the sizes of both string lists.
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
/*
|
||||||
|
* First revision of HEADER_CPU_TOPOLOGY
|
||||||
|
*
|
||||||
|
* See 'struct perf_header_string_list' definition earlier
|
||||||
|
* in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
struct perf_header_string_list cores; /* Variable length */
|
struct perf_header_string_list cores; /* Variable length */
|
||||||
struct perf_header_string_list threads; /* Variable length */
|
struct perf_header_string_list threads; /* Variable length */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Second revision of HEADER_CPU_TOPOLOGY, older tools
|
||||||
|
* will not consider what comes next
|
||||||
|
*/
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t core_id;
|
uint32_t core_id;
|
||||||
uint32_t socket_id;
|
uint32_t socket_id;
|
||||||
} cpus[nr]; /* Variable length records */
|
} cpus[nr]; /* Variable length records */
|
||||||
|
/* 'nr' comes from previously processed HEADER_NRCPUS's nr_cpu_avail */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Third revision of HEADER_CPU_TOPOLOGY, older tools
|
||||||
|
* will not consider what comes next
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct perf_header_string_list dies; /* Variable length */
|
||||||
|
uint32_t die_id[nr_cpus_avail]; /* from previously processed HEADER_NR_CPUS, VLA */
|
||||||
};
|
};
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
sibling cores : 0-3
|
sibling sockets : 0-8
|
||||||
|
sibling dies : 0-3
|
||||||
|
sibling dies : 4-7
|
||||||
sibling threads : 0-1
|
sibling threads : 0-1
|
||||||
sibling threads : 2-3
|
sibling threads : 2-3
|
||||||
|
sibling threads : 4-5
|
||||||
|
sibling threads : 6-7
|
||||||
|
|
||||||
HEADER_NUMA_TOPOLOGY = 14,
|
HEADER_NUMA_TOPOLOGY = 14,
|
||||||
|
|
||||||
|
@ -272,6 +292,69 @@ struct {
|
||||||
|
|
||||||
Two uint64_t for the time of first sample and the time of last sample.
|
Two uint64_t for the time of first sample and the time of last sample.
|
||||||
|
|
||||||
|
HEADER_SAMPLE_TOPOLOGY = 22,
|
||||||
|
|
||||||
|
Physical memory map and its node assignments.
|
||||||
|
|
||||||
|
The format of data in MEM_TOPOLOGY is as follows:
|
||||||
|
|
||||||
|
0 - version | for future changes
|
||||||
|
8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes
|
||||||
|
16 - count | number of nodes
|
||||||
|
|
||||||
|
For each node we store map of physical indexes:
|
||||||
|
|
||||||
|
32 - node id | node index
|
||||||
|
40 - size | size of bitmap
|
||||||
|
48 - bitmap | bitmap of memory indexes that belongs to node
|
||||||
|
| /sys/devices/system/node/node<NODE>/memory<INDEX>
|
||||||
|
|
||||||
|
The MEM_TOPOLOGY can be displayed with following command:
|
||||||
|
|
||||||
|
$ perf report --header-only -I
|
||||||
|
...
|
||||||
|
# memory nodes (nr 1, block size 0x8000000):
|
||||||
|
# 0 [7G]: 0-23,32-69
|
||||||
|
|
||||||
|
HEADER_CLOCKID = 23,
|
||||||
|
|
||||||
|
One uint64_t for the clockid frequency, specified, for instance, via 'perf
|
||||||
|
record -k' (see clock_gettime()), to enable timestamps derived metrics
|
||||||
|
conversion into wall clock time on the reporting stage.
|
||||||
|
|
||||||
|
HEADER_DIR_FORMAT = 24,
|
||||||
|
|
||||||
|
The data files layout is described by HEADER_DIR_FORMAT feature. Currently it
|
||||||
|
holds only version number (1):
|
||||||
|
|
||||||
|
uint64_t version;
|
||||||
|
|
||||||
|
The current version holds only version value (1) means that data files:
|
||||||
|
|
||||||
|
- Follow the 'data.*' name format.
|
||||||
|
|
||||||
|
- Contain raw events data in standard perf format as read from kernel (and need
|
||||||
|
to be sorted)
|
||||||
|
|
||||||
|
Future versions are expected to describe different data files layout according
|
||||||
|
to special needs.
|
||||||
|
|
||||||
|
HEADER_BPF_PROG_INFO = 25,
|
||||||
|
|
||||||
|
struct bpf_prog_info_linear, which contains detailed information about
|
||||||
|
a BPF program, including type, id, tag, jited/xlated instructions, etc.
|
||||||
|
|
||||||
|
HEADER_BPF_BTF = 26,
|
||||||
|
|
||||||
|
Contains BPF Type Format (BTF). For more information about BTF, please
|
||||||
|
refer to Documentation/bpf/btf.rst.
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 id;
|
||||||
|
u32 data_size;
|
||||||
|
char data[];
|
||||||
|
};
|
||||||
|
|
||||||
HEADER_COMPRESSED = 27,
|
HEADER_COMPRESSED = 27,
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -38,6 +38,6 @@ To report cacheline events from previous recording: perf c2c report
|
||||||
To browse sample contexts use perf report --sample 10 and select in context menu
|
To browse sample contexts use perf report --sample 10 and select in context menu
|
||||||
To separate samples by time use perf report --sort time,overhead,sym
|
To separate samples by time use perf report --sort time,overhead,sym
|
||||||
To set sample time separation other than 100ms with --sort time use --time-quantum
|
To set sample time separation other than 100ms with --sort time use --time-quantum
|
||||||
Add -I to perf report to sample register values visible in perf report context.
|
Add -I to perf record to sample register values, which will be visible in perf report sample context.
|
||||||
To show IPC for sampling periods use perf record -e '{cycles,instructions}:S' and then browse context
|
To show IPC for sampling periods use perf record -e '{cycles,instructions}:S' and then browse context
|
||||||
To show context switches in perf report sample context add --switch-events to perf record.
|
To show context switches in perf report sample context add --switch-events to perf record.
|
||||||
|
|
|
@ -7,6 +7,8 @@ tools/lib/traceevent
|
||||||
tools/lib/api
|
tools/lib/api
|
||||||
tools/lib/bpf
|
tools/lib/bpf
|
||||||
tools/lib/subcmd
|
tools/lib/subcmd
|
||||||
|
tools/lib/argv_split.c
|
||||||
|
tools/lib/ctype.c
|
||||||
tools/lib/hweight.c
|
tools/lib/hweight.c
|
||||||
tools/lib/rbtree.c
|
tools/lib/rbtree.c
|
||||||
tools/lib/string.c
|
tools/lib/string.c
|
||||||
|
|
|
@ -417,6 +417,9 @@ ifdef CORESIGHT
|
||||||
$(call feature_check,libopencsd)
|
$(call feature_check,libopencsd)
|
||||||
ifeq ($(feature-libopencsd), 1)
|
ifeq ($(feature-libopencsd), 1)
|
||||||
CFLAGS += -DHAVE_CSTRACE_SUPPORT $(LIBOPENCSD_CFLAGS)
|
CFLAGS += -DHAVE_CSTRACE_SUPPORT $(LIBOPENCSD_CFLAGS)
|
||||||
|
ifeq ($(feature-reallocarray), 0)
|
||||||
|
CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
|
||||||
|
endif
|
||||||
LDFLAGS += $(LIBOPENCSD_LDFLAGS)
|
LDFLAGS += $(LIBOPENCSD_LDFLAGS)
|
||||||
EXTLIBS += $(OPENCSDLIBS)
|
EXTLIBS += $(OPENCSDLIBS)
|
||||||
$(call detected,CONFIG_LIBOPENCSD)
|
$(call detected,CONFIG_LIBOPENCSD)
|
||||||
|
@ -641,11 +644,15 @@ endif
|
||||||
|
|
||||||
ifndef NO_SLANG
|
ifndef NO_SLANG
|
||||||
ifneq ($(feature-libslang), 1)
|
ifneq ($(feature-libslang), 1)
|
||||||
msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
|
ifneq ($(feature-libslang-include-subdir), 1)
|
||||||
NO_SLANG := 1
|
msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
|
||||||
else
|
NO_SLANG := 1
|
||||||
|
else
|
||||||
|
CFLAGS += -DHAVE_SLANG_INCLUDE_SUBDIR
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifndef NO_SLANG
|
||||||
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
||||||
CFLAGS += -I/usr/include/slang
|
|
||||||
CFLAGS += -DHAVE_SLANG_SUPPORT
|
CFLAGS += -DHAVE_SLANG_SUPPORT
|
||||||
EXTLIBS += -lslang
|
EXTLIBS += -lslang
|
||||||
$(call detected,CONFIG_SLANG)
|
$(call detected,CONFIG_SLANG)
|
||||||
|
|
|
@ -420,6 +420,24 @@ fadvise_advice_tbl := $(srctree)/tools/perf/trace/beauty/fadvise.sh
|
||||||
$(fadvise_advice_array): $(linux_uapi_dir)/in.h $(fadvise_advice_tbl)
|
$(fadvise_advice_array): $(linux_uapi_dir)/in.h $(fadvise_advice_tbl)
|
||||||
$(Q)$(SHELL) '$(fadvise_advice_tbl)' $(linux_uapi_dir) > $@
|
$(Q)$(SHELL) '$(fadvise_advice_tbl)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
|
fsmount_arrays := $(beauty_outdir)/fsmount_arrays.c
|
||||||
|
fsmount_tbls := $(srctree)/tools/perf/trace/beauty/fsmount.sh
|
||||||
|
|
||||||
|
$(fsmount_arrays): $(linux_uapi_dir)/fs.h $(fsmount_tbls)
|
||||||
|
$(Q)$(SHELL) '$(fsmount_tbls)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
|
fspick_arrays := $(beauty_outdir)/fspick_arrays.c
|
||||||
|
fspick_tbls := $(srctree)/tools/perf/trace/beauty/fspick.sh
|
||||||
|
|
||||||
|
$(fspick_arrays): $(linux_uapi_dir)/fs.h $(fspick_tbls)
|
||||||
|
$(Q)$(SHELL) '$(fspick_tbls)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
|
fsconfig_arrays := $(beauty_outdir)/fsconfig_arrays.c
|
||||||
|
fsconfig_tbls := $(srctree)/tools/perf/trace/beauty/fsconfig.sh
|
||||||
|
|
||||||
|
$(fsconfig_arrays): $(linux_uapi_dir)/fs.h $(fsconfig_tbls)
|
||||||
|
$(Q)$(SHELL) '$(fsconfig_tbls)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
pkey_alloc_access_rights_array := $(beauty_outdir)/pkey_alloc_access_rights_array.c
|
pkey_alloc_access_rights_array := $(beauty_outdir)/pkey_alloc_access_rights_array.c
|
||||||
asm_generic_hdr_dir := $(srctree)/tools/include/uapi/asm-generic/
|
asm_generic_hdr_dir := $(srctree)/tools/include/uapi/asm-generic/
|
||||||
pkey_alloc_access_rights_tbl := $(srctree)/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
|
pkey_alloc_access_rights_tbl := $(srctree)/tools/perf/trace/beauty/pkey_alloc_access_rights.sh
|
||||||
|
@ -494,6 +512,12 @@ mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/mount_flags.sh
|
||||||
$(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl)
|
$(mount_flags_array): $(linux_uapi_dir)/fs.h $(mount_flags_tbl)
|
||||||
$(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@
|
$(Q)$(SHELL) '$(mount_flags_tbl)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
|
move_mount_flags_array := $(beauty_outdir)/move_mount_flags_array.c
|
||||||
|
move_mount_flags_tbl := $(srctree)/tools/perf/trace/beauty/move_mount_flags.sh
|
||||||
|
|
||||||
|
$(move_mount_flags_array): $(linux_uapi_dir)/fs.h $(move_mount_flags_tbl)
|
||||||
|
$(Q)$(SHELL) '$(move_mount_flags_tbl)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
prctl_option_array := $(beauty_outdir)/prctl_option_array.c
|
prctl_option_array := $(beauty_outdir)/prctl_option_array.c
|
||||||
prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/
|
prctl_hdr_dir := $(srctree)/tools/include/uapi/linux/
|
||||||
prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
|
prctl_option_tbl := $(srctree)/tools/perf/trace/beauty/prctl_option.sh
|
||||||
|
@ -526,6 +550,12 @@ arch_errno_tbl := $(srctree)/tools/perf/trace/beauty/arch_errno_names.sh
|
||||||
$(arch_errno_name_array): $(arch_errno_tbl)
|
$(arch_errno_name_array): $(arch_errno_tbl)
|
||||||
$(Q)$(SHELL) '$(arch_errno_tbl)' $(CC) $(arch_errno_hdr_dir) > $@
|
$(Q)$(SHELL) '$(arch_errno_tbl)' $(CC) $(arch_errno_hdr_dir) > $@
|
||||||
|
|
||||||
|
sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c
|
||||||
|
sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh
|
||||||
|
|
||||||
|
$(sync_file_range_arrays): $(linux_uapi_dir)/fs.h $(sync_file_range_tbls)
|
||||||
|
$(Q)$(SHELL) '$(sync_file_range_tbls)' $(linux_uapi_dir) > $@
|
||||||
|
|
||||||
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
|
||||||
|
|
||||||
# Create python binding output directory if not already present
|
# Create python binding output directory if not already present
|
||||||
|
@ -629,6 +659,9 @@ build-dir = $(if $(__build-dir),$(__build-dir),.)
|
||||||
|
|
||||||
prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioctl_array) \
|
prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioctl_array) \
|
||||||
$(fadvise_advice_array) \
|
$(fadvise_advice_array) \
|
||||||
|
$(fsconfig_arrays) \
|
||||||
|
$(fsmount_arrays) \
|
||||||
|
$(fspick_arrays) \
|
||||||
$(pkey_alloc_access_rights_array) \
|
$(pkey_alloc_access_rights_array) \
|
||||||
$(sndrv_pcm_ioctl_array) \
|
$(sndrv_pcm_ioctl_array) \
|
||||||
$(sndrv_ctl_ioctl_array) \
|
$(sndrv_ctl_ioctl_array) \
|
||||||
|
@ -639,12 +672,14 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
|
||||||
$(madvise_behavior_array) \
|
$(madvise_behavior_array) \
|
||||||
$(mmap_flags_array) \
|
$(mmap_flags_array) \
|
||||||
$(mount_flags_array) \
|
$(mount_flags_array) \
|
||||||
|
$(move_mount_flags_array) \
|
||||||
$(perf_ioctl_array) \
|
$(perf_ioctl_array) \
|
||||||
$(prctl_option_array) \
|
$(prctl_option_array) \
|
||||||
$(usbdevfs_ioctl_array) \
|
$(usbdevfs_ioctl_array) \
|
||||||
$(x86_arch_prctl_code_array) \
|
$(x86_arch_prctl_code_array) \
|
||||||
$(rename_flags_array) \
|
$(rename_flags_array) \
|
||||||
$(arch_errno_name_array)
|
$(arch_errno_name_array) \
|
||||||
|
$(sync_file_range_arrays)
|
||||||
|
|
||||||
$(OUTPUT)%.o: %.c prepare FORCE
|
$(OUTPUT)%.o: %.c prepare FORCE
|
||||||
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
|
$(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
|
||||||
|
@ -923,9 +958,13 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
|
||||||
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
|
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
|
||||||
$(OUTPUT)pmu-events/pmu-events.c \
|
$(OUTPUT)pmu-events/pmu-events.c \
|
||||||
$(OUTPUT)$(fadvise_advice_array) \
|
$(OUTPUT)$(fadvise_advice_array) \
|
||||||
|
$(OUTPUT)$(fsconfig_arrays) \
|
||||||
|
$(OUTPUT)$(fsmount_arrays) \
|
||||||
|
$(OUTPUT)$(fspick_arrays) \
|
||||||
$(OUTPUT)$(madvise_behavior_array) \
|
$(OUTPUT)$(madvise_behavior_array) \
|
||||||
$(OUTPUT)$(mmap_flags_array) \
|
$(OUTPUT)$(mmap_flags_array) \
|
||||||
$(OUTPUT)$(mount_flags_array) \
|
$(OUTPUT)$(mount_flags_array) \
|
||||||
|
$(OUTPUT)$(move_mount_flags_array) \
|
||||||
$(OUTPUT)$(drm_ioctl_array) \
|
$(OUTPUT)$(drm_ioctl_array) \
|
||||||
$(OUTPUT)$(pkey_alloc_access_rights_array) \
|
$(OUTPUT)$(pkey_alloc_access_rights_array) \
|
||||||
$(OUTPUT)$(sndrv_ctl_ioctl_array) \
|
$(OUTPUT)$(sndrv_ctl_ioctl_array) \
|
||||||
|
@ -939,7 +978,8 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
|
||||||
$(OUTPUT)$(usbdevfs_ioctl_array) \
|
$(OUTPUT)$(usbdevfs_ioctl_array) \
|
||||||
$(OUTPUT)$(x86_arch_prctl_code_array) \
|
$(OUTPUT)$(x86_arch_prctl_code_array) \
|
||||||
$(OUTPUT)$(rename_flags_array) \
|
$(OUTPUT)$(rename_flags_array) \
|
||||||
$(OUTPUT)$(arch_errno_name_array)
|
$(OUTPUT)$(arch_errno_name_array) \
|
||||||
|
$(OUTPUT)$(sync_file_range_arrays)
|
||||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue