Merge branch 'pm-cpufreq'
[cascardo/linux.git] / tools / perf / util / pmu.c
index b615cdf..89c91a1 100644 (file)
@@ -462,10 +462,6 @@ static struct perf_pmu *pmu_lookup(const char *name)
        LIST_HEAD(aliases);
        __u32 type;
 
-       /* No support for intel_bts or intel_pt so disallow them */
-       if (!strcmp(name, "intel_bts") || !strcmp(name, "intel_pt"))
-               return NULL;
-
        /*
         * The pmu data we store & need consists of the pmu
         * type value and format definitions. Load both right
@@ -542,7 +538,7 @@ struct perf_pmu *perf_pmu__find(const char *name)
 }
 
 static struct perf_pmu_format *
-pmu_find_format(struct list_head *formats, char *name)
+pmu_find_format(struct list_head *formats, const char *name)
 {
        struct perf_pmu_format *format;
 
@@ -553,6 +549,21 @@ pmu_find_format(struct list_head *formats, char *name)
        return NULL;
 }
 
+__u64 perf_pmu__format_bits(struct list_head *formats, const char *name)
+{
+       struct perf_pmu_format *format = pmu_find_format(formats, name);
+       __u64 bits = 0;
+       int fbit;
+
+       if (!format)
+               return 0;
+
+       for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
+               bits |= 1ULL << fbit;
+
+       return bits;
+}
+
 /*
  * Sets value based on the format definition (format parameter)
  * and unformated value (value parameter).
@@ -574,6 +585,18 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
        }
 }
 
+static __u64 pmu_format_max_value(const unsigned long *format)
+{
+       int w;
+
+       w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
+       if (!w)
+               return 0;
+       if (w < 64)
+               return (1ULL << w) - 1;
+       return -1;
+}
+
 /*
  * Term is a string term, and might be a param-term. Try to look up it's value
  * in the remaining terms.
@@ -607,7 +630,9 @@ static char *formats_error_string(struct list_head *formats)
 {
        struct perf_pmu_format *format;
        char *err, *str;
-       static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n";
+       static const char *static_terms = "config,config1,config2,name,"
+                                         "period,freq,branch_type,time,"
+                                         "call-graph,stack-size\n";
        unsigned i = 0;
 
        if (!asprintf(&str, "valid terms:"))
@@ -647,7 +672,7 @@ static int pmu_config_term(struct list_head *formats,
 {
        struct perf_pmu_format *format;
        __u64 *vp;
-       __u64 val;
+       __u64 val, max_val;
 
        /*
         * If this is a parameter we've already used for parameterized-eval,
@@ -713,6 +738,22 @@ static int pmu_config_term(struct list_head *formats,
        } else
                return -EINVAL;
 
+       max_val = pmu_format_max_value(format->bits);
+       if (val > max_val) {
+               if (err) {
+                       err->idx = term->err_val;
+                       if (asprintf(&err->str,
+                                    "value too big for format, maximum is %llu",
+                                    (unsigned long long)max_val) < 0)
+                               err->str = strdup("value too big for format");
+                       return -EINVAL;
+               }
+               /*
+                * Assume we don't care if !err, in which case the value will be
+                * silently truncated.
+                */
+       }
+
        pmu_format_value(format->bits, val, vp, zero);
        return 0;
 }