diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index a0d489e..a820ed4 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -42,6 +42,7 @@
 #include <dirent.h>
 #include <sys/time.h>			/* getrlimit */
 #include <sys/resource.h>		/* getrlimit */
+#include <sys/queue.h>
 #include <ftw.h>
 #include <sys/stat.h>
 #include "jsmn.h"
@@ -366,6 +367,94 @@ static int print_events_table_entry(void *data, char *name, char *event,
 	return 0;
 }
 
+struct event_struct {
+	char *name;
+	char *event;
+	char *desc;
+	char *long_desc;
+	char *pmu;
+	char *unit;
+	char *perpkg;
+	char *metric_expr;
+	char *metric_name;
+	char *metric_group;
+	LIST_ENTRY(event_struct) list;
+	char strings[];
+};
+
+LIST_HEAD(listhead, event_struct) recommended_events;
+
+static int save_recommended_events(void *data, char *name, char *event,
+				    char *desc, char *long_desc,
+				    char *pmu, char *unit, char *perpkg,
+				    char *metric_expr,
+				    char *metric_name, char *metric_group)
+{
+	static int count = 0;
+	char temp[1024];
+	struct event_struct *es;
+	struct stat *sb = data;
+	int len = 0;
+	char *strings;
+
+	/*
+	 * Lazily allocate size of the JSON file to hold the
+	 * strings, which would be more than large enough.
+	 */
+	len = sb->st_size;
+
+	es = malloc(sizeof(*es) + len);
+	if (!es)
+		return -ENOMEM;
+	memset(es, 0, sizeof(*es));
+	LIST_INSERT_HEAD(&recommended_events, es, list);
+
+	strings = &es->strings[0];
+
+	if (name) {
+		es->name = strings;
+		strings += snprintf(strings, len, "%s", name) + 1;
+	}
+	if (event) {
+		es->event = strings;
+		strings += snprintf(strings, len, "%s", event) + 1;
+	}
+	if (desc) {
+		es->desc = strings;
+		strings += snprintf(strings, len, "%s", desc) + 1;
+	}
+	if (long_desc) {
+		es->long_desc = strings;
+		strings += snprintf(strings, len, "%s", long_desc) + 1;
+	}
+	if (pmu) {
+		es->pmu = strings;
+		strings += snprintf(strings, len, "%s", pmu) + 1;
+	}
+	if (unit) {
+		es->unit = strings;
+		strings += snprintf(strings, len, "%s", unit) + 1;
+	}
+	if (perpkg) {
+		es->perpkg = strings;
+		strings += snprintf(strings, len, "%s", perpkg) + 1;
+	}
+	if (metric_expr) {
+		es->metric_expr = strings;
+		strings += snprintf(strings, len, "%s", metric_expr) + 1;
+	}
+	if (metric_name) {
+		es->metric_name = strings;
+		strings += snprintf(strings, len, "%s", metric_name) + 1;
+	}
+	if (metric_group) {
+		es->metric_group = strings;
+		strings += snprintf(strings, len, "%s", metric_group) + 1;
+	}
+
+	return 0;
+}
+
 static void print_events_table_suffix(FILE *outfp)
 {
 	fprintf(outfp, "{\n");
@@ -407,6 +496,61 @@ static char *real_event(const char *name, char *event)
 	return event;
 }
 
