Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1339368 > unrolled thread
| Started by | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| First post | 2016-02-22 12:20 +0100 |
| Last post | 2016-02-22 20:00 +0100 |
| Articles | 20 on this page of 26 — 4 participants |
Back to article view | Back to linux.kernel
[patch V2 00/28] x86/perf/intel/uncore|rapl: Fix error handling and sanitize pmu management Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 18/28] x86/perf/intel_rapl: Make Knights Landings support functional Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
Re: [patch V2 18/28] x86/perf/intel_rapl: Make Knights Landings support functional Borislav Petkov <bp@alien8.de> - 2016-02-22 21:40 +0100
[patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
Re: [patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit Peter Zijlstra <peterz@infradead.org> - 2016-02-22 13:00 +0100
Re: [patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 13:10 +0100
[patch V2 17/28] x86/perf/cqm: Get rid of the silly for_each_cpu lookups Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 16/28] x86/perf/intel_uncore: Make it modular Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 12/28] x86/perf/uncore: Track packages not per cpu data Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 24/28] x86/perf/intel/rapl: Make pmu lock raw Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 02/28] x86/perf/intel/uncore: Simplify error rollback Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 03/28] x86/perf/intel/uncore: Fix error handling Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
Re: [patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output Andi Kleen <andi@firstfloor.org> - 2016-02-22 19:50 +0100
Re: [patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 20:00 +0100
[patch V2 08/28] x86/perf/uncore: Make uncore_pcibus_to_physid static Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 11/28] x86/topology: Create logical package id Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
Re: [patch V2 11/28] x86/topology: Create logical package id Andi Kleen <andi@firstfloor.org> - 2016-02-22 20:00 +0100
Re: [patch V2 11/28] x86/topology: Create logical package id Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 20:10 +0100
[patch V2 14/28] x86/perf/intel_uncore: Make PCI and MSR uncore independent Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 23/28] x86/perf/intel/rapl: Refactor code some more Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 07/28] x86/perf/intel_uncore: Make code readable Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 20/28] x86/perf/intel/rapl: Sanitize the quirk handling Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 25/28] x86/perf/intel/rapl: Utilize event->pmu_private Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
[patch V2 05/28] x86/perf/intel_uncore: Cleanup hardware on exit Thomas Gleixner <tglx@linutronix.de> - 2016-02-22 12:20 +0100
Re: [patch V2 00/28] x86/perf/intel/uncore|rapl: Fix error handling and sanitize pmu management Andi Kleen <andi@firstfloor.org> - 2016-02-22 20:00 +0100
Page 1 of 2 [1] 2 Next page →
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 00/28] x86/perf/intel/uncore|rapl: Fix error handling and sanitize pmu management |
| Message-ID | <r4Wxk-4RK-17@gated-at.bofh.it> |
This series addresses the following issues:
- Add proper error handling to uncore and rapl drivers
- Get rid of the pseudo per cpuness of these drivers and do a proper per
package storage
- Allow them to be modular
In order to do proper per package storage I added a facility which sanity
checks the physical package id of the processors which is supplied by bios and
does a logical package id translation. That allows drivers to do allocations
for the maximum number of possible packages independent of possible BIOS
creativity.
Changes vs. V1:
- Add logical package management
- Drop the exit_box callbacks for modern processors. This needs to be
revisited on a case by case basis.
- Fixup and convert the rapl driver as well
Thanks,
tglx
---
arch/x86/Kconfig | 6
arch/x86/include/asm/processor.h | 2
arch/x86/include/asm/topology.h | 10
arch/x86/kernel/apic/apic.c | 14
arch/x86/kernel/cpu/Makefile | 7
arch/x86/kernel/cpu/common.c | 2
arch/x86/kernel/cpu/intel.c | 13
arch/x86/kernel/cpu/perf_event_intel_cqm.c | 34
arch/x86/kernel/cpu/perf_event_intel_rapl.c | 438 ++++++------
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 694 ++++++++++----------
arch/x86/kernel/cpu/perf_event_intel_uncore.h | 51 +
arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c | 6
arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c | 14
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 10
arch/x86/kernel/cpu/proc.c | 1
arch/x86/kernel/smpboot.c | 100 ++
b/arch/x86/Kconfig.perf | 23
include/linux/perf_event.h | 1
kernel/events/core.c | 1
lib/cpumask.c | 1
20 files changed, 827 insertions(+), 601 deletions(-)
[toc] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 18/28] x86/perf/intel_rapl: Make Knights Landings support functional |
| Message-ID | <r4WH0-4WG-23@gated-at.bofh.it> |
| In reply to | #1339368 |
The Knights Landings support added the events and the detection case, but then returns 0 without actually initializing the driver. Fixes: 3a2a7797326a4 "perf/x86/intel/rapl: Add support for Knights Landing (KNL)" Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com> --- arch/x86/kernel/cpu/perf_event_intel_rapl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Index: b/arch/x86/kernel/cpu/perf_event_intel_rapl.c =================================================================== --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c @@ -731,7 +731,7 @@ static int __init rapl_pmu_init(void) rapl_add_quirk(rapl_hsw_server_quirk); rapl_cntr_mask = RAPL_IDX_KNL; rapl_pmu_events_group.attrs = rapl_events_knl_attr; - + break; default: /* unsupported */ return 0;
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-02-22 21:40 +0100 |
| Subject | Re: [patch V2 18/28] x86/perf/intel_rapl: Make Knights Landings support functional |
| Message-ID | <r55qV-2PE-3@gated-at.bofh.it> |
| In reply to | #1339369 |
On Mon, Feb 22, 2016 at 11:06:56AM -0000, Thomas Gleixner wrote:
> The Knights Landings support added the events and the detection case, but then
> returns 0 without actually initializing the driver.
>
> Fixes: 3a2a7797326a4 "perf/x86/intel/rapl: Add support for Knights Landing (KNL)"
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com>
> ---
> arch/x86/kernel/cpu/perf_event_intel_rapl.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> Index: b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
> ===================================================================
> --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
> +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
> @@ -731,7 +731,7 @@ static int __init rapl_pmu_init(void)
> rapl_add_quirk(rapl_hsw_server_quirk);
> rapl_cntr_mask = RAPL_IDX_KNL;
> rapl_pmu_events_group.attrs = rapl_events_knl_attr;
> -
> + break;
> default:
> /* unsupported */
> return 0;
Cc: <stable@vger.kernel.org> # 4.3
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit |
| Message-ID | <r4WH0-4WG-21@gated-at.bofh.it> |
| In reply to | #1339368 |
The only missing bit is to completely clear the hardware state on failure
exit. This is now a pretty simple exercise.
Undo the box->init_box() setup on all packages which have been initialized so
far.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -754,6 +754,30 @@ static void uncore_pmu_unregister(struct
pmu->registered = false;
}
+static void __init __uncore_exit_boxes(struct intel_uncore_type *type, int cpu)
+{
+ struct intel_uncore_pmu *pmu = type->pmus;
+ struct intel_uncore_box *box;
+ int i, pkg;
+
+ if (pmu) {
+ pkg = topology_physical_package_id(cpu);
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ box = pmu->boxes[pkg];
+ if (box)
+ uncore_box_exit(box);
+ }
+ }
+}
+
+static void __init uncore_exit_boxes(void *dummy)
+{
+ struct intel_uncore_type **types = uncore_msr_uncores;
+
+ while (*types)
+ __uncore_exit_boxes(*types++, smp_processor_id());
+}
+
static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
{
int pkg;
@@ -1371,6 +1395,8 @@ static int __init intel_uncore_init(void
return 0;
err:
+ /* Undo box->init_box() */
+ on_each_cpu_mask(&uncore_cpu_mask, uncore_exit_boxes, NULL, 1);
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
cpu_notifier_register_done();
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-02-22 13:00 +0100 |
| Subject | Re: [patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit |
| Message-ID | <r4XjJ-5i9-17@gated-at.bofh.it> |
| In reply to | #1339370 |
On Mon, Feb 22, 2016 at 11:06:52AM -0000, Thomas Gleixner wrote:
> +static void __init uncore_exit_boxes(void *dummy)
> +{
> + struct intel_uncore_type **types = uncore_msr_uncores;
> +
> + while (*types)
> + __uncore_exit_boxes(*types++, smp_processor_id());
for (types = uncore_msr_uncores; *types; types++)
__uncore_exit_boxes(*types, smp_processor_id());
> +}
You flipped to for() loops in the other places, figures this one should
match?
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 13:10 +0100 |
| Subject | Re: [patch V2 13/28] x86/perf/intel_uncore: Clear all hardware state on exit |
| Message-ID | <r4Xto-5Eo-13@gated-at.bofh.it> |
| In reply to | #1339417 |
On Mon, 22 Feb 2016, Peter Zijlstra wrote:
> On Mon, Feb 22, 2016 at 11:06:52AM -0000, Thomas Gleixner wrote:
> > +static void __init uncore_exit_boxes(void *dummy)
> > +{
> > + struct intel_uncore_type **types = uncore_msr_uncores;
> > +
> > + while (*types)
> > + __uncore_exit_boxes(*types++, smp_processor_id());
>
> for (types = uncore_msr_uncores; *types; types++)
> __uncore_exit_boxes(*types, smp_processor_id());
>
> > +}
>
> You flipped to for() loops in the other places, figures this one should
> match?
Yes. Forgot about that one.
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 17/28] x86/perf/cqm: Get rid of the silly for_each_cpu lookups |
| Message-ID | <r4WH0-4WG-29@gated-at.bofh.it> |
| In reply to | #1339368 |
CQM is a strict per package facility. Use the proper cpumasks to lookup the
readers.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_cqm.c | 34 ++++++++++-------------------
1 file changed, 12 insertions(+), 22 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
@@ -1244,15 +1244,12 @@ static struct pmu intel_cqm_pmu = {
static inline void cqm_pick_event_reader(int cpu)
{
- int phys_id = topology_physical_package_id(cpu);
- int i;
+ int reader;
- for_each_cpu(i, &cqm_cpumask) {
- if (phys_id == topology_physical_package_id(i))
- return; /* already got reader for this socket */
- }
-
- cpumask_set_cpu(cpu, &cqm_cpumask);
+ /* First online cpu in package becomes the reader */
+ reader = cpumask_any_and(&cqm_cpumask, topology_core_cpumask(cpu));
+ if (reader >= nr_cpu_ids)
+ cpumask_set_cpu(cpu, &cqm_cpumask);
}
static void intel_cqm_cpu_starting(unsigned int cpu)
@@ -1270,24 +1267,17 @@ static void intel_cqm_cpu_starting(unsig
static void intel_cqm_cpu_exit(unsigned int cpu)
{
- int phys_id = topology_physical_package_id(cpu);
- int i;
+ int target;
- /*
- * Is @cpu a designated cqm reader?
- */
+ /* Is @cpu the current cqm reader for this package ? */
if (!cpumask_test_and_clear_cpu(cpu, &cqm_cpumask))
return;
- for_each_online_cpu(i) {
- if (i == cpu)
- continue;
-
- if (phys_id == topology_physical_package_id(i)) {
- cpumask_set_cpu(i, &cqm_cpumask);
- break;
- }
- }
+ /* Find another online reader in this package */
+ target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
+
+ if (target < nr_cpu_ids)
+ cpumask_set_cpu(target, &cqm_cpumask);
}
static int intel_cqm_cpu_notifier(struct notifier_block *nb,
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 16/28] x86/perf/intel_uncore: Make it modular |
| Message-ID | <r4WH1-4WG-33@gated-at.bofh.it> |
| In reply to | #1339368 |
Now that we have a proper cleanup all over the place, it's simple to make this
a modular driver.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/Kconfig | 6 ++----
arch/x86/Kconfig.perf | 13 +++++++++++++
arch/x86/kernel/cpu/Makefile | 3 ++-
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 24 ++++++++++++++++++------
4 files changed, 35 insertions(+), 11 deletions(-)
Index: b/arch/x86/Kconfig
===================================================================
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -160,10 +160,6 @@ config INSTRUCTION_DECODER
def_bool y
depends on KPROBES || PERF_EVENTS || UPROBES
-config PERF_EVENTS_INTEL_UNCORE
- def_bool y
- depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
-
config OUTPUT_FORMAT
string
default "elf32-i386" if X86_32
@@ -1039,6 +1035,8 @@ config X86_THERMAL_VECTOR
def_bool y
depends on X86_MCE_INTEL
+source "arch/x86/Kconfig.perf"
+
config X86_LEGACY_VM86
bool "Legacy VM86 support"
default n
Index: b/arch/x86/Kconfig.perf
===================================================================
--- /dev/null
+++ b/arch/x86/Kconfig.perf
@@ -0,0 +1,13 @@
+menu "Performance monitoring"
+
+config PERF_EVENTS_INTEL_UNCORE
+ tristate "Intel uncore performance events"
+ depends on PERF_EVENTS && CPU_SUP_INTEL && PCI
+ default y
+ ---help---
+ Include support for Intel uncore performance events. These are
+ available on NehalemEX and more modern processors.
+
+ If unsure say y.
+
+endmenu
Index: b/arch/x86/kernel/cpu/Makefile
===================================================================
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -43,7 +43,8 @@ obj-$(CONFIG_CPU_SUP_INTEL) += perf_eve
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_pt.o perf_event_intel_bts.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_cstate.o
-obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += perf_event_intel_uncore.o \
+obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += perf_event_intel_uncores.o
+perf_event_intel_uncores-objs := perf_event_intel_uncore.o \
perf_event_intel_uncore_snb.o \
perf_event_intel_uncore_snbep.o \
perf_event_intel_uncore_nhmex.o
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -21,6 +21,8 @@ static struct event_constraint uncore_co
struct event_constraint uncore_constraint_empty =
EVENT_CONSTRAINT(0, 0, 0);
+MODULE_LICENSE("GPL");
+
static int uncore_pcibus_to_physid(struct pci_bus *bus)
{
struct pci2phy_map *map;
@@ -754,7 +756,7 @@ static void uncore_pmu_unregister(struct
pmu->registered = false;
}
-static void __init __uncore_exit_boxes(struct intel_uncore_type *type, int cpu)
+static void __uncore_exit_boxes(struct intel_uncore_type *type, int cpu)
{
struct intel_uncore_pmu *pmu = type->pmus;
struct intel_uncore_box *box;
@@ -770,7 +772,7 @@ static void __init __uncore_exit_boxes(s
}
}
-static void __init uncore_exit_boxes(void *dummy)
+static void uncore_exit_boxes(void *dummy)
{
struct intel_uncore_type **types = uncore_msr_uncores;
@@ -787,7 +789,7 @@ static void uncore_free_boxes(struct int
kfree(pmu->boxes);
}
-static void __init uncore_type_exit(struct intel_uncore_type *type)
+static void uncore_type_exit(struct intel_uncore_type *type)
{
struct intel_uncore_pmu *pmu = type->pmus;
int i;
@@ -804,7 +806,7 @@ static void __init uncore_type_exit(stru
type->events_group = NULL;
}
-static void __init uncore_types_exit(struct intel_uncore_type **types)
+static void uncore_types_exit(struct intel_uncore_type **types)
{
for (; *types; types++)
uncore_type_exit(*types);
@@ -1060,7 +1062,7 @@ static int __init uncore_pci_init(void)
return ret;
}
-static void __init uncore_pci_exit(void)
+static void uncore_pci_exit(void)
{
if (pcidrv_registered) {
pcidrv_registered = false;
@@ -1404,4 +1406,14 @@ static int __init intel_uncore_init(void
cpu_notifier_register_done();
return ret;
}
-device_initcall(intel_uncore_init);
+module_init(intel_uncore_init);
+
+static void __exit intel_uncore_exit(void)
+{
+ cpu_notifier_register_done();
+ __unregister_cpu_notifier(&uncore_cpu_nb);
+ uncore_types_exit(uncore_msr_uncores);
+ uncore_pci_exit();
+ cpu_notifier_register_done();
+}
+module_exit(intel_uncore_exit);
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 12/28] x86/perf/uncore: Track packages not per cpu data |
| Message-ID | <r4WH0-4WG-25@gated-at.bofh.it> |
| In reply to | #1339368 |
uncore is a per package facility, but the code tries to mimick a per cpu
facility with completely convoluted constructs.
Simplify the whole machinery by tracking per package information. While at it,
avoid the kfree/alloc dance when a cpu goes offline and online again. There is
no point in freeing the box after it was allocated. We just keep proper
refcounting and the first cpu which comes online in a package does the
initialization/activation of the box.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 420 ++++++++------------
arch/x86/kernel/cpu/perf_event_intel_uncore.h | 18
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 10
3 files changed, 197 insertions(+), 251 deletions(-)
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -9,9 +9,9 @@ struct pci_driver *uncore_pci_driver;
/* pci bus to socket mapping */
DEFINE_RAW_SPINLOCK(pci2phy_map_lock);
struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head);
-struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+struct pci_extra_dev *uncore_extra_pci_dev;
+static int max_packages;
-static DEFINE_RAW_SPINLOCK(uncore_box_lock);
/* mask of cpus that collect uncore events */
static cpumask_t uncore_cpu_mask;
@@ -94,27 +94,7 @@ ssize_t uncore_event_show(struct kobject
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
{
- struct intel_uncore_box *box;
-
- box = *per_cpu_ptr(pmu->box, cpu);
- if (box)
- return box;
-
- raw_spin_lock(&uncore_box_lock);
- /* Recheck in lock to handle races. */
- if (*per_cpu_ptr(pmu->box, cpu))
- goto out;
- list_for_each_entry(box, &pmu->box_list, list) {
- if (box->phys_id == topology_physical_package_id(cpu)) {
- atomic_inc(&box->refcnt);
- *per_cpu_ptr(pmu->box, cpu) = box;
- break;
- }
- }
-out:
- raw_spin_unlock(&uncore_box_lock);
-
- return *per_cpu_ptr(pmu->box, cpu);
+ return pmu->boxes[topology_logical_package_id(cpu)];
}
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
@@ -315,9 +295,9 @@ static struct intel_uncore_box *uncore_a
raw_spin_lock_init(&box->shared_regs[i].lock);
uncore_pmu_init_hrtimer(box);
- atomic_set(&box->refcnt, 1);
box->cpu = -1;
- box->phys_id = -1;
+ box->pci_phys_id = -1;
+ box->pkgid = -1;
/* set default hrtimer timeout */
box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
@@ -774,14 +754,24 @@ static void uncore_pmu_unregister(struct
pmu->registered = false;
}
+static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
+{
+ int pkg;
+
+ for (pkg = 0; pkg < max_packages; pkg++)
+ kfree(pmu->boxes[pkg]);
+ kfree(pmu->boxes);
+}
+
static void __init uncore_type_exit(struct intel_uncore_type *type)
{
+ struct intel_uncore_pmu *pmu = type->pmus;
int i;
- if (type->pmus) {
- for (i = 0; i < type->num_boxes; i++) {
- uncore_pmu_unregister(&type->pmus[i]);
- free_percpu(type->pmus[i].box);
+ if (pmu) {
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ uncore_pmu_unregister(pmu);
+ uncore_free_boxes(pmu);
}
kfree(type->pmus);
type->pmus = NULL;
@@ -796,37 +786,36 @@ static void __init uncore_types_exit(str
uncore_type_exit(*types);
}
-static int __init uncore_type_init(struct intel_uncore_type *type)
+static int __init uncore_type_init(struct intel_uncore_type *type, bool setid)
{
struct intel_uncore_pmu *pmus;
struct attribute_group *attr_group;
struct attribute **attrs;
+ size_t size;
int i, j;
pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL);
if (!pmus)
return -ENOMEM;
- type->pmus = pmus;
-
- type->unconstrainted = (struct event_constraint)
- __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
- 0, type->num_counters, 0, 0);
+ size = max_packages * sizeof(struct intel_uncore_box *);
for (i = 0; i < type->num_boxes; i++) {
- pmus[i].func_id = -1;
- pmus[i].pmu_idx = i;
- pmus[i].type = type;
- INIT_LIST_HEAD(&pmus[i].box_list);
- pmus[i].box = alloc_percpu(struct intel_uncore_box *);
- if (!pmus[i].box)
+ pmus[i].func_id = setid ? i : -1;
+ pmus[i].pmu_idx = i;
+ pmus[i].type = type;
+ pmus[i].boxes = kzalloc(size, GFP_KERNEL);
+ if (!pmus[i].boxes)
return -ENOMEM;
}
+ type->pmus = pmus;
+ type->unconstrainted = (struct event_constraint)
+ __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
+ 0, type->num_counters, 0, 0);
+
if (type->event_descs) {
- i = 0;
- while (type->event_descs[i].attr.attr.name)
- i++;
+ for (i = 0; type->event_descs[i].attr.attr.name; i++);
attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) +
sizeof(*attr_group), GFP_KERNEL);
@@ -847,12 +836,13 @@ static int __init uncore_type_init(struc
return 0;
}
-static int __init uncore_types_init(struct intel_uncore_type **types)
+static int __init
+uncore_types_init(struct intel_uncore_type **types, bool setid)
{
- int i, ret;
+ int ret;
- for (i = 0; types[i]; i++) {
- ret = uncore_type_init(types[i]);
+ for (; *types; types++) {
+ ret = uncore_type_init(*types, setid);
if (ret)
return ret;
}
@@ -864,28 +854,28 @@ static int __init uncore_types_init(stru
*/
static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct intel_uncore_type *type;
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
- struct intel_uncore_type *type;
- bool first_box = false;
- int phys_id, ret;
+ int phys_id, pkg, ret;
phys_id = uncore_pcibus_to_physid(pdev->bus);
- if (phys_id < 0 || phys_id >= UNCORE_SOCKET_MAX)
+ if (phys_id < 0)
return -ENODEV;
+ pkg = topology_phys_to_logical_pkg(phys_id);
+ if (WARN_ON_ONCE(pkg < 0))
+ return -EINVAL;
+
if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
- uncore_extra_pci_dev[phys_id][idx] = pdev;
+
+ uncore_extra_pci_dev[pkg].dev[idx] = pdev;
pci_set_drvdata(pdev, NULL);
return 0;
}
type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
- box = uncore_alloc_box(type, NUMA_NO_NODE);
- if (!box)
- return -ENOMEM;
-
/*
* for performance monitoring unit with multiple boxes,
* each box has a different function id.
@@ -902,32 +892,35 @@ static int uncore_pci_probe(struct pci_d
pmu++;
}
+ if (WARN_ON_ONCE(pmu->boxes[pkg] != NULL))
+ return -EINVAL;
+
+ box = uncore_alloc_box(type, NUMA_NO_NODE);
+ if (!box)
+ return -ENOMEM;
+
if (pmu->func_id < 0)
pmu->func_id = pdev->devfn;
else
WARN_ON_ONCE(pmu->func_id != pdev->devfn);
- box->phys_id = phys_id;
+ atomic_inc(&box->refcnt);
+ box->pci_phys_id = phys_id;
+ box->pkgid = pkg;
box->pci_dev = pdev;
box->pmu = pmu;
uncore_box_init(box);
pci_set_drvdata(pdev, box);
- raw_spin_lock(&uncore_box_lock);
- if (list_empty(&pmu->box_list))
- first_box = true;
- list_add_tail(&box->list, &pmu->box_list);
- raw_spin_unlock(&uncore_box_lock);
-
- if (!first_box)
+ pmu->boxes[pkg] = box;
+ if (atomic_inc_return(&pmu->activeboxes) > 1)
return 0;
+ /* First active box registers the pmu */
ret = uncore_pmu_register(pmu);
if (ret) {
pci_set_drvdata(pdev, NULL);
- raw_spin_lock(&uncore_box_lock);
- list_del(&box->list);
- raw_spin_unlock(&uncore_box_lock);
+ pmu->boxes[pkg] = NULL;
uncore_box_exit(box);
kfree(box);
}
@@ -938,15 +931,16 @@ static void uncore_pci_remove(struct pci
{
struct intel_uncore_box *box = pci_get_drvdata(pdev);
struct intel_uncore_pmu *pmu;
- int i, cpu, phys_id;
- bool last_box = false;
+ int i, phys_id, pkg;
phys_id = uncore_pcibus_to_physid(pdev->bus);
+ pkg = topology_phys_to_logical_pkg(phys_id);
+
box = pci_get_drvdata(pdev);
if (!box) {
for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
- if (uncore_extra_pci_dev[phys_id][i] == pdev) {
- uncore_extra_pci_dev[phys_id][i] = NULL;
+ if (uncore_extra_pci_dev[pkg].dev[i] == pdev) {
+ uncore_extra_pci_dev[pkg].dev[i] = NULL;
break;
}
}
@@ -955,34 +949,20 @@ static void uncore_pci_remove(struct pci
}
pmu = box->pmu;
- if (WARN_ON_ONCE(phys_id != box->phys_id))
+ if (WARN_ON_ONCE(phys_id != box->pci_phys_id))
return;
pci_set_drvdata(pdev, NULL);
-
- raw_spin_lock(&uncore_box_lock);
- list_del(&box->list);
- if (list_empty(&pmu->box_list))
- last_box = true;
- raw_spin_unlock(&uncore_box_lock);
-
- for_each_possible_cpu(cpu) {
- if (*per_cpu_ptr(pmu->box, cpu) == box) {
- *per_cpu_ptr(pmu->box, cpu) = NULL;
- atomic_dec(&box->refcnt);
- }
- }
-
- WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
+ pmu->boxes[pkg] = NULL;
+ if (atomic_dec_return(&pmu->activeboxes) == 0)
+ uncore_pmu_unregister(pmu);
uncore_box_exit(box);
kfree(box);
-
- if (last_box)
- uncore_pmu_unregister(pmu);
}
static int __init uncore_pci_init(void)
{
+ size_t size;
int ret;
switch (boot_cpu_data.x86_model) {
@@ -1025,24 +1005,34 @@ static int __init uncore_pci_init(void)
if (ret)
return ret;
- ret = uncore_types_init(uncore_pci_uncores);
- if (ret)
+ size = max_packages * sizeof(struct pci_extra_dev);
+ uncore_extra_pci_dev = kzalloc(size, GFP_KERNEL);
+ if (!uncore_extra_pci_dev) {
+ ret = -ENOMEM;
goto err;
+ }
+
+ ret = uncore_types_init(uncore_pci_uncores, false);
+ if (ret)
+ goto errtype;
uncore_pci_driver->probe = uncore_pci_probe;
uncore_pci_driver->remove = uncore_pci_remove;
ret = pci_register_driver(uncore_pci_driver);
if (ret)
- goto err;
+ goto errtype;
pcidrv_registered = true;
return 0;
-err:
+errtype:
uncore_types_exit(uncore_pci_uncores);
- uncore_pci_uncores = empty_uncore;
+ kfree(uncore_extra_pci_dev);
+ uncore_extra_pci_dev = NULL;
uncore_free_pcibus_map();
+err:
+ uncore_pci_uncores = empty_uncore;
return ret;
}
@@ -1052,110 +1042,81 @@ static void __init uncore_pci_exit(void)
pcidrv_registered = false;
pci_unregister_driver(uncore_pci_driver);
uncore_types_exit(uncore_pci_uncores);
+ kfree(uncore_extra_pci_dev);
uncore_free_pcibus_map();
}
}
-/* CPU hot plug/unplug are serialized by cpu_add_remove_lock mutex */
-static LIST_HEAD(boxes_to_free);
-
-static void uncore_kfree_boxes(void)
-{
- struct intel_uncore_box *box;
-
- while (!list_empty(&boxes_to_free)) {
- box = list_entry(boxes_to_free.next,
- struct intel_uncore_box, list);
- list_del(&box->list);
- kfree(box);
- }
-}
-
static void uncore_cpu_dying(int cpu)
{
- struct intel_uncore_type *type;
+ struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
- int i, j;
+ int i, pkg;
- for (i = 0; uncore_msr_uncores[i]; i++) {
- type = uncore_msr_uncores[i];
- for (j = 0; j < type->num_boxes; j++) {
- pmu = &type->pmus[j];
- box = *per_cpu_ptr(pmu->box, cpu);
- *per_cpu_ptr(pmu->box, cpu) = NULL;
- if (box && atomic_dec_and_test(&box->refcnt)) {
- list_add(&box->list, &boxes_to_free);
+ pkg = topology_logical_package_id(cpu);
+ for (; *types; types++) {
+ type = *types;
+ 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);
- }
}
}
}
-static int uncore_cpu_starting(int cpu)
+static void uncore_cpu_starting(int cpu, bool init)
{
- struct intel_uncore_type *type;
+ struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
- struct intel_uncore_box *box, *exist;
- int i, j, k, phys_id;
+ struct intel_uncore_box *box;
+ int i, pkg, ncpus = 1;
- phys_id = topology_physical_package_id(cpu);
+ if (init) {
+ /*
+ * On init we get the number of online cpus in the package
+ * and set refcount for all of them.
+ */
+ ncpus = cpumask_weight(topology_core_cpumask(cpu));
+ }
- for (i = 0; uncore_msr_uncores[i]; i++) {
- type = uncore_msr_uncores[i];
- for (j = 0; j < type->num_boxes; j++) {
- pmu = &type->pmus[j];
- box = *per_cpu_ptr(pmu->box, cpu);
- /* called by uncore_cpu_init? */
- if (box && box->phys_id >= 0) {
- uncore_box_init(box);
+ pkg = topology_logical_package_id(cpu);
+ for (; *types; types++) {
+ type = *types;
+ pmu = type->pmus;
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ box = pmu->boxes[pkg];
+ if (!box)
continue;
- }
-
- for_each_online_cpu(k) {
- exist = *per_cpu_ptr(pmu->box, k);
- if (exist && exist->phys_id == phys_id) {
- atomic_inc(&exist->refcnt);
- *per_cpu_ptr(pmu->box, cpu) = exist;
- if (box) {
- list_add(&box->list,
- &boxes_to_free);
- box = NULL;
- }
- break;
- }
- }
-
- if (box) {
- box->phys_id = phys_id;
+ /* The first cpu on a package activates the box */
+ if (atomic_add_return(ncpus, &box->refcnt) == ncpus)
uncore_box_init(box);
- }
}
}
- return 0;
}
-static int uncore_cpu_prepare(int cpu, int phys_id)
+static int uncore_cpu_prepare(int cpu)
{
- struct intel_uncore_type *type;
+ struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
- int i, j;
-
- for (i = 0; uncore_msr_uncores[i]; i++) {
- type = uncore_msr_uncores[i];
- for (j = 0; j < type->num_boxes; j++) {
- pmu = &type->pmus[j];
- if (pmu->func_id < 0)
- pmu->func_id = j;
+ int i, pkg;
+ pkg = topology_logical_package_id(cpu);
+ for (; *types; types++) {
+ type = *types;
+ pmu = type->pmus;
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ if (pmu->boxes[pkg])
+ continue;
+ /* First cpu of a package allocates the box */
box = uncore_alloc_box(type, cpu_to_node(cpu));
if (!box)
return -ENOMEM;
-
box->pmu = pmu;
- box->phys_id = phys_id;
- *per_cpu_ptr(pmu->box, cpu) = box;
+ box->pkgid = pkg;
+ pmu->boxes[pkg] = box;
}
}
return 0;
@@ -1166,13 +1127,11 @@ static void uncore_change_type_ctx(struc
{
struct intel_uncore_pmu *pmu = type->pmus;
struct intel_uncore_box *box;
- int i;
+ int i, pkg;
+ pkg = topology_logical_package_id(old_cpu < 0 ? new_cpu : old_cpu);
for (i = 0; i < type->num_boxes; i++, pmu++) {
- if (old_cpu < 0)
- box = uncore_pmu_to_box(pmu, new_cpu);
- else
- box = uncore_pmu_to_box(pmu, old_cpu);
+ box = pmu->boxes[pkg];
if (!box)
continue;
@@ -1202,27 +1161,20 @@ static void uncore_change_context(struct
static void uncore_event_exit_cpu(int cpu)
{
- int i, phys_id, target;
+ int target;
- /* 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))
return;
- /* find a new cpu to collect uncore events */
- phys_id = topology_physical_package_id(cpu);
- target = -1;
- for_each_online_cpu(i) {
- if (i == cpu)
- continue;
- if (phys_id == topology_physical_package_id(i)) {
- target = i;
- break;
- }
- }
+ /* Find a new cpu to collect uncore events */
+ target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
- /* migrate uncore events to the new cpu */
- if (target >= 0)
+ /* Migrate uncore events to the new target */
+ if (target < nr_cpu_ids)
cpumask_set_cpu(target, &uncore_cpu_mask);
+ else
+ target = -1;
uncore_change_context(uncore_msr_uncores, cpu, target);
uncore_change_context(uncore_pci_uncores, cpu, target);
@@ -1230,13 +1182,15 @@ static void uncore_event_exit_cpu(int cp
static void uncore_event_init_cpu(int cpu)
{
- int i, phys_id;
+ int target;
- phys_id = topology_physical_package_id(cpu);
- for_each_cpu(i, &uncore_cpu_mask) {
- if (phys_id == topology_physical_package_id(i))
- return;
- }
+ /*
+ * Check if there is an online cpu in the package
+ * which collects uncore events already.
+ */
+ target = cpumask_any_and(&uncore_cpu_mask, topology_core_cpumask(cpu));
+ if (target < nr_cpu_ids)
+ return;
cpumask_set_cpu(cpu, &uncore_cpu_mask);
@@ -1249,38 +1203,25 @@ static int uncore_cpu_notifier(struct no
{
unsigned int cpu = (long)hcpu;
- /* allocate/free data structure for uncore box */
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- return notifier_from_errno(uncore_cpu_prepare(cpu, -1));
+ return notifier_from_errno(uncore_cpu_prepare(cpu));
+
case CPU_STARTING:
- uncore_cpu_starting(cpu);
+ uncore_cpu_starting(cpu, false);
+ case CPU_DOWN_FAILED:
+ uncore_event_init_cpu(cpu);
break;
+
case CPU_UP_CANCELED:
case CPU_DYING:
uncore_cpu_dying(cpu);
break;
- case CPU_ONLINE:
- case CPU_DEAD:
- uncore_kfree_boxes();
- break;
- default:
- break;
- }
- /* select the cpu that collects uncore events */
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_DOWN_FAILED:
- case CPU_STARTING:
- uncore_event_init_cpu(cpu);
- break;
case CPU_DOWN_PREPARE:
uncore_event_exit_cpu(cpu);
break;
- default:
- break;
}
-
return NOTIFY_OK;
}
@@ -1357,7 +1298,7 @@ static int __init uncore_cpu_init(void)
return 0;
}
- ret = uncore_types_init(uncore_msr_uncores);
+ ret = uncore_types_init(uncore_msr_uncores, true);
if (ret)
goto err;
@@ -1373,39 +1314,34 @@ static int __init uncore_cpu_init(void)
static void __init uncore_cpu_setup(void *dummy)
{
- uncore_cpu_starting(smp_processor_id());
+ uncore_cpu_starting(smp_processor_id(), true);
}
+/* Lazy to avoid allocation of a few bytes for the normal case */
+static __initdata DECLARE_BITMAP(packages, MAX_LOCAL_APIC);
+
static int __init uncore_cpumask_init(void)
{
- int cpu, ret = 0;
-
- cpu_notifier_register_begin();
+ unsigned int cpu;
for_each_online_cpu(cpu) {
- int i, phys_id = topology_physical_package_id(cpu);
+ unsigned int pkg = topology_logical_package_id(cpu);
+ int ret;
- for_each_cpu(i, &uncore_cpu_mask) {
- if (phys_id == topology_physical_package_id(i)) {
- phys_id = -1;
- break;
- }
- }
- if (phys_id < 0)
+ if (test_and_set_bit(pkg, packages))
continue;
-
- ret = uncore_cpu_prepare(cpu, phys_id);
+ /*
+ * The first online cpu of each package takes the refcounts
+ * for all other online cpus in that package.
+ */
+ ret = uncore_cpu_prepare(cpu);
if (ret)
- goto out;
+ return ret;
uncore_event_init_cpu(cpu);
+ smp_call_function_single(cpu, uncore_cpu_setup, NULL, 1);
}
- on_each_cpu(uncore_cpu_setup, NULL, 1);
-
__register_cpu_notifier(&uncore_cpu_nb);
-
-out:
- cpu_notifier_register_done();
- return ret;
+ return 0;
}
static int __init intel_uncore_init(void)
@@ -1418,22 +1354,26 @@ static int __init intel_uncore_init(void
if (cpu_has_hypervisor)
return -ENODEV;
+ max_packages = topology_max_packages();
+
ret = uncore_pci_init();
if (ret)
return ret;
ret = uncore_cpu_init();
if (ret)
- goto errpci;
+ goto err;
+
+ cpu_notifier_register_begin();
ret = uncore_cpumask_init();
if (ret)
- goto errcpu;
-
+ goto err;
+ cpu_notifier_register_done();
return 0;
-errcpu:
+err:
uncore_types_exit(uncore_msr_uncores);
-errpci:
uncore_pci_exit();
+ cpu_notifier_register_done();
return ret;
}
device_initcall(intel_uncore_init);
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -19,11 +19,12 @@
#define UNCORE_EXTRA_PCI_DEV 0xff
#define UNCORE_EXTRA_PCI_DEV_MAX 3
-/* support up to 8 sockets */
-#define UNCORE_SOCKET_MAX 8
-
#define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
+struct pci_extra_dev {
+ struct pci_dev *dev[UNCORE_EXTRA_PCI_DEV_MAX];
+};
+
struct intel_uncore_ops;
struct intel_uncore_pmu;
struct intel_uncore_box;
@@ -79,9 +80,9 @@ struct intel_uncore_pmu {
int pmu_idx;
int func_id;
bool registered;
+ atomic_t activeboxes;
struct intel_uncore_type *type;
- struct intel_uncore_box ** __percpu box;
- struct list_head box_list;
+ struct intel_uncore_box **boxes;
};
struct intel_uncore_extra_reg {
@@ -91,7 +92,8 @@ struct intel_uncore_extra_reg {
};
struct intel_uncore_box {
- int phys_id;
+ int pci_phys_id;
+ int pkgid;
int n_active; /* number of active events */
int n_events;
int cpu; /* cpu to collect events */
@@ -316,7 +318,7 @@ static inline void uncore_box_exit(struc
static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
{
- return (box->phys_id < 0);
+ return (box->pkgid < 0);
}
static inline struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
@@ -345,7 +347,7 @@ extern struct intel_uncore_type **uncore
extern struct pci_driver *uncore_pci_driver;
extern raw_spinlock_t pci2phy_map_lock;
extern struct list_head pci2phy_map_head;
-extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+extern struct pci_extra_dev *uncore_extra_pci_dev;
extern struct event_constraint uncore_constraint_empty;
/* perf_event_intel_uncore_snb.c */
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
@@ -987,7 +987,9 @@ static void snbep_qpi_enable_event(struc
if (reg1->idx != EXTRA_REG_NONE) {
int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
- struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx];
+ int pkg = topology_phys_to_logical_pkg(box->pci_phys_id);
+ struct pci_dev *filter_pdev = uncore_extra_pci_dev[pkg].dev[idx];
+
if (filter_pdev) {
pci_write_config_dword(filter_pdev, reg1->reg,
(u32)reg1->config);
@@ -2521,14 +2523,16 @@ static struct intel_uncore_type *hswep_m
void hswep_uncore_cpu_init(void)
{
+ int pkg = topology_phys_to_logical_pkg(0);
+
if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
/* Detect 6-8 core systems with only two SBOXes */
- if (uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3]) {
+ if (uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3]) {
u32 capid4;
- pci_read_config_dword(uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3],
+ pci_read_config_dword(uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3],
0x94, &capid4);
if (((capid4 >> 6) & 0x3) == 0)
hswep_uncore_sbox.num_boxes = 2;
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 24/28] x86/perf/intel/rapl: Make pmu lock raw |
| Message-ID | <r4WH1-4WG-35@gated-at.bofh.it> |
| In reply to | #1339368 |
This lock is taken in hard interrupt context even on Preempt-RT. Make it raw
so RT does not have to patch it.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_rapl.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
@@ -120,7 +120,7 @@ static struct perf_pmu_events_attr event
};
struct rapl_pmu {
- spinlock_t lock;
+ raw_spinlock_t lock;
int n_active;
struct list_head active_list;
struct pmu *pmu;
@@ -210,12 +210,12 @@ static enum hrtimer_restart rapl_hrtimer
if (!pmu->n_active)
return HRTIMER_NORESTART;
- spin_lock_irqsave(&pmu->lock, flags);
+ raw_spin_lock_irqsave(&pmu->lock, flags);
list_for_each_entry(event, &pmu->active_list, active_entry)
rapl_event_update(event);
- spin_unlock_irqrestore(&pmu->lock, flags);
+ raw_spin_unlock_irqrestore(&pmu->lock, flags);
hrtimer_forward_now(hrtimer, pmu->timer_interval);
@@ -252,9 +252,9 @@ static void rapl_pmu_event_start(struct
struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu);
unsigned long flags;
- spin_lock_irqsave(&pmu->lock, flags);
+ raw_spin_lock_irqsave(&pmu->lock, flags);
__rapl_pmu_event_start(pmu, event);
- spin_unlock_irqrestore(&pmu->lock, flags);
+ raw_spin_unlock_irqrestore(&pmu->lock, flags);
}
static void rapl_pmu_event_stop(struct perf_event *event, int mode)
@@ -263,7 +263,7 @@ static void rapl_pmu_event_stop(struct p
struct hw_perf_event *hwc = &event->hw;
unsigned long flags;
- spin_lock_irqsave(&pmu->lock, flags);
+ raw_spin_lock_irqsave(&pmu->lock, flags);
/* mark event as deactivated and stopped */
if (!(hwc->state & PERF_HES_STOPPED)) {
@@ -288,7 +288,7 @@ static void rapl_pmu_event_stop(struct p
hwc->state |= PERF_HES_UPTODATE;
}
- spin_unlock_irqrestore(&pmu->lock, flags);
+ raw_spin_unlock_irqrestore(&pmu->lock, flags);
}
static int rapl_pmu_event_add(struct perf_event *event, int mode)
@@ -297,14 +297,14 @@ static int rapl_pmu_event_add(struct per
struct hw_perf_event *hwc = &event->hw;
unsigned long flags;
- spin_lock_irqsave(&pmu->lock, flags);
+ raw_spin_lock_irqsave(&pmu->lock, flags);
hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
if (mode & PERF_EF_START)
__rapl_pmu_event_start(pmu, event);
- spin_unlock_irqrestore(&pmu->lock, flags);
+ raw_spin_unlock_irqrestore(&pmu->lock, flags);
return 0;
}
@@ -567,7 +567,7 @@ static int rapl_cpu_prepare(int cpu)
pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
if (!pmu)
return -1;
- spin_lock_init(&pmu->lock);
+ raw_spin_lock_init(&pmu->lock);
INIT_LIST_HEAD(&pmu->active_list);
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 02/28] x86/perf/intel/uncore: Simplify error rollback |
| Message-ID | <r4WH1-4WG-37@gated-at.bofh.it> |
| In reply to | #1339368 |
No point in doing partial rollbacks. Robustify uncore_exit_type() so it does
not dereference type->pmus unconditionally and remove all the partial rollback
hackery.
Preparatory patch for proper error handling.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 45 +++++++++++++-------------
1 file changed, 24 insertions(+), 21 deletions(-)
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -767,10 +767,12 @@ static void __init uncore_type_exit(stru
{
int i;
- for (i = 0; i < type->num_boxes; i++)
- free_percpu(type->pmus[i].box);
- kfree(type->pmus);
- type->pmus = NULL;
+ if (type->pmus) {
+ for (i = 0; i < type->num_boxes; i++)
+ free_percpu(type->pmus[i].box);
+ kfree(type->pmus);
+ type->pmus = NULL;
+ }
kfree(type->events_group);
type->events_group = NULL;
}
@@ -778,6 +780,7 @@ static void __init uncore_type_exit(stru
static void __init uncore_types_exit(struct intel_uncore_type **types)
{
int i;
+
for (i = 0; types[i]; i++)
uncore_type_exit(types[i]);
}
@@ -806,7 +809,7 @@ static int __init uncore_type_init(struc
INIT_LIST_HEAD(&pmus[i].box_list);
pmus[i].box = alloc_percpu(struct intel_uncore_box *);
if (!pmus[i].box)
- goto fail;
+ return -ENOMEM;
}
if (type->event_descs) {
@@ -817,7 +820,7 @@ static int __init uncore_type_init(struc
attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) +
sizeof(*attr_group), GFP_KERNEL);
if (!attr_group)
- goto fail;
+ return -ENOMEM;
attrs = (struct attribute **)(attr_group + 1);
attr_group->name = "events";
@@ -831,9 +834,6 @@ static int __init uncore_type_init(struc
type->pmu_group = &uncore_pmu_attr_group;
return 0;
-fail:
- uncore_type_exit(type);
- return -ENOMEM;
}
static int __init uncore_types_init(struct intel_uncore_type **types)
@@ -843,13 +843,9 @@ static int __init uncore_types_init(stru
for (i = 0; types[i]; i++) {
ret = uncore_type_init(types[i]);
if (ret)
- goto fail;
+ return ret;
}
return 0;
-fail:
- while (--i >= 0)
- uncore_type_exit(types[i]);
- return ret;
}
/*
@@ -1007,17 +1003,21 @@ static int __init uncore_pci_init(void)
ret = uncore_types_init(uncore_pci_uncores);
if (ret)
- return ret;
+ goto err;
uncore_pci_driver->probe = uncore_pci_probe;
uncore_pci_driver->remove = uncore_pci_remove;
ret = pci_register_driver(uncore_pci_driver);
- if (ret == 0)
- pcidrv_registered = true;
- else
- uncore_types_exit(uncore_pci_uncores);
+ if (ret)
+ goto err;
+
+ pcidrv_registered = true;
+ return 0;
+err:
+ uncore_types_exit(uncore_pci_uncores);
+ uncore_pci_uncores = empty_uncore;
return ret;
}
@@ -1316,9 +1316,12 @@ static int __init uncore_cpu_init(void)
ret = uncore_types_init(uncore_msr_uncores);
if (ret)
- return ret;
-
+ goto err;
return 0;
+err:
+ uncore_types_exit(uncore_msr_uncores);
+ uncore_msr_uncores = empty_uncore;
+ return ret;
}
static int __init uncore_pmus_register(void)
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 03/28] x86/perf/intel/uncore: Fix error handling |
| Message-ID | <r4WH0-4WG-31@gated-at.bofh.it> |
| In reply to | #1339368 |
This driver lacks any form of proper error handling. If initialization fails
or hotplug prepare fails, it lets the facility with half initialized stuff
around.
Fix the state and memory leaks in a first step. As a second step we need to
undo the hardware state which is set via uncore_box_init() on some of the
uncore implementations.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 122 ++++++++++++++++++--------
arch/x86/kernel/cpu/perf_event_intel_uncore.h | 15 +--
2 files changed, 94 insertions(+), 43 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -38,6 +38,16 @@ int uncore_pcibus_to_physid(struct pci_b
return phys_id;
}
+static void uncore_free_pcibus_map(void)
+{
+ struct pci2phy_map *map, *tmp;
+
+ list_for_each_entry_safe(map, tmp, &pci2phy_map_head, list) {
+ list_del(&map->list);
+ kfree(map);
+ }
+}
+
struct pci2phy_map *__find_pci2phy_map(int segment)
{
struct pci2phy_map *map, *alloc = NULL;
@@ -760,16 +770,28 @@ static int uncore_pmu_register(struct in
}
ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
+ if (!ret)
+ pmu->registered = true;
return ret;
}
+static void uncore_pmu_unregister(struct intel_uncore_pmu *pmu)
+{
+ if (!pmu->registered)
+ return;
+ perf_pmu_unregister(&pmu->pmu);
+ pmu->registered = false;
+}
+
static void __init uncore_type_exit(struct intel_uncore_type *type)
{
int i;
if (type->pmus) {
- for (i = 0; i < type->num_boxes; i++)
+ for (i = 0; i < type->num_boxes; i++) {
+ uncore_pmu_unregister(&type->pmus[i]);
free_percpu(type->pmus[i].box);
+ }
kfree(type->pmus);
type->pmus = NULL;
}
@@ -856,8 +878,8 @@ static int uncore_pci_probe(struct pci_d
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
struct intel_uncore_type *type;
- int phys_id;
bool first_box = false;
+ int phys_id, ret;
phys_id = uncore_pcibus_to_physid(pdev->bus);
if (phys_id < 0)
@@ -906,9 +928,18 @@ static int uncore_pci_probe(struct pci_d
list_add_tail(&box->list, &pmu->box_list);
raw_spin_unlock(&uncore_box_lock);
- if (first_box)
- uncore_pmu_register(pmu);
- return 0;
+ if (!first_box)
+ return 0;
+
+ ret = uncore_pmu_register(pmu);
+ if (ret) {
+ pci_set_drvdata(pdev, NULL);
+ raw_spin_lock(&uncore_box_lock);
+ list_del(&box->list);
+ raw_spin_unlock(&uncore_box_lock);
+ kfree(box);
+ }
+ return ret;
}
static void uncore_pci_remove(struct pci_dev *pdev)
@@ -954,7 +985,7 @@ static void uncore_pci_remove(struct pci
kfree(box);
if (last_box)
- perf_pmu_unregister(&pmu->pmu);
+ uncore_pmu_unregister(pmu);
}
static int __init uncore_pci_init(void)
@@ -1018,6 +1049,7 @@ static int __init uncore_pci_init(void)
err:
uncore_types_exit(uncore_pci_uncores);
uncore_pci_uncores = empty_uncore;
+ uncore_free_pcibus_map();
return ret;
}
@@ -1027,6 +1059,7 @@ static void __init uncore_pci_exit(void)
pcidrv_registered = false;
pci_unregister_driver(uncore_pci_driver);
uncore_types_exit(uncore_pci_uncores);
+ uncore_free_pcibus_map();
}
}
@@ -1223,8 +1256,7 @@ static int uncore_cpu_notifier(struct no
/* allocate/free data structure for uncore box */
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- uncore_cpu_prepare(cpu, -1);
- break;
+ return notifier_from_errno(uncore_cpu_prepare(cpu, -1));
case CPU_STARTING:
uncore_cpu_starting(cpu);
break;
@@ -1265,9 +1297,29 @@ static struct notifier_block uncore_cpu_
.priority = CPU_PRI_PERF + 1,
};
-static void __init uncore_cpu_setup(void *dummy)
+static int __init type_pmu_register(struct intel_uncore_type *type)
{
- uncore_cpu_starting(smp_processor_id());
+ int i, ret;
+
+ for (i = 0; i < type->num_boxes; i++) {
+ ret = uncore_pmu_register(&type->pmus[i]);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int __init uncore_msr_pmus_register(void)
+{
+ struct intel_uncore_type **types = uncore_msr_uncores;
+ int ret;
+
+ while (*types) {
+ ret = type_pmu_register(*types++);
+ if (ret)
+ return ret;
+ }
+ return 0;
}
static int __init uncore_cpu_init(void)
@@ -1317,6 +1369,10 @@ static int __init uncore_cpu_init(void)
ret = uncore_types_init(uncore_msr_uncores);
if (ret)
goto err;
+
+ ret = uncore_msr_pmus_register();
+ if (ret)
+ goto err;
return 0;
err:
uncore_types_exit(uncore_msr_uncores);
@@ -1324,26 +1380,14 @@ static int __init uncore_cpu_init(void)
return ret;
}
-static int __init uncore_pmus_register(void)
+static void __init uncore_cpu_setup(void *dummy)
{
- struct intel_uncore_pmu *pmu;
- struct intel_uncore_type *type;
- int i, j;
-
- for (i = 0; uncore_msr_uncores[i]; i++) {
- type = uncore_msr_uncores[i];
- for (j = 0; j < type->num_boxes; j++) {
- pmu = &type->pmus[j];
- uncore_pmu_register(pmu);
- }
- }
-
- return 0;
+ uncore_cpu_starting(smp_processor_id());
}
-static void __init uncore_cpumask_init(void)
+static int __init uncore_cpumask_init(void)
{
- int cpu;
+ int cpu, ret = 0;
cpu_notifier_register_begin();
@@ -1359,17 +1403,20 @@ static void __init uncore_cpumask_init(v
if (phys_id < 0)
continue;
- uncore_cpu_prepare(cpu, phys_id);
+ ret = uncore_cpu_prepare(cpu, phys_id);
+ if (ret)
+ goto out;
uncore_event_init_cpu(cpu);
}
on_each_cpu(uncore_cpu_setup, NULL, 1);
__register_cpu_notifier(&uncore_cpu_nb);
+out:
cpu_notifier_register_done();
+ return ret;
}
-
static int __init intel_uncore_init(void)
{
int ret;
@@ -1382,17 +1429,20 @@ static int __init intel_uncore_init(void
ret = uncore_pci_init();
if (ret)
- goto fail;
+ return ret;
ret = uncore_cpu_init();
- if (ret) {
- uncore_pci_exit();
- goto fail;
- }
- uncore_cpumask_init();
+ if (ret)
+ goto errpci;
+ ret = uncore_cpumask_init();
+ if (ret)
+ goto errcpu;
- uncore_pmus_register();
return 0;
-fail:
+
+errcpu:
+ uncore_types_exit(uncore_msr_uncores);
+errpci:
+ uncore_pci_exit();
return ret;
}
device_initcall(intel_uncore_init);
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -73,13 +73,14 @@ struct intel_uncore_ops {
};
struct intel_uncore_pmu {
- struct pmu pmu;
- char name[UNCORE_PMU_NAME_LEN];
- int pmu_idx;
- int func_id;
- struct intel_uncore_type *type;
- struct intel_uncore_box ** __percpu box;
- struct list_head box_list;
+ struct pmu pmu;
+ char name[UNCORE_PMU_NAME_LEN];
+ int pmu_idx;
+ int func_id;
+ bool registered;
+ struct intel_uncore_type *type;
+ struct intel_uncore_box ** __percpu box;
+ struct list_head box_list;
};
struct intel_uncore_extra_reg {
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output |
| Message-ID | <r4WH1-4WG-41@gated-at.bofh.it> |
| In reply to | #1339368 |
The output is inconsistent. Use a proper pr_fmt prefix and split out the
advertisement into a seperate function.
Remove the WARN_ON in the failure case. It's pointless as we already know
where it failed.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_rapl.c | 42 +++++++++++++++-------------
1 file changed, 23 insertions(+), 19 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
@@ -44,6 +44,9 @@
* the duration of the measurement. Tools may use a function such as
* ldexp(raw_count, -32);
*/
+
+#define pr_fmt(fmt) "RAPL PMU: " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/perf_event.h>
@@ -144,7 +147,7 @@ static inline u64 rapl_read_counter(stru
static inline u64 rapl_scale(u64 v, int cfg)
{
if (cfg > NR_RAPL_DOMAINS) {
- pr_warn("invalid domain %d, failed to scale data\n", cfg);
+ pr_warn("Invalid domain %d, failed to scale data\n", cfg);
return v;
}
/*
@@ -680,6 +683,21 @@ static int rapl_check_hw_unit(void (*qui
return 0;
}
+static void __init rapl_advertise(void)
+{
+ int i;
+
+ pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
+ hweight32(rapl_cntr_mask), rapl_timer_ms);
+
+ for (i = 0; i < NR_RAPL_DOMAINS; i++) {
+ if (rapl_cntr_mask & (1 << i)) {
+ pr_info("hw unit of domain %s 2^-%d Joules\n",
+ rapl_domain_names[i], rapl_hw_unit[i]);
+ }
+ }
+}
+
static void __init cleanup_rapl_pmus(void)
{
int cpu;
@@ -696,7 +714,7 @@ static const struct x86_cpu_id rapl_cpu_
static int __init rapl_pmu_init(void)
{
void (*quirk)(void) = NULL;
- int cpu, ret, i;
+ int cpu, ret;
/*
* check for Intel processor family 6
@@ -751,30 +769,16 @@ static int __init rapl_pmu_init(void)
}
ret = perf_pmu_register(&rapl_pmu_class, "power", -1);
- if (WARN_ON(ret)) {
- pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret);
+ if (ret)
goto out;
- }
__perf_cpu_notifier(rapl_cpu_notifier);
cpu_notifier_register_done();
-
- pr_info("RAPL PMU detected,"
- " API unit is 2^-32 Joules,"
- " %d fixed counters"
- " %llu ms ovfl timer\n",
- hweight32(rapl_cntr_mask),
- rapl_timer_ms);
- for (i = 0; i < NR_RAPL_DOMAINS; i++) {
- if (rapl_cntr_mask & (1 << i)) {
- pr_info("hw unit of domain %s 2^-%d Joules\n",
- rapl_domain_names[i], rapl_hw_unit[i]);
- }
- }
-
+ rapl_advertise();
return 0;
out:
+ pr_warn("Initialization failed (%d), disabled\n", ret);
cleanup_rapl_pmus();
cpu_notifier_register_done();
return ret;
[toc] | [prev] | [next] | [standalone]
| From | Andi Kleen <andi@firstfloor.org> |
|---|---|
| Date | 2016-02-22 19:50 +0100 |
| Subject | Re: [patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output |
| Message-ID | <r53It-1Cz-1@gated-at.bofh.it> |
| In reply to | #1339377 |
Thomas Gleixner <tglx@linutronix.de> writes:
>
> +static void __init rapl_advertise(void)
> +{
> + int i;
> +
> + pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
> + hweight32(rapl_cntr_mask), rapl_timer_ms);
Does the final resulting line contain RAPL for grepping?
Ideally would be similar as before in case someone has a parser for
this.
-Andi
--
ak@linux.intel.com -- Speaking for myself only
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 20:00 +0100 |
| Subject | Re: [patch V2 22/28] x86/perf/intel/rapl: Cleanup the printk output |
| Message-ID | <r53Sa-1FT-13@gated-at.bofh.it> |
| In reply to | #1339811 |
Andi,
On Mon, 22 Feb 2016, Andi Kleen wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
> >
> > +static void __init rapl_advertise(void)
> > +{
> > + int i;
> > +
> > + pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
> > + hweight32(rapl_cntr_mask), rapl_timer_ms);
>
> Does the final resulting line contain RAPL for grepping?
Yes. That's what the pr_fmt prepends.
[35282.080376] calling rapl_pmu_init+0x0/0xff5 [perf_event_intel_rapl] @ 10523
[35282.080679] RAPL PMU: API unit is 2^-32 Joules, 3 fixed counters, 655360 ms ovfl timer
[35282.088634] RAPL PMU: hw unit of domain pp0-core 2^-14 Joules
[35282.094394] RAPL PMU: hw unit of domain package 2^-14 Joules
[35282.111347] RAPL PMU: hw unit of domain dram 2^-16 Joules
[35282.127514] initcall rapl_pmu_init+0x0/0xff5 [perf_event_intel_rapl] returned 0 after 46023 usecs
> Ideally would be similar as before in case someone has a parser for
> this.
It is.
Thanks,
tglx
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 08/28] x86/perf/uncore: Make uncore_pcibus_to_physid static |
| Message-ID | <r4WH1-4WG-43@gated-at.bofh.it> |
| In reply to | #1339368 |
No users outside of this file.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 2 +-
arch/x86/kernel/cpu/perf_event_intel_uncore.h | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -21,7 +21,7 @@ static struct event_constraint uncore_co
struct event_constraint uncore_constraint_empty =
EVENT_CONSTRAINT(0, 0, 0);
-int uncore_pcibus_to_physid(struct pci_bus *bus)
+static int uncore_pcibus_to_physid(struct pci_bus *bus)
{
struct pci2phy_map *map;
int phys_id = -1;
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -125,7 +125,6 @@ struct pci2phy_map {
int pbus_to_physid[256];
};
-int uncore_pcibus_to_physid(struct pci_bus *bus);
struct pci2phy_map *__find_pci2phy_map(int segment);
ssize_t uncore_event_show(struct kobject *kobj,
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 11/28] x86/topology: Create logical package id |
| Message-ID | <r4WH1-4WG-51@gated-at.bofh.it> |
| In reply to | #1339368 |
For per package oriented services we must be able to rely on the number of cpu
packages to be within bounds. Create a tracking facility, which
- calculates the number of possible packages depending on nr_cpu_ids after
boot
- makes sure that the package id is within the number of possible packages. If
the apic id is outside we map it to a logical package id if there is enough
space available.
Provide interfaces for drivers to query the mapping and do translations from
physcial to logical ids.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/include/asm/processor.h | 2
arch/x86/include/asm/topology.h | 10 +++
arch/x86/kernel/apic/apic.c | 14 +++++
arch/x86/kernel/cpu/common.c | 2
arch/x86/kernel/cpu/intel.c | 13 +++++
arch/x86/kernel/cpu/proc.c | 1
arch/x86/kernel/smpboot.c | 100 +++++++++++++++++++++++++++++++++++++++
7 files changed, 142 insertions(+)
Index: b/arch/x86/include/asm/processor.h
===================================================================
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -129,6 +129,8 @@ struct cpuinfo_x86 {
u16 booted_cores;
/* Physical processor id: */
u16 phys_proc_id;
+ /* Logical processor id: */
+ u16 logical_proc_id;
/* Core id: */
u16 cpu_core_id;
/* Compute unit id */
Index: b/arch/x86/include/asm/topology.h
===================================================================
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -119,12 +119,22 @@ static inline void setup_node_to_cpumask
extern const struct cpumask *cpu_coregroup_mask(int cpu);
+#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_core_id(cpu) (cpu_data(cpu).cpu_core_id)
#ifdef ENABLE_TOPO_DEFINES
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
+
+extern unsigned int __max_logical_packages;
+#define topology_max_packages() (__max_logical_packages)
+int topology_update_package_map(unsigned int apicid, unsigned int cpu);
+extern int topology_phys_to_logical_pkg(unsigned int pkg);
+#else
+#define topology_max_packages() (1)
+static inline int
+topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; }
#endif
static inline void arch_fix_phys_package_id(int num, u32 slot)
Index: b/arch/x86/kernel/apic/apic.c
===================================================================
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2078,6 +2078,20 @@ int generic_processor_info(int apicid, i
cpu = cpumask_next_zero(-1, cpu_present_mask);
/*
+ * This can happen on physical hotplug. The sanity check at boot time
+ * is done from native_smp_prepare_cpus() after num_possible_cpus() is
+ * established.
+ */
+ if (topology_update_package_map(apicid, cpu) < 0) {
+ int thiscpu = max + disabled_cpus;
+
+ pr_warning("ACPI: Package limit reached. Processor %d/0x%x ignored.\n",
+ thiscpu, apicid);
+ disabled_cpus++;
+ return -ENOSPC;
+ }
+
+ /*
* Validate version
*/
if (version == 0x0) {
Index: b/arch/x86/kernel/cpu/common.c
===================================================================
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -977,6 +977,8 @@ static void identify_cpu(struct cpuinfo_
#ifdef CONFIG_NUMA
numa_add_cpu(smp_processor_id());
#endif
+ /* The boot/hotplug time assigment got cleared, restore it */
+ c->logical_proc_id = topology_phys_to_logical_pkg(c->phys_proc_id);
}
/*
Index: b/arch/x86/kernel/cpu/intel.c
===================================================================
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -160,6 +160,19 @@ static void early_init_intel(struct cpui
pr_info("Disabling PGE capability bit\n");
setup_clear_cpu_cap(X86_FEATURE_PGE);
}
+
+ 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);
+ }
}
#ifdef CONFIG_X86_32
Index: b/arch/x86/kernel/cpu/proc.c
===================================================================
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -12,6 +12,7 @@ static void show_cpuinfo_core(struct seq
{
#ifdef CONFIG_SMP
seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
+ seq_printf(m, "logical id\t: %d\n", c->logical_proc_id);
seq_printf(m, "siblings\t: %d\n",
cpumask_weight(topology_core_cpumask(cpu)));
seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Index: b/arch/x86/kernel/smpboot.c
===================================================================
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -97,6 +97,14 @@ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t
DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
EXPORT_PER_CPU_SYMBOL(cpu_info);
+/* Logical package management. We might want to allocate that dynamically */
+static int *physical_to_logical_pkg __read_mostly;
+static unsigned long *physical_package_map __read_mostly;;
+static unsigned long *logical_package_map __read_mostly;
+static unsigned int max_physical_pkg_id __read_mostly;
+unsigned int __max_logical_packages __read_mostly;
+EXPORT_SYMBOL(__max_logical_packages);
+
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
{
unsigned long flags;
@@ -251,6 +259,97 @@ static void notrace start_secondary(void
cpu_startup_entry(CPUHP_ONLINE);
}
+int topology_update_package_map(unsigned int apicid, unsigned int cpu)
+{
+ unsigned int new, pkg = apicid >> boot_cpu_data.x86_coreid_bits;
+
+ /* Called from early boot ? */
+ if (!physical_package_map)
+ return 0;
+
+ if (pkg >= max_physical_pkg_id)
+ return -EINVAL;
+
+ /* Set the logical package id */
+ if (test_and_set_bit(pkg, physical_package_map))
+ goto found;
+
+ if (pkg < __max_logical_packages) {
+ set_bit(pkg, logical_package_map);
+ physical_to_logical_pkg[pkg] = pkg;
+ goto found;
+ }
+ new = find_first_zero_bit(logical_package_map, __max_logical_packages);
+ if (new >= __max_logical_packages) {
+ physical_to_logical_pkg[pkg] = -1;
+ pr_warn("APIC(%x) Package %u exceeds logical package map\n",
+ apicid, pkg);
+ return -ENOSPC;
+ }
+ set_bit(new, logical_package_map);
+ pr_info("APIC(%x) Converting physical %u to logical package %u\n",
+ apicid, pkg, new);
+ physical_to_logical_pkg[pkg] = new;
+
+found:
+ cpu_data(cpu).logical_proc_id = physical_to_logical_pkg[pkg];
+ return 0;
+}
+
+/**
+ * topology_phys_to_logical_pkg - Map a physical package id to a logical
+ *
+ * Returns logical package id or -1 if not found
+ */
+int topology_phys_to_logical_pkg(unsigned int phys_pkg)
+{
+ if (phys_pkg >= max_physical_pkg_id)
+ return -1;
+ return physical_to_logical_pkg[phys_pkg];
+}
+EXPORT_SYMBOL(topology_phys_to_logical_pkg);
+
+static void __init smp_init_package_map(void)
+{
+ unsigned int ncpus, cpu;
+ size_t size;
+
+ /*
+ * Today neither Intel nor AMD support heterogenous systems. That
+ * might change in the future....
+ */
+ ncpus = boot_cpu_data.x86_max_cores * smp_num_siblings;
+ __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
+
+ /*
+ * Possibly larger than what we need as the number of apic ids per
+ * package can be smaller than the actual used apic ids.
+ */
+ max_physical_pkg_id = DIV_ROUND_UP(MAX_LOCAL_APIC, ncpus);
+ size = max_physical_pkg_id * sizeof(unsigned int);
+ physical_to_logical_pkg = kmalloc(size, GFP_KERNEL);
+ memset(physical_to_logical_pkg, 0xff, size);
+ size = BITS_TO_LONGS(max_physical_pkg_id);
+ physical_package_map = kzalloc(size, GFP_KERNEL);
+ size = BITS_TO_LONGS(__max_logical_packages);
+ logical_package_map = kzalloc(size, GFP_KERNEL);
+
+ pr_info("Max logical packages: %u\n", __max_logical_packages);
+
+ for_each_present_cpu(cpu) {
+ unsigned int apicid = apic->cpu_present_to_apicid(cpu);
+
+ if (apicid == BAD_APICID || !apic->apic_id_valid(apicid))
+ continue;
+ if (!topology_update_package_map(apicid, cpu))
+ continue;
+ pr_warn("CPU %u APICId %x disabled\n", cpu, apicid);
+ per_cpu(x86_bios_cpu_apicid, cpu) = BAD_APICID;
+ set_cpu_possible(cpu, false);
+ set_cpu_present(cpu, false);
+ }
+}
+
void __init smp_store_boot_cpu_info(void)
{
int id = 0; /* CPU 0 */
@@ -258,6 +357,7 @@ void __init smp_store_boot_cpu_info(void
*c = boot_cpu_data;
c->cpu_index = id;
+ smp_init_package_map();
}
/*
[toc] | [prev] | [next] | [standalone]
| From | Andi Kleen <andi@firstfloor.org> |
|---|---|
| Date | 2016-02-22 20:00 +0100 |
| Subject | Re: [patch V2 11/28] x86/topology: Create logical package id |
| Message-ID | <r53Sa-1FT-7@gated-at.bofh.it> |
| In reply to | #1339381 |
Thomas Gleixner <tglx@linutronix.de> writes:
> +
> + if (c->cpuid_level >= 0x00000001) {
> + u32 eax, ebx, ecx, edx;
> +
> + cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
Use cpuid_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);
> + }
> +++ b/arch/x86/kernel/cpu/proc.c
> @@ -12,6 +12,7 @@ static void show_cpuinfo_core(struct seq
> {
> #ifdef CONFIG_SMP
> seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
> + seq_printf(m, "logical id\t: %d\n", c->logical_proc_id);
I'm not sure it makes sense to export this. What good would it be for
the user?
If it was it would need to be documented somewhere. But I would
just drop it and keep it kernel internal.
FWIW every time something is added to this file it usually breaks
some (dumb) programs.
> + /*
> + * Today neither Intel nor AMD support heterogenous systems. That
> + * might change in the future....
> + */
> + ncpus = boot_cpu_data.x86_max_cores * smp_num_siblings;
> + __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
FWIW Hypervisors can do nearly everything today.
I assume your code handles it.
Let's hope that the Hypervisors always set up the correct CPUID now
for their sibling configuration. If they don't with this change
some CPUs would be suddenly lost.
Would it be worth to have a kernel option where the maximum can be overriden
in case this happens?
-Andi
--
ak@linux.intel.com -- Speaking for myself only
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 20:10 +0100 |
| Subject | Re: [patch V2 11/28] x86/topology: Create logical package id |
| Message-ID | <r541Q-1YW-21@gated-at.bofh.it> |
| In reply to | #1339818 |
Andi,
On Mon, 22 Feb 2016, Andi Kleen wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
> > + if (c->cpuid_level >= 0x00000001) {
> > + u32 eax, ebx, ecx, edx;
> > +
> > + cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
>
> Use cpuid_edx()
That does not give me EBX ...
> > + /*
> > + * 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);
> > + }
> > +++ b/arch/x86/kernel/cpu/proc.c
> > @@ -12,6 +12,7 @@ static void show_cpuinfo_core(struct seq
> > {
> > #ifdef CONFIG_SMP
> > seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
> > + seq_printf(m, "logical id\t: %d\n", c->logical_proc_id);
>
>
> I'm not sure it makes sense to export this. What good would it be for
> the user?
>
> If it was it would need to be documented somewhere. But I would
> just drop it and keep it kernel internal.
You are right. We print already when we change the package number, so it can
be retrieved from dmesg.
> FWIW every time something is added to this file it usually breaks
> some (dumb) programs.
Ok, did not think about that.
> > + /*
> > + * Today neither Intel nor AMD support heterogenous systems. That
> > + * might change in the future....
> > + */
> > + ncpus = boot_cpu_data.x86_max_cores * smp_num_siblings;
> > + __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
>
> FWIW Hypervisors can do nearly everything today.
>
> I assume your code handles it.
It should. At least as long as nr_cpu_ids is sufficiently large.
> Let's hope that the Hypervisors always set up the correct CPUID now
> for their sibling configuration. If they don't with this change
> some CPUs would be suddenly lost.
The ones I looked at are doing is sane. Famous last words :)
> Would it be worth to have a kernel option where the maximum can be overriden
> in case this happens?
Let's wait for it to happen. It's done in no time, but if not needed it's just
ballast.
Thanks,
tglx
[toc] | [prev] | [next] | [standalone]
| From | Thomas Gleixner <tglx@linutronix.de> |
|---|---|
| Date | 2016-02-22 12:20 +0100 |
| Subject | [patch V2 14/28] x86/perf/intel_uncore: Make PCI and MSR uncore independent |
| Message-ID | <r4WH1-4WG-53@gated-at.bofh.it> |
| In reply to | #1339368 |
Andi wanted to do this before, but the patch fell down the cracks. Implement
it with the proper error handling.
Requested-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 34 +++++++++++++-------------
1 file changed, 18 insertions(+), 16 deletions(-)
Index: b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
===================================================================
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -1023,7 +1023,7 @@ static int __init uncore_pci_init(void)
ret = skl_uncore_pci_init();
break;
default:
- return 0;
+ return -ENODEV;
}
if (ret)
@@ -1319,7 +1319,7 @@ static int __init uncore_cpu_init(void)
knl_uncore_cpu_init();
break;
default:
- return 0;
+ return -ENODEV;
}
ret = uncore_types_init(uncore_msr_uncores, true);
@@ -1344,7 +1344,7 @@ static void __init uncore_cpu_setup(void
/* Lazy to avoid allocation of a few bytes for the normal case */
static __initdata DECLARE_BITMAP(packages, MAX_LOCAL_APIC);
-static int __init uncore_cpumask_init(void)
+static int __init uncore_cpumask_init(bool msr)
{
unsigned int cpu;
@@ -1355,12 +1355,15 @@ static int __init uncore_cpumask_init(vo
if (test_and_set_bit(pkg, packages))
continue;
/*
- * The first online cpu of each package takes the refcounts
- * for all other online cpus in that package.
+ * The first online cpu of each package allocates and takes
+ * the refcounts for all other online cpus in that package.
+ * If msrs are not enabled no allocation is required.
*/
- ret = uncore_cpu_prepare(cpu);
- if (ret)
- return ret;
+ if (msr) {
+ ret = uncore_cpu_prepare(cpu);
+ if (ret)
+ return ret;
+ }
uncore_event_init_cpu(cpu);
smp_call_function_single(cpu, uncore_cpu_setup, NULL, 1);
}
@@ -1370,7 +1373,7 @@ static int __init uncore_cpumask_init(vo
static int __init intel_uncore_init(void)
{
- int ret;
+ int pret, cret, ret;
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
return -ENODEV;
@@ -1380,15 +1383,14 @@ static int __init intel_uncore_init(void
max_packages = topology_max_packages();
- ret = uncore_pci_init();
- if (ret)
- return ret;
- ret = uncore_cpu_init();
- if (ret)
- goto err;
+ pret = uncore_pci_init();
+ cret = uncore_cpu_init();
+
+ if (cret && pret)
+ return -ENODEV;
cpu_notifier_register_begin();
- ret = uncore_cpumask_init();
+ ret = uncore_cpumask_init(!cret);
if (ret)
goto err;
cpu_notifier_register_done();
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web