diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore.c | 175 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore.h | 66 |
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 | ||
| 3 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; | 3 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; |
| 4 | static struct intel_uncore_type **msr_uncores = empty_uncore; | 4 | static struct intel_uncore_type **msr_uncores = empty_uncore; |
| 5 | static struct intel_uncore_type **pci_uncores = empty_uncore; | ||
| 6 | /* pci bus to socket mapping */ | ||
| 7 | static int pcibus_to_physid[256] = { [0 ... 255] = -1, }; | ||
| 8 | |||
| 9 | static DEFINE_RAW_SPINLOCK(uncore_box_lock); | ||
| 5 | 10 | ||
| 6 | /* mask of cpus that collect uncore events */ | 11 | /* mask of cpus that collect uncore events */ |
| 7 | static cpumask_t uncore_cpu_mask; | 12 | static 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 | ||
| 217 | static void uncore_perf_event_update(struct intel_uncore_box *box, | 222 | static void uncore_perf_event_update(struct intel_uncore_box *box, |
| @@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu) | |||
| 305 | static struct intel_uncore_box * | 310 | static struct intel_uncore_box * |
| 306 | uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) | 311 | uncore_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 | ||
| 730 | static 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 | |||
| 709 | static int __init uncore_type_init(struct intel_uncore_type *type) | 737 | static 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 | ||
| 805 | static struct pci_driver *uncore_pci_driver; | ||
| 806 | static bool pcidrv_registered; | ||
| 807 | |||
| 808 | /* | ||
| 809 | * add a pci uncore device | ||
| 810 | */ | ||
| 811 | static 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 | |||
| 859 | static 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 | |||
| 883 | static 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 | |||
| 892 | static 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 | |||
| 917 | static 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 | |||
| 776 | static void __cpuinit uncore_cpu_dying(int cpu) | 926 | static 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 | ||
| 926 | static void __cpuinit uncore_event_init_cpu(int cpu) | 1077 | static 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 | ||
| 941 | static int __cpuinit uncore_cpu_notifier(struct notifier_block *self, | 1093 | static 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 | ||
| 115 | struct intel_uncore_box { | 117 | struct 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 | ||
| 167 | static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box) | ||
| 168 | { | ||
| 169 | return box->pmu->type->box_ctl; | ||
| 170 | } | ||
| 171 | |||
| 172 | static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box) | ||
| 173 | { | ||
| 174 | return box->pmu->type->fixed_ctl; | ||
| 175 | } | ||
| 176 | |||
| 177 | static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box) | ||
| 178 | { | ||
| 179 | return box->pmu->type->fixed_ctr; | ||
| 180 | } | ||
| 181 | |||
| 182 | static inline | ||
| 183 | unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx) | ||
| 184 | { | ||
| 185 | return idx * 4 + box->pmu->type->event_ctl; | ||
| 186 | } | ||
| 187 | |||
| 188 | static inline | ||
| 189 | unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx) | ||
| 190 | { | ||
| 191 | return idx * 8 + box->pmu->type->perf_ctr; | ||
| 192 | } | ||
| 193 | |||
| 164 | static inline | 194 | static inline |
| 165 | unsigned uncore_msr_box_ctl(struct intel_uncore_box *box) | 195 | unsigned 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 | ||
| 233 | static inline | ||
| 234 | unsigned 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 | |||
| 242 | static inline | ||
| 243 | unsigned 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 | |||
| 251 | static inline | ||
| 252 | unsigned 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 | |||
| 260 | static inline | ||
| 261 | unsigned 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 | |||
| 203 | static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box) | 269 | static 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; |