+static void fixup_field(char *from, char **to)
+{
+	/*
+	 * If we already had a valid pointer (string), then
+	 * don't allocate a new one, just reuse and overwrite.
+	 */
+	if (!*to)
+		*to = malloc(strlen(from));
+
+	strcpy(*to, from);
+}
+
+static int try_fixup(const char *fn, char *event, char **desc, char **name, char **long_desc, char **pmu, char **filter,
+				char **perpkg, char **unit, char **metric_expr, char **metric_name, char **metric_group)
+{
+	/* try to find matching event from recommended values */
+	struct event_struct *es;
+
+	LIST_FOREACH(es, &recommended_events, list) {
+		if (!strcmp(event, es->event)) {
+			/* now fixup */
+			if (es->desc)
+				fixup_field(es->desc, desc);
+			if (es->name)
+				fixup_field(es->name, name);
+			if (es->long_desc)
+				fixup_field(es->long_desc, long_desc);
+			if (es->pmu)
+				fixup_field(es->pmu, pmu);
+		//	if (event_struct->filter)
+		//		fixup_field(event_struct->filter, filter);
+			if (es->perpkg)
+				fixup_field(es->perpkg, perpkg);
+			if (es->unit)
+				fixup_field(es->unit, unit);
+			if (es->metric_expr)
+				fixup_field(es->metric_expr, metric_expr);
+			if (es->metric_name)
+				fixup_field(es->metric_name, metric_name);
+			if (es->metric_group)
+				fixup_field(es->metric_group, metric_group);
+
+			return 0;
+		}
+	}
+
+	pr_err("%s: could not find matching %s for %s\n", prog, event, fn);
+	return -1;
+}
+
+#define  FREE_MEMORIES \
+		free(event); free(desc); free(name); free(long_desc); \
+		free(extra_desc);  free(pmu); free(filter); free(perpkg); \
+		free(unit); free(metric_expr); free(metric_name);
+
 /* Call func with each event in the json file */
 int json_events(const char *fn,
 	  int (*func)(void *data, char *name, char *event, char *desc,
@@ -551,20 +695,22 @@ int json_events(const char *fn,
 		if (name)
 			fixname(name);
 
+		if (!desc) {
+			/*
+			 * If we have no valid desc, then fixup *all* values from recommended
+			 * by matching the event.
+			 */
+			err = try_fixup(fn, event, &desc, &name, &long_desc, &pmu, &filter, &perpkg, &unit, &metric_expr,
+					&metric_name, &metric_group);
+			if (err) {
+				FREE_MEMORIES
+				goto out_free;
+			}
+		}
+
 		err = func(data, name, real_event(name, event), desc, long_desc,
 			   pmu, unit, perpkg, metric_expr, metric_name, metric_group);
-		free(event);
-		free(desc);
-		free(name);
-		free(long_desc);
-		free(extra_desc);
-		free(pmu);
-		free(filter);
-		free(perpkg);
-		free(unit);
-		free(metric_expr);
-		free(metric_name);
-		free(metric_group);
+		FREE_MEMORIES
 		if (err)
 			break;
 		tok += j;
@@ -776,6 +922,32 @@ static int isLeafDir(const char *fpath)
 	return res;
 }
 
+static int isJsonFile(const char *name)
+{
+	const char *suffix;
+
+	if (strlen(name) < 5)
+		return 0;
+
+	suffix = name + strlen(name) - 5;
+
+	if (strncmp(suffix, ".json", 5) == 0)
+		return 1;
+	return 0;
+}
+
+static int preprocess_level0_files(const char *fpath, const struct stat *sb,
+				int typeflag, struct FTW *ftwbuf)
+{
+	int level	= ftwbuf->level;
+	int is_file = typeflag == FTW_F;
+
+	if (level == 1 && is_file && isJsonFile(fpath))
+		return json_events(fpath, save_recommended_events, (void *)sb);
+
+	return 0;
+}
+
 static int process_one_file(const char *fpath, const struct stat *sb,
 			    int typeflag, struct FTW *ftwbuf)
 {
@@ -806,8 +978,10 @@ static int process_one_file(const char *fpath, const struct stat *sb,
 		 level, sb->st_size, bname, fpath);
 
 	/* base dir */
-	if (level == 0)
-		return 0;
+	if (level == 0) {
+		LIST_INIT(&recommended_events);
+		return nftw(fpath, preprocess_level0_files, get_maxfds(), 0);
+	}
 
 	/* model directory, reset topic */
 	if (level == 1 && is_dir && isLeafDir(fpath)) {
@@ -869,9 +1043,7 @@ static int process_one_file(const char *fpath, const struct stat *sb,
 	 * ignore it. It could be a readme.txt for instance.
 	 */
 	if (is_file) {
-		char *suffix = bname + strlen(bname) - 5;
-
-		if (strncmp(suffix, ".json", 5)) {
+		if (!isJsonFile(bname)) {
 			pr_info("%s: Ignoring file without .json suffix %s\n", prog,
 				fpath);
 			return 0;
@@ -933,6 +1105,7 @@ int main(int argc, char *argv[])
 	const char *output_file;
 	const char *start_dirname;
 	struct stat stbuf;
+	struct event_struct *es1, *es2;
 
 	prog = basename(argv[0]);
 	if (argc < 4) {
@@ -988,6 +1161,14 @@ int main(int argc, char *argv[])
 		goto empty_map;
 	}
 
+	/* Free struct for recommended events */
+	es1 = LIST_FIRST(&recommended_events);
+	while (es1) {
+		es2 = LIST_NEXT(es1, list);
+		free(es1);
+		es1 = es2;
+	}
+
 	if (close_table)
 		print_events_table_suffix(eventsfp);
 
