aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ds.c
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2009-03-13 05:42:18 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-13 06:57:19 -0400
commitbc44fb5f7d3e764ed7698c835a1a0f35aba2eb3d (patch)
tree4d1c5e8d7cca598ca410e2e9892828af309a86a4 /arch/x86/kernel/ds.c
parent62a394eb77a1ddea73273f53ed8c3ccf6e04f2fb (diff)
x86, bts: detect size of DS fields
Impact: more robust DS feature enumeration Detect the size of the pointer-type fields in the DS area configuration via the DTES64 features rather than based on the cpuid. Rename a variable to denote that size to reflect that it only covers the pointer-type fields. Add more boot-time diagnostics giving the detected size and the sizes of BTS and PEBS records. Use the size of the BTS/PEBS record to indicate that the respective feature is not available (if the record size is zero). Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> LKML-Reference: <20090313104218.A30096@sedona.ch.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r--arch/x86/kernel/ds.c84
1 files changed, 44 insertions, 40 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 87b67e3a765a..6e5ec679a0cd 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -39,7 +39,7 @@ struct ds_configuration {
39 /* the size of one pointer-typed field in the DS structure and 39 /* the size of one pointer-typed field in the DS structure and
40 in the BTS and PEBS buffers in bytes; 40 in the BTS and PEBS buffers in bytes;
41 this covers the first 8 DS fields related to buffer management. */ 41 this covers the first 8 DS fields related to buffer management. */
42 unsigned char sizeof_field; 42 unsigned char sizeof_ptr_field;
43 /* the size of a BTS/PEBS record in bytes */ 43 /* the size of a BTS/PEBS record in bytes */
44 unsigned char sizeof_rec[2]; 44 unsigned char sizeof_rec[2];
45 /* a series of bit-masks to control various features indexed 45 /* a series of bit-masks to control various features indexed
@@ -142,14 +142,14 @@ enum ds_qualifier {
142static inline unsigned long ds_get(const unsigned char *base, 142static inline unsigned long ds_get(const unsigned char *base,
143 enum ds_qualifier qual, enum ds_field field) 143 enum ds_qualifier qual, enum ds_field field)
144{ 144{
145 base += (ds_cfg.sizeof_field * (field + (4 * qual))); 145 base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual)));
146 return *(unsigned long *)base; 146 return *(unsigned long *)base;
147} 147}
148 148
149static inline void ds_set(unsigned char *base, enum ds_qualifier qual, 149static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
150 enum ds_field field, unsigned long value) 150 enum ds_field field, unsigned long value)
151{ 151{
152 base += (ds_cfg.sizeof_field * (field + (4 * qual))); 152 base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual)));
153 (*(unsigned long *)base) = value; 153 (*(unsigned long *)base) = value;
154} 154}
155 155
@@ -410,7 +410,7 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual,
410 * Later architectures use 64bit pointers throughout, whereas earlier 410 * Later architectures use 64bit pointers throughout, whereas earlier
411 * architectures use 32bit pointers in 32bit mode. 411 * architectures use 32bit pointers in 32bit mode.
412 * 412 *
413 * We compute the base address for the first 8 fields based on: 413 * We compute the base address for the fields based on:
414 * - the field size stored in the DS configuration 414 * - the field size stored in the DS configuration
415 * - the relative field position 415 * - the relative field position
416 * 416 *
@@ -441,13 +441,13 @@ enum bts_field {
441 441
442static inline unsigned long bts_get(const char *base, enum bts_field field) 442static inline unsigned long bts_get(const char *base, enum bts_field field)
443{ 443{
444 base += (ds_cfg.sizeof_field * field); 444 base += (ds_cfg.sizeof_ptr_field * field);
445 return *(unsigned long *)base; 445 return *(unsigned long *)base;
446} 446}
447 447
448static inline void bts_set(char *base, enum bts_field field, unsigned long val) 448static inline void bts_set(char *base, enum bts_field field, unsigned long val)
449{ 449{
450 base += (ds_cfg.sizeof_field * field);; 450 base += (ds_cfg.sizeof_ptr_field * field);;
451 (*(unsigned long *)base) = val; 451 (*(unsigned long *)base) = val;
452} 452}
453 453
@@ -593,6 +593,10 @@ static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
593 struct ds_context *context; 593 struct ds_context *context;
594 int error; 594 int error;
595 595
596 error = -EOPNOTSUPP;
597 if (!ds_cfg.sizeof_rec[qual])
598 goto out;
599
596 error = -EINVAL; 600 error = -EINVAL;
597 if (!base) 601 if (!base)
598 goto out; 602 goto out;
@@ -635,10 +639,6 @@ struct bts_tracer *ds_request_bts(struct task_struct *task,
635 unsigned long irq; 639 unsigned long irq;
636 int error; 640 int error;
637 641
638 error = -EOPNOTSUPP;
639 if (!ds_cfg.ctl[dsf_bts])
640 goto out;
641
642 /* buffer overflow notification is not yet implemented */ 642 /* buffer overflow notification is not yet implemented */
643 error = -EOPNOTSUPP; 643 error = -EOPNOTSUPP;
644 if (ovfl) 644 if (ovfl)
@@ -848,7 +848,8 @@ const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer)
848 848
849 ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); 849 ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs);
850 tracer->trace.reset_value = 850 tracer->trace.reset_value =
851 *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)); 851 *(u64 *)(tracer->ds.context->ds +
852 (ds_cfg.sizeof_ptr_field * 8));
852 853
853 return &tracer->trace; 854 return &tracer->trace;
854} 855}
@@ -884,7 +885,8 @@ int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value)
884 if (!tracer) 885 if (!tracer)
885 return -EINVAL; 886 return -EINVAL;
886 887
887 *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value; 888 *(u64 *)(tracer->ds.context->ds +
889 (ds_cfg.sizeof_ptr_field * 8)) = value;
888 890
889 return 0; 891 return 0;
890} 892}
@@ -894,52 +896,54 @@ static const struct ds_configuration ds_cfg_netburst = {
894 .ctl[dsf_bts] = (1 << 2) | (1 << 3), 896 .ctl[dsf_bts] = (1 << 2) | (1 << 3),
895 .ctl[dsf_bts_kernel] = (1 << 5), 897 .ctl[dsf_bts_kernel] = (1 << 5),
896 .ctl[dsf_bts_user] = (1 << 6), 898 .ctl[dsf_bts_user] = (1 << 6),
897
898 .sizeof_field = sizeof(long),
899 .sizeof_rec[ds_bts] = sizeof(long) * 3,
900#ifdef __i386__
901 .sizeof_rec[ds_pebs] = sizeof(long) * 10,
902#else
903 .sizeof_rec[ds_pebs] = sizeof(long) * 18,
904#endif
905}; 899};
906static const struct ds_configuration ds_cfg_pentium_m = { 900static const struct ds_configuration ds_cfg_pentium_m = {
907 .name = "Pentium M", 901 .name = "Pentium M",
908 .ctl[dsf_bts] = (1 << 6) | (1 << 7), 902 .ctl[dsf_bts] = (1 << 6) | (1 << 7),
909
910 .sizeof_field = sizeof(long),
911 .sizeof_rec[ds_bts] = sizeof(long) * 3,
912#ifdef __i386__
913 .sizeof_rec[ds_pebs] = sizeof(long) * 10,
914#else
915 .sizeof_rec[ds_pebs] = sizeof(long) * 18,
916#endif
917}; 903};
918static const struct ds_configuration ds_cfg_core2_atom = { 904static const struct ds_configuration ds_cfg_core2_atom = {
919 .name = "Core 2/Atom", 905 .name = "Core 2/Atom",
920 .ctl[dsf_bts] = (1 << 6) | (1 << 7), 906 .ctl[dsf_bts] = (1 << 6) | (1 << 7),
921 .ctl[dsf_bts_kernel] = (1 << 9), 907 .ctl[dsf_bts_kernel] = (1 << 9),
922 .ctl[dsf_bts_user] = (1 << 10), 908 .ctl[dsf_bts_user] = (1 << 10),
923
924 .sizeof_field = 8,
925 .sizeof_rec[ds_bts] = 8 * 3,
926 .sizeof_rec[ds_pebs] = 8 * 18,
927}; 909};
928 910
929static void 911static void
930ds_configure(const struct ds_configuration *cfg) 912ds_configure(const struct ds_configuration *cfg,
913 struct cpuinfo_x86 *cpu)
931{ 914{
915 unsigned long nr_pebs_fields = 0;
916
917 printk(KERN_INFO "[ds] using %s configuration\n", cfg->name);
918
919#ifdef __i386__
920 nr_pebs_fields = 10;
921#else
922 nr_pebs_fields = 18;
923#endif
924
932 memset(&ds_cfg, 0, sizeof(ds_cfg)); 925 memset(&ds_cfg, 0, sizeof(ds_cfg));
933 ds_cfg = *cfg; 926 ds_cfg = *cfg;
934 927
935 printk(KERN_INFO "[ds] using %s configuration\n", ds_cfg.name); 928 ds_cfg.sizeof_ptr_field =
929 (cpu_has(cpu, X86_FEATURE_DTES64) ? 8 : 4);
936 930
937 if (!cpu_has_bts) { 931 ds_cfg.sizeof_rec[ds_bts] = ds_cfg.sizeof_ptr_field * 3;
938 ds_cfg.ctl[dsf_bts] = 0; 932 ds_cfg.sizeof_rec[ds_pebs] = ds_cfg.sizeof_ptr_field * nr_pebs_fields;
933
934 if (!cpu_has(cpu, X86_FEATURE_BTS)) {
935 ds_cfg.sizeof_rec[ds_bts] = 0;
939 printk(KERN_INFO "[ds] bts not available\n"); 936 printk(KERN_INFO "[ds] bts not available\n");
940 } 937 }
941 if (!cpu_has_pebs) 938 if (!cpu_has(cpu, X86_FEATURE_PEBS)) {
939 ds_cfg.sizeof_rec[ds_pebs] = 0;
942 printk(KERN_INFO "[ds] pebs not available\n"); 940 printk(KERN_INFO "[ds] pebs not available\n");
941 }
942
943 printk(KERN_INFO "[ds] sizes: address: %u bit, ",
944 8 * ds_cfg.sizeof_ptr_field);
945 printk("bts/pebs record: %u/%u bytes\n",
946 ds_cfg.sizeof_rec[ds_bts], ds_cfg.sizeof_rec[ds_pebs]);
943 947
944 WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field)); 948 WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field));
945} 949}
@@ -951,12 +955,12 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
951 switch (c->x86_model) { 955 switch (c->x86_model) {
952 case 0x9: 956 case 0x9:
953 case 0xd: /* Pentium M */ 957 case 0xd: /* Pentium M */
954 ds_configure(&ds_cfg_pentium_m); 958 ds_configure(&ds_cfg_pentium_m, c);
955 break; 959 break;
956 case 0xf: 960 case 0xf:
957 case 0x17: /* Core2 */ 961 case 0x17: /* Core2 */
958 case 0x1c: /* Atom */ 962 case 0x1c: /* Atom */
959 ds_configure(&ds_cfg_core2_atom); 963 ds_configure(&ds_cfg_core2_atom, c);
960 break; 964 break;
961 case 0x1a: /* i7 */ 965 case 0x1a: /* i7 */
962 default: 966 default:
@@ -969,7 +973,7 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
969 case 0x0: 973 case 0x0:
970 case 0x1: 974 case 0x1:
971 case 0x2: /* Netburst */ 975 case 0x2: /* Netburst */
972 ds_configure(&ds_cfg_netburst); 976 ds_configure(&ds_cfg_netburst, c);
973 break; 977 break;
974 default: 978 default:
975 /* sorry, don't know about them */ 979 /* sorry, don't know about them */