aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2012-06-15 02:31:36 -0400
committerIngo Molnar <mingo@kernel.org>2012-06-18 06:13:23 -0400
commit14371cce03c2fc393997e17f979e76674b7f392a (patch)
tree9f062dd2104df744e77da17054ad265e8c236b0c
parentfcde10e916326545e8fec1807357c68ef08dc443 (diff)
perf: Add generic PCI uncore PMU device support
This patch adds generic support for uncore PMUs presented as PCI devices. (These come in addition to the CPU/MSR based uncores.) Signed-off-by: Zheng Yan <zheng.z.yan@intel.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1339741902-8449-8-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c175
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h66
2 files changed, 236 insertions, 5 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 3ed941ac3745..e20c65a0e108 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -2,6 +2,11 @@
2 2
3static struct intel_uncore_type *empty_uncore[] = { NULL, }; 3static struct intel_uncore_type *empty_uncore[] = { NULL, };
4static struct intel_uncore_type **msr_uncores = empty_uncore; 4static struct intel_uncore_type **msr_uncores = empty_uncore;
5static struct intel_uncore_type **pci_uncores = empty_uncore;
6/* pci bus to socket mapping */
7static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
8
9static DEFINE_RAW_SPINLOCK(uncore_box_lock);
5 10
6/* mask of cpus that collect uncore events */ 11/* mask of cpus that collect uncore events */
7static cpumask_t uncore_cpu_mask; 12static cpumask_t uncore_cpu_mask;
@@ -205,13 +210,13 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box,
205 hwc->last_tag = ++box->tags[idx]; 210 hwc->last_tag = ++box->tags[idx];
206 211
207 if (hwc->idx == UNCORE_PMC_IDX_FIXED) { 212 if (hwc->idx == UNCORE_PMC_IDX_FIXED) {
208 hwc->event_base = uncore_msr_fixed_ctr(box); 213 hwc->event_base = uncore_fixed_ctr(box);
209 hwc->config_base = uncore_msr_fixed_ctl(box); 214 hwc->config_base = uncore_fixed_ctl(box);
210 return; 215 return;
211 } 216 }
212 217
213 hwc->config_base = uncore_msr_event_ctl(box, hwc->idx); 218 hwc->config_base = uncore_event_ctl(box, hwc->idx);
214 hwc->event_base = uncore_msr_perf_ctr(box, hwc->idx); 219 hwc->event_base = uncore_perf_ctr(box, hwc->idx);
215} 220}
216 221
217static void uncore_perf_event_update(struct intel_uncore_box *box, 222static void uncore_perf_event_update(struct intel_uncore_box *box,
@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)
305static struct intel_uncore_box * 310static struct intel_uncore_box *
306uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) 311uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
307{ 312{
313 static struct intel_uncore_box *box;
314
315 box = *per_cpu_ptr(pmu->box, cpu);
316 if (box)
317 return box;
318
319 raw_spin_lock(&uncore_box_lock);
320 list_for_each_entry(box, &pmu->box_list, list) {
321 if (box->phys_id == topology_physical_package_id(cpu)) {
322 atomic_inc(&box->refcnt);
323 *per_cpu_ptr(pmu->box, cpu) = box;
324 break;
325 }
326 }
327 raw_spin_unlock(&uncore_box_lock);
328
308 return *per_cpu_ptr(pmu->box, cpu); 329 return *per_cpu_ptr(pmu->box, cpu);
309} 330}
310 331
@@ -706,6 +727,13 @@ static void __init uncore_type_exit(struct intel_uncore_type *type)
706 type->attr_groups[1] = NULL; 727 type->attr_groups[1] = NULL;
707} 728}
708 729
730static void uncore_types_exit(struct intel_uncore_type **types)
731{
732 int i;
733 for (i = 0; types[i]; i++)
734 uncore_type_exit(types[i]);
735}
736
709static int __init uncore_type_init(struct intel_uncore_type *type) 737static int __init uncore_type_init(struct intel_uncore_type *type)
710{ 738{
711 struct intel_uncore_pmu *pmus; 739 struct intel_uncore_pmu *pmus;
@@ -725,6 +753,7 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
725 pmus[i].func_id = -1; 753 pmus[i].func_id = -1;
726 pmus[i].pmu_idx = i; 754 pmus[i].pmu_idx = i;
727 pmus[i].type = type; 755 pmus[i].type = type;
756 INIT_LIST_HEAD(&pmus[i].box_list);
728 pmus[i].box = alloc_percpu(struct intel_uncore_box *); 757 pmus[i].box = alloc_percpu(struct intel_uncore_box *);
729 if (!pmus[i].box) 758 if (!pmus[i].box)
730 goto fail; 759 goto fail;
@@ -773,6 +802,127 @@ fail:
773 return ret; 802 return ret;
774} 803}
775 804
805static struct pci_driver *uncore_pci_driver;
806static bool pcidrv_registered;
807
808/*
809 * add a pci uncore device
810 */
811static int __devinit uncore_pci_add(struct intel_uncore_type *type,
812 struct pci_dev *pdev)
813{
814 struct intel_uncore_pmu *pmu;
815 struct intel_uncore_box *box;
816 int i, phys_id;
817
818 phys_id = pcibus_to_physid[pdev->bus->number];
819 if (phys_id < 0)
820 return -ENODEV;
821
822 box = uncore_alloc_box(0);
823 if (!box)
824 return -ENOMEM;
825
826 /*
827 * for performance monitoring unit with multiple boxes,
828 * each box has a different function id.
829 */
830 for (i = 0; i < type->num_boxes; i++) {
831 pmu = &type->pmus[i];
832 if (pmu->func_id == pdev->devfn)
833 break;
834 if (pmu->func_id < 0) {
835 pmu->func_id = pdev->devfn;
836 break;
837 }
838 pmu = NULL;
839 }
840
841 if (!pmu) {
842 kfree(box);
843 return -EINVAL;
844 }
845
846 box->phys_id = phys_id;
847 box->pci_dev = pdev;
848 box->pmu = pmu;
849 uncore_box_init(box);
850 pci_set_drvdata(pdev, box);
851
852 raw_spin_lock(&uncore_box_lock);
853 list_add_tail(&box->list, &pmu->box_list);
854 raw_spin_unlock(&uncore_box_lock);
855
856 return 0;
857}
858
859static void __devexit uncore_pci_remove(struct pci_dev *pdev)
860{
861 struct intel_uncore_box *box = pci_get_drvdata(pdev);
862 struct intel_uncore_pmu *pmu = box->pmu;
863 int cpu, phys_id = pcibus_to_physid[pdev->bus->number];
864
865 if (WARN_ON_ONCE(phys_id != box->phys_id))
866 return;
867
868 raw_spin_lock(&uncore_box_lock);
869 list_del(&box->list);
870 raw_spin_unlock(&uncore_box_lock);
871
872 for_each_possible_cpu(cpu) {
873 if (*per_cpu_ptr(pmu->box, cpu) == box) {
874 *per_cpu_ptr(pmu->box, cpu) = NULL;
875 atomic_dec(&box->refcnt);
876 }
877 }
878
879 WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
880 kfree(box);
881}
882
883static int __devinit uncore_pci_probe(struct pci_dev *pdev,
884 const struct pci_device_id *id)
885{
886 struct intel_uncore_type *type;
887
888 type = (struct intel_uncore_type *)id->driver_data;
889 return uncore_pci_add(type, pdev);
890}
891
892static int __init uncore_pci_init(void)
893{
894 int ret;
895
896 switch (boot_cpu_data.x86_model) {
897 default:
898 return 0;
899 }
900
901 ret = uncore_types_init(pci_uncores);
902 if (ret)
903 return ret;
904
905 uncore_pci_driver->probe = uncore_pci_probe;
906 uncore_pci_driver->remove = uncore_pci_remove;
907
908 ret = pci_register_driver(uncore_pci_driver);
909 if (ret == 0)
910 pcidrv_registered = true;
911 else
912 uncore_types_exit(pci_uncores);
913
914 return ret;
915}
916
917static void __init uncore_pci_exit(void)
918{
919 if (pcidrv_registered) {
920 pcidrv_registered = false;
921 pci_unregister_driver(uncore_pci_driver);
922 uncore_types_exit(pci_uncores);
923 }
924}
925
776static void __cpuinit uncore_cpu_dying(int cpu) 926static void __cpuinit uncore_cpu_dying(int cpu)
777{ 927{
778 struct intel_uncore_type *type; 928 struct intel_uncore_type *type;
@@ -921,6 +1071,7 @@ static void __cpuinit uncore_event_exit_cpu(int cpu)
921 cpumask_set_cpu(target, &uncore_cpu_mask); 1071 cpumask_set_cpu(target, &uncore_cpu_mask);
922 1072
923 uncore_change_context(msr_uncores, cpu, target); 1073 uncore_change_context(msr_uncores, cpu, target);
1074 uncore_change_context(pci_uncores, cpu, target);
924} 1075}
925 1076
926static void __cpuinit uncore_event_init_cpu(int cpu) 1077static void __cpuinit uncore_event_init_cpu(int cpu)
@@ -936,6 +1087,7 @@ static void __cpuinit uncore_event_init_cpu(int cpu)
936 cpumask_set_cpu(cpu, &uncore_cpu_mask); 1087 cpumask_set_cpu(cpu, &uncore_cpu_mask);
937 1088
938 uncore_change_context(msr_uncores, -1, cpu); 1089 uncore_change_context(msr_uncores, -1, cpu);
1090 uncore_change_context(pci_uncores, -1, cpu);
939} 1091}
940 1092
941static int __cpuinit uncore_cpu_notifier(struct notifier_block *self, 1093static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
@@ -1051,6 +1203,14 @@ static int __init uncore_pmus_register(void)
1051 } 1203 }
1052 } 1204 }
1053 1205
1206 for (i = 0; pci_uncores[i]; i++) {
1207 type = pci_uncores[i];
1208 for (j = 0; j < type->num_boxes; j++) {
1209 pmu = &type->pmus[j];
1210 uncore_pmu_register(pmu);
1211 }
1212 }
1213
1054 return 0; 1214 return 0;
1055} 1215}
1056 1216
@@ -1061,9 +1221,14 @@ static int __init intel_uncore_init(void)
1061 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 1221 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
1062 return -ENODEV; 1222 return -ENODEV;
1063 1223
1064 ret = uncore_cpu_init(); 1224 ret = uncore_pci_init();
1065 if (ret) 1225 if (ret)
1066 goto fail; 1226 goto fail;
1227 ret = uncore_cpu_init();
1228 if (ret) {
1229 uncore_pci_exit();
1230 goto fail;
1231 }
1067 1232
1068 uncore_pmus_register(); 1233 uncore_pmus_register();
1069 return 0; 1234 return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index eeb5ca5815a8..aa01df87b8de 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -1,5 +1,6 @@
1#include <linux/module.h> 1#include <linux/module.h>
2#include <linux/slab.h> 2#include <linux/slab.h>
3#include <linux/pci.h>
3#include <linux/perf_event.h> 4#include <linux/perf_event.h>
4#include "perf_event.h" 5#include "perf_event.h"
5 6
@@ -110,6 +111,7 @@ struct intel_uncore_pmu {
110 int func_id; 111 int func_id;
111 struct intel_uncore_type *type; 112 struct intel_uncore_type *type;
112 struct intel_uncore_box ** __percpu box; 113 struct intel_uncore_box ** __percpu box;
114 struct list_head box_list;
113}; 115};
114 116
115struct intel_uncore_box { 117struct intel_uncore_box {
@@ -123,6 +125,7 @@ struct intel_uncore_box {
123 struct perf_event *event_list[UNCORE_PMC_IDX_MAX]; 125 struct perf_event *event_list[UNCORE_PMC_IDX_MAX];
124 unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; 126 unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
125 u64 tags[UNCORE_PMC_IDX_MAX]; 127 u64 tags[UNCORE_PMC_IDX_MAX];
128 struct pci_dev *pci_dev;
126 struct intel_uncore_pmu *pmu; 129 struct intel_uncore_pmu *pmu;
127 struct hrtimer hrtimer; 130 struct hrtimer hrtimer;
128 struct list_head list; 131 struct list_head list;
@@ -161,6 +164,33 @@ static ssize_t uncore_event_show(struct kobject *kobj,
161 return sprintf(buf, "%s", event->config); 164 return sprintf(buf, "%s", event->config);
162} 165}
163 166
167static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
168{
169 return box->pmu->type->box_ctl;
170}
171
172static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box)
173{
174 return box->pmu->type->fixed_ctl;
175}
176
177static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box)
178{
179 return box->pmu->type->fixed_ctr;
180}
181
182static inline
183unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx)
184{
185 return idx * 4 + box->pmu->type->event_ctl;
186}
187
188static inline
189unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx)
190{
191 return idx * 8 + box->pmu->type->perf_ctr;
192}
193
164static inline 194static inline
165unsigned uncore_msr_box_ctl(struct intel_uncore_box *box) 195unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
166{ 196{
@@ -200,6 +230,42 @@ unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
200 box->pmu->type->msr_offset * box->pmu->pmu_idx; 230 box->pmu->type->msr_offset * box->pmu->pmu_idx;
201} 231}
202 232
233static inline
234unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
235{
236 if (box->pci_dev)
237 return uncore_pci_fixed_ctl(box);
238 else
239 return uncore_msr_fixed_ctl(box);
240}
241
242static inline
243unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
244{
245 if (box->pci_dev)
246 return uncore_pci_fixed_ctr(box);
247 else
248 return uncore_msr_fixed_ctr(box);
249}
250
251static inline
252unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
253{
254 if (box->pci_dev)
255 return uncore_pci_event_ctl(box, idx);
256 else
257 return uncore_msr_event_ctl(box, idx);
258}
259
260static inline
261unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx)
262{
263 if (box->pci_dev)
264 return uncore_pci_perf_ctr(box, idx);
265 else
266 return uncore_msr_perf_ctr(box, idx);
267}
268
203static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box) 269static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box)
204{ 270{
205 return box->pmu->type->perf_ctr_bits; 271 return box->pmu->type->perf_ctr_bits;