changeset 11261:e8fc0feaefb8

6750860 core_pcbe back-end needs to support generic events
author Kuriakose Kuruvilla <Kuriakose.Kuruvilla@Sun.COM>
date Sat, 05 Dec 2009 14:11:51 -0800
parents eb8c6f2097e8
children b7ebfbf2359e
files usr/src/uts/intel/pcbe/core_pcbe.c
diffstat 1 files changed, 319 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/intel/pcbe/core_pcbe.c	Sat Dec 05 13:25:40 2009 +0800
+++ b/usr/src/uts/intel/pcbe/core_pcbe.c	Sat Dec 05 14:11:51 2009 -0800
@@ -24,6 +24,47 @@
  */
 
 /*
+ * This file contains preset event names from the Performance Application
+ * Programming Interface v3.5 which included the following notice:
+ *
+ *                             Copyright (c) 2005,6
+ *                           Innovative Computing Labs
+ *                         Computer Science Department,
+ *                            University of Tennessee,
+ *                                 Knoxville, TN.
+ *                              All Rights Reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    * Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *    * Neither the name of the University of Tennessee nor the names of its
+ *      contributors may be used to endorse or promote products derived from
+ *      this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * This open source software license conforms to the BSD License template.
+ */
+
+
+/*
  * Performance Counter Back-End for Intel processors supporting Architectural
  * Performance Monitoring.
  */
@@ -175,6 +216,46 @@
 #define	ALL_CORES	(1ULL << 15)
 #define	ALL_AGENTS	(1ULL << 13)
 
+struct generic_events {
+	const char	*name;
+	uint8_t		event_num;
+	uint8_t		umask;
+};
+
+static const struct generic_events cmn_generic_events[] = {
+	{ "PAPI_tot_cyc", 0x3c, 0x00 }, /* cpu_clk_unhalted.thread_p/core */
+	{ "PAPI_tot_ins", 0xc0, 0x00 }, /* inst_retired.any_p		  */
+	{ "PAPI_br_ins",  0xc4, 0x0c }, /* br_inst_retired.taken	  */
+	{ "PAPI_br_msp",  0xc5, 0x00 }, /* br_inst_retired.mispred	  */
+	{ "PAPI_br_ntk",  0xc4, 0x03 },
+				/* br_inst_retired.pred_not_taken|pred_taken */
+	{ "PAPI_br_prc",  0xc4, 0x05 },
+				/* br_inst_retired.pred_not_taken|pred_taken */
+	{ "PAPI_hw_int",  0xc8, 0x00 }, /* hw_int_rvc			  */
+	{ "PAPI_tot_iis", 0xaa, 0x01 }, /* macro_insts.decoded		  */
+	{ "PAPI_l1_dca",  0x43, 0x01 }, /* l1d_all_ref			  */
+	{ "PAPI_l1_icm",  0x81, 0x00 }, /* l1i_misses			  */
+	{ "PAPI_l1_icr",  0x80, 0x00 }, /* l1i_reads			  */
+	{ "PAPI_l1_tcw",  0x41, 0x0f }, /* l1d_cache_st.mesi		  */
+	{ "PAPI_l2_stm",  0x2a, 0x41 }, /* l2_st.self.i_state		  */
+	{ "PAPI_l2_tca",  0x2e, 0x4f }, /* l2_rqsts.self.demand.mesi	  */
+	{ "PAPI_l2_tch",  0x2e, 0x4e }, /* l2_rqsts.mes			  */
+	{ "PAPI_l2_tcm",  0x2e, 0x41 }, /* l2_rqsts.self.demand.i_state   */
+	{ "PAPI_l2_tcw",  0x2a, 0x4f }, /* l2_st.self.mesi		  */
+	{ "PAPI_ld_ins",  0xc0, 0x01 }, /* inst_retired.loads		  */
+	{ "PAPI_lst_ins", 0xc0, 0x03 }, /* inst_retired.loads|stores	  */
+	{ "PAPI_sr_ins",  0xc0, 0x02 }, /* inst_retired.stores		  */
+	{ "PAPI_tlb_dm",  0x08, 0x01 }, /* dtlb_misses.any		  */
+	{ "PAPI_tlb_im",  0x82, 0x12 }, /* itlb.small_miss|large_miss	  */
+	{ "PAPI_tlb_tl",  0x0c, 0x03 }, /* page_walks			  */
+	{ "",		  NT_END, 0  }
+};
+
+static const struct generic_events generic_events_pic0[] = {
+	{ "PAPI_l1_dcm",  0xcb, 0x01 }, /* mem_load_retired.l1d_miss */
+	{ "",		  NT_END, 0  }
+};
+
 /*
  * The events listed in the following table can be counted on all
  * general-purpose counters on processors that are of Penryn and Merom Family
@@ -361,22 +442,29 @@
 };
 
 /* FFC entries must be in order */
-char *ffc_names_non_htt[] = {
+static char *ffc_names_non_htt[] = {
 	"instr_retired.any",
 	"cpu_clk_unhalted.core",
 	"cpu_clk_unhalted.ref",
 	NULL
 };
 
-char *ffc_names_htt[] = {
+static char *ffc_names_htt[] = {
 	"instr_retired.any",
 	"cpu_clk_unhalted.thread",
 	"cpu_clk_unhalted.ref",
 	NULL
 };
 
-char **ffc_names = NULL;
+static char *ffc_genericnames[] = {
+	"PAPI_tot_ins",
+	"PAPI_tot_cyc",
+	"",
+	NULL
+};
 
+static char	**ffc_names = NULL;
+static char	**ffc_allnames = NULL;
 static char	**gpc_names = NULL;
 static uint32_t	versionid;
 static uint64_t	num_gpc;
@@ -423,20 +511,65 @@
 	{ 0xc4, 0x00, C_ALL, "br_inst_retired.all_branches" },	\
 	{ 0xc5, 0x00, C_ALL, "br_misp_retired.all_branches" }
 
-const struct events_table_t arch_events_table_non_htt[] = {
+static const struct events_table_t arch_events_table_non_htt[] = {
 	{ 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.core" },
 	ARCH_EVENTS_COMMON
 };
 
-const struct events_table_t arch_events_table_htt[] = {
+static const struct events_table_t arch_events_table_htt[] = {
 	{ 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.thread_p" },
 	ARCH_EVENTS_COMMON
 };
 
-const struct events_table_t *arch_events_table = NULL;
+static char *arch_genevents_table[] = {
+	"PAPI_tot_cyc", /* cpu_clk_unhalted.thread_p/core */
+	"PAPI_tot_ins", /* inst_retired.any_p		  */
+	"",		/* cpu_clk_unhalted.ref_p	  */
+	"",		/* longest_lat_cache.reference	  */
+	"",		/* longest_lat_cache.miss	  */
+	"",		/* br_inst_retired.all_branches	  */
+	"",		/* br_misp_retired.all_branches	  */
+};
+
+static const struct events_table_t *arch_events_table = NULL;
 static uint64_t known_arch_events;
 static uint64_t known_ffc_num;
 
+#define	GENERICEVENTS_FAM6_MOD26					       \
+{ 0xc4, 0x01, C0|C1|C2|C3, "PAPI_br_cn" },   /* br_inst_retired.conditional */ \
+{ 0x1d, 0x01, C0|C1|C2|C3, "PAPI_hw_int" },  /* hw_int.rcx		    */ \
+{ 0x17, 0x01, C0|C1|C2|C3, "PAPI_tot_iis" }, /* inst_queue_writes	    */ \
+{ 0x43, 0x01, C0|C1,	   "PAPI_l1_dca" },  /* l1d_all_ref.any		    */ \
+{ 0x24, 0x03, C0|C1|C2|C3, "PAPI_l1_dcm" },  /* l2_rqsts. loads and rfos    */ \
+{ 0x40, 0x0f, C0|C1|C2|C3, "PAPI_l1_dcr" },  /* l1d_cache_ld.mesi	    */ \
+{ 0x41, 0x0f, C0|C1|C2|C3, "PAPI_l1_dcw" },  /* l1d_cache_st.mesi	    */ \
+{ 0x80, 0x03, C0|C1|C2|C3, "PAPI_l1_ica" },  /* l1i.reads		    */ \
+{ 0x80, 0x01, C0|C1|C2|C3, "PAPI_l1_ich" },  /* l1i.hits		    */ \
+{ 0x80, 0x02, C0|C1|C2|C3, "PAPI_l1_icm" },  /* l1i.misses		    */ \
+{ 0x80, 0x03, C0|C1|C2|C3, "PAPI_l1_icr" },  /* l1i.reads		    */ \
+{ 0x24, 0x33, C0|C1|C2|C3, "PAPI_l1_ldm" },  /* l2_rqsts. loads and ifetches */\
+{ 0x24, 0xff, C0|C1|C2|C3, "PAPI_l1_tcm" },  /* l2_rqsts.references	    */ \
+{ 0x24, 0x02, C0|C1|C2|C3, "PAPI_l2_ldm" },  /* l2_rqsts.ld_miss	    */ \
+{ 0x24, 0x08, C0|C1|C2|C3, "PAPI_l2_stm" },  /* l2_rqsts.rfo_miss	    */ \
+{ 0x24, 0x3f, C0|C1|C2|C3, "PAPI_l2_tca" },				       \
+				/* l2_rqsts. loads, rfos and ifetches */       \
+{ 0x24, 0x15, C0|C1|C2|C3, "PAPI_l2_tch" },				       \
+				/* l2_rqsts. ld_hit, rfo_hit and ifetch_hit */ \
+{ 0x24, 0x2a, C0|C1|C2|C3, "PAPI_l2_tcm" },				       \
+			/* l2_rqsts. ld_miss, rfo_miss and ifetch_miss */      \
+{ 0x24, 0x33, C0|C1|C2|C3, "PAPI_l2_tcr" },  /* l2_rqsts. loads and ifetches */\
+{ 0x24, 0x0c, C0|C1|C2|C3, "PAPI_l2_tcw" },  /* l2_rqsts.rfos		    */ \
+{ 0x2e, 0x4f, C0|C1|C2|C3, "PAPI_l3_tca" },  /* l3_lat_cache.reference	    */ \
+{ 0x2e, 0x41, C0|C1|C2|C3, "PAPI_l3_tcm" },  /* l3_lat_cache.misses	    */ \
+{ 0x0b, 0x01, C0|C1|C2|C3, "PAPI_ld_ins" },  /* mem_inst_retired.loads	    */ \
+{ 0x0b, 0x03, C0|C1|C2|C3, "PAPI_lst_ins" },				       \
+				/* mem_inst_retired.loads and stores	    */ \
+{ 0x26, 0xf0, C0|C1|C2|C3, "PAPI_prf_dm" },  /* l2_data_rqsts.prefetch.mesi */ \
+{ 0x0b, 0x02, C0|C1|C2|C3, "PAPI_sr_ins" },  /* mem_inst_retired.stores	    */ \
+{ 0x49, 0x01, C0|C1|C2|C3, "PAPI_tlb_dm" },  /* dtlb_misses.any		    */ \
+{ 0x85, 0x01, C0|C1|C2|C3, "PAPI_tlb_im" }   /* itlb_misses.any		    */
+
+
 #define	EVENTS_FAM6_MOD26						\
 									\
 { 0x80, 0x04, C0|C1|C2|C3, "l1i.cycles_stalled" },			\
@@ -743,6 +876,25 @@
 { 0xCC, 0x02, C0|C1|C2|C3, "fp_mmx_trans.to_mmx" },			\
 { 0xC3, 0x04, C0|C1|C2|C3, "machine_clears.smc" }
 
+#define	GENERICEVENTS_FAM6_MOD28					       \
+{ 0xc4, 0x00, C0|C1, "PAPI_br_ins" },	/* br_inst_retired.any */	       \
+{ 0xc5, 0x00, C0|C1, "PAPI_br_msp" },	/* br_inst_retired.mispred */	       \
+{ 0xc4, 0x03, C0|C1, "PAPI_br_ntk" },					       \
+			/* br_inst_retired.pred_not_taken|mispred_not_taken */ \
+{ 0xc4, 0x05, C0|C1, "PAPI_br_prc" },					       \
+			/* br_inst_retired.pred_not_taken|pred_taken */	       \
+{ 0xc8, 0x00, C0|C1, "PAPI_hw_int" },	/* hw_int_rcv */	      	       \
+{ 0xaa, 0x03, C0|C1, "PAPI_tot_iis" },	/* macro_insts.all_decoded */	       \
+{ 0x40, 0x23, C0|C1, "PAPI_l1_dca" },	/* l1d_cache.l1|st */	      	       \
+{ 0x2a, 0x41, C0|C1, "PAPI_l2_stm" },	/* l2_st.self.i_state */	       \
+{ 0x2e, 0x4f, C0|C1, "PAPI_l2_tca" },	/* longest_lat_cache.reference */      \
+{ 0x2e, 0x4e, C0|C1, "PAPI_l2_tch" },   /* l2_rqsts.mes */		       \
+{ 0x2e, 0x41, C0|C1, "PAPI_l2_tcm" },	/* longest_lat_cache.miss */	       \
+{ 0x2a, 0x4f, C0|C1, "PAPI_l2_tcw" },	/* l2_st.self.mesi */		       \
+{ 0x08, 0x07, C0|C1, "PAPI_tlb_dm" },	/* data_tlb_misses.dtlb.miss */	       \
+{ 0x82, 0x02, C0|C1, "PAPI_tlb_im" }	/* itlb.misses */
+
+
 #define	EVENTS_FAM6_MOD28						\
 	{ 0x2,  0x81, C0|C1, "store_forwards.good" },                   \
 	{ 0x6,  0x0,  C0|C1, "segment_reg_loads.any" },                 \
@@ -867,11 +1019,13 @@
 static const struct events_table_t *events_table = NULL;
 
 const struct events_table_t events_fam6_mod26[] = {
+	GENERICEVENTS_FAM6_MOD26,
 	EVENTS_FAM6_MOD26,
 	{ NT_END, 0, 0, "" }
 };
 
 const struct events_table_t events_fam6_mod28[] = {
+	GENERICEVENTS_FAM6_MOD28,
 	EVENTS_FAM6_MOD28,
 	{ NT_END, 0, 0, "" }
 };
@@ -884,7 +1038,9 @@
 pcbe_init_core_uarch()
 {
 	const struct nametable_core_uarch	*n;
+	const struct generic_events		*k;
 	const struct nametable_core_uarch	*picspecific_events;
+	const struct generic_events		*picspecific_genericevents;
 	size_t			common_size;
 	size_t			size;
 	uint64_t		i;
@@ -897,11 +1053,18 @@
 		common_size += strlen(n->name) + 1;
 	}
 
+	for (k = cmn_generic_events; k->event_num != NT_END; k++) {
+		common_size += strlen(k->name) + 1;
+	}
+
 	for (i = 0; i < num_gpc; i++) {
 		size = 0;
+		picspecific_genericevents = NULL;
+
 		switch (i) {
 			case 0:
 				picspecific_events = pic0_events;
+				picspecific_genericevents = generic_events_pic0;
 				break;
 			case 1:
 				picspecific_events = pic1_events;
@@ -917,6 +1080,12 @@
 				size += strlen(n->name) + 1;
 			}
 		}
+		if (picspecific_genericevents != NULL) {
+			for (k = picspecific_genericevents;
+			    k->event_num != NT_END; k++) {
+				size += strlen(k->name) + 1;
+			}
+		}
 
 		gpc_names[i] =
 		    kmem_alloc(size + common_size + 1, KM_SLEEP);
@@ -924,17 +1093,28 @@
 		gpc_names[i][0] = '\0';
 		if (picspecific_events != NULL) {
 			for (n = picspecific_events;
-			    n->event_num != NT_END;
-			    n++) {
+			    n->event_num != NT_END; n++) {
 				(void) strcat(gpc_names[i], n->name);
 				(void) strcat(gpc_names[i], ",");
 			}
 		}
+		if (picspecific_genericevents != NULL) {
+			for (k = picspecific_genericevents;
+			    k->event_num != NT_END; k++) {
+				(void) strcat(gpc_names[i], k->name);
+				(void) strcat(gpc_names[i], ",");
+			}
+		}
 		for (n = cmn_gpc_events_core_uarch; n->event_num != NT_END;
 		    n++) {
 			(void) strcat(gpc_names[i], n->name);
 			(void) strcat(gpc_names[i], ",");
 		}
+		for (k = cmn_generic_events; k->event_num != NT_END; k++) {
+			(void) strcat(gpc_names[i], k->name);
+			(void) strcat(gpc_names[i], ",");
+		}
+
 		/*
 		 * Remove trailing comma.
 		 */
@@ -1065,7 +1245,24 @@
 		return (-1);
 	}
 
-	/* GPC events for Family 6 Models 15 & 23 only */
+	/* FFC names */
+	ffc_allnames = kmem_alloc(num_ffc * sizeof (char *), KM_SLEEP);
+	for (i = 0; i < num_ffc; i++) {
+		ffc_allnames[i] = kmem_alloc(
+		    strlen(ffc_names[i]) + strlen(ffc_genericnames[i]) + 2,
+		    KM_SLEEP);
+
+		ffc_allnames[i][0] = '\0';
+		(void) strcat(ffc_allnames[i], ffc_names[i]);
+
+		/* Check if this ffc has a generic name */
+		if (strcmp(ffc_genericnames[i], "") != 0) {
+			(void) strcat(ffc_allnames[i], ",");
+			(void) strcat(ffc_allnames[i], ffc_genericnames[i]);
+		}
+	}
+
+	/* GPC events for Family 6 Models 15, 23 and 29 only */
 	if ((cpuid_getfamily(CPU) == 6) &&
 	    ((cpuid_getmodel(CPU) == 15) || (cpuid_getmodel(CPU) == 23) ||
 	    (cpuid_getmodel(CPU) == 29))) {
@@ -1112,6 +1309,10 @@
 			if (((1U << i) & arch_events_vector) == 0) {
 				arch_events_string_length +=
 				    strlen(arch_events_table[i].name) + 1;
+				if (strcmp(arch_genevents_table[i], "") != 0) {
+					arch_events_string_length +=
+					    strlen(arch_genevents_table[i]) + 1;
+				}
 			}
 		}
 
@@ -1154,6 +1355,14 @@
 					(void) strcat(gpc_names[i],
 					    arch_events_table[j].name);
 					(void) strcat(gpc_names[i], ",");
+					if (strcmp(
+					    arch_genevents_table[j], "")
+					    != 0) {
+						(void) strcat(gpc_names[i],
+						    arch_genevents_table[j]);
+						(void) strcat(gpc_names[i],
+						    ",");
+					}
 				}
 			}
 
@@ -1171,10 +1380,7 @@
 			gpc_names[i][size - 1] = '\0';
 		}
 	}
-	/*
-	 * Fixed-function Counters (FFC) are already listed individually in
-	 * ffc_names[]
-	 */
+
 	return (0);
 }
 
@@ -1200,7 +1406,7 @@
 	if (picnum < num_gpc) {
 		return (gpc_names[picnum]);
 	} else {
-		return (ffc_names[picnum - num_gpc]);
+		return (ffc_allnames[picnum - num_gpc]);
 	}
 }
 
@@ -1234,6 +1440,20 @@
 	return (NULL);
 }
 
+static const struct generic_events *
+find_generic_events(char *name, const struct generic_events *table)
+{
+	const struct generic_events *n;
+
+	for (n = table; n->event_num != NT_END; n++) {
+		if (strcmp(name, n->name) == 0) {
+			return (n);
+		};
+	}
+
+	return (NULL);
+}
+
 static const struct events_table_t *
 find_gpcevent(char *name)
 {
@@ -1241,7 +1461,8 @@
 
 	/* Search architectural events */
 	for (i = 0; i < known_arch_events; i++) {
-		if (strcmp(name, arch_events_table[i].name) == 0) {
+		if (strcmp(name, arch_events_table[i].name) == 0 ||
+		    strcmp(name, arch_genevents_table[i]) == 0) {
 			if (((1U << i) & arch_events_vector) == 0) {
 				return (&arch_events_table[i]);
 			}
@@ -1259,6 +1480,7 @@
 
 	return (NULL);
 }
+
 static uint64_t
 core_pcbe_event_coverage(char *event)
 {
@@ -1277,8 +1499,12 @@
 			    BITMASK_XBITS(num_gpc));
 		}
 	} else {
-		if (find_gpcevent_core_uarch(event, cmn_gpc_events_core_uarch)
-		    != NULL) {
+		if (find_generic_events(event, cmn_generic_events) != NULL) {
+			bitmap |= BITMASK_XBITS(num_gpc);
+		} if (find_generic_events(event, generic_events_pic0) != NULL) {
+			bitmap |= 1ULL;
+		} else if (find_gpcevent_core_uarch(event,
+		    cmn_gpc_events_core_uarch) != NULL) {
 			bitmap |= BITMASK_XBITS(num_gpc);
 		} else if (find_gpcevent_core_uarch(event, pic0_events) !=
 		    NULL) {
@@ -1295,6 +1521,8 @@
 		for (i = 0; i < num_ffc; i++) {
 			if (strcmp(event, ffc_names[i]) == 0) {
 				bitmap |= bitmask;
+			} else if (strcmp(event, ffc_genericnames[i]) == 0) {
+				bitmap |= bitmask;
 			}
 			bitmask = bitmask << 1;
 		}
@@ -1344,6 +1572,7 @@
 {
 	core_pcbe_config_t	conf;
 	const struct nametable_core_uarch	*n;
+	const struct generic_events *k = NULL;
 	const struct nametable_core_uarch	*m;
 	const struct nametable_core_uarch	*picspecific_events;
 	struct nametable_core_uarch	nt_raw = { "", 0x0, 0x0 };
@@ -1369,6 +1598,10 @@
 			if ((C(picnum) & eventcode->supported_counters) == 0) {
 				return (CPC_PIC_NOT_CAPABLE);
 			}
+			if (nattrs > 0 &&
+			    (strncmp("PAPI_", event, 5) == 0)) {
+				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
+			}
 			conf.core_ctl = eventcode->eventselect;
 			conf.core_ctl |= eventcode->unitmask <<
 			    CORE_UMASK_SHIFT;
@@ -1380,58 +1613,78 @@
 			conf.core_ctl = event_num & 0xFF;
 		}
 	} else {
-		n = find_gpcevent_core_uarch(event, cmn_gpc_events_core_uarch);
-		if (n == NULL) {
-			switch (picnum) {
-				case 0:
-					picspecific_events = pic0_events;
-					break;
-				case 1:
-					picspecific_events = pic1_events;
-					break;
-				default:
-					picspecific_events = NULL;
-					break;
-			}
-			if (picspecific_events != NULL) {
-				n = find_gpcevent_core_uarch(event,
-				    picspecific_events);
+		if ((k = find_generic_events(event, cmn_generic_events)) !=
+		    NULL ||
+		    (picnum == 0 &&
+		    (k = find_generic_events(event, generic_events_pic0)) !=
+		    NULL)) {
+			if (nattrs > 0) {
+				return (CPC_ATTRIBUTE_OUT_OF_RANGE);
 			}
-		}
-		if (n == NULL) {
-			/*
-			 * Check if this is a case where the event was
-			 * specified directly by its event number instead of
-			 * its name string.
-			 */
-			if (ddi_strtol(event, NULL, 0, &event_num) != 0) {
-				return (CPC_INVALID_EVENT);
-			}
-
-			event_num = event_num & 0xFF;
+			conf.core_ctl = k->event_num;
+			conf.core_ctl |= k->umask << CORE_UMASK_SHIFT;
+		} else {
+			/* Not a generic event */
 
-			/*
-			 * Search the event table to find out if the event
-			 * specified has an privilege requirements.  Currently
-			 * none of the pic-specific counters have any privilege
-			 * requirements.  Hence only the table
-			 * cmn_gpc_events_core_uarch is searched.
-			 */
-			for (m = cmn_gpc_events_core_uarch;
-			    m->event_num != NT_END;
-			    m++) {
-				if (event_num == m->event_num) {
-					break;
+			n = find_gpcevent_core_uarch(event,
+			    cmn_gpc_events_core_uarch);
+			if (n == NULL) {
+				switch (picnum) {
+					case 0:
+						picspecific_events =
+						    pic0_events;
+						break;
+					case 1:
+						picspecific_events =
+						    pic1_events;
+						break;
+					default:
+						picspecific_events = NULL;
+						break;
+				}
+				if (picspecific_events != NULL) {
+					n = find_gpcevent_core_uarch(event,
+					    picspecific_events);
 				}
 			}
-			if (m->event_num == NT_END) {
-				nt_raw.event_num = (uint8_t)event_num;
-				n = &nt_raw;
-			} else {
-				n = m;
+			if (n == NULL) {
+
+				/*
+				 * Check if this is a case where the event was
+				 * specified directly by its event number
+				 * instead of its name string.
+				 */
+				if (ddi_strtol(event, NULL, 0, &event_num) !=
+				    0) {
+					return (CPC_INVALID_EVENT);
+				}
+
+				event_num = event_num & 0xFF;
+
+				/*
+				 * Search the event table to find out if the
+				 * event specified has an privilege
+				 * requirements.  Currently none of the
+				 * pic-specific counters have any privilege
+				 * requirements.  Hence only the table
+				 * cmn_gpc_events_core_uarch is searched.
+				 */
+				for (m = cmn_gpc_events_core_uarch;
+				    m->event_num != NT_END;
+				    m++) {
+					if (event_num == m->event_num) {
+						break;
+					}
+				}
+				if (m->event_num == NT_END) {
+					nt_raw.event_num = (uint8_t)event_num;
+					n = &nt_raw;
+				} else {
+					n = m;
+				}
 			}
+			conf.core_ctl = n->event_num; /* Event Select */
 		}
-		conf.core_ctl = n->event_num; /* Event Select */
 	}
 
 
@@ -1489,7 +1742,7 @@
 		conf.core_ctl |= CORE_INT;
 	conf.core_ctl |= CORE_EN;
 
-	if (versionid < 3) {
+	if (versionid < 3 && k == NULL) {
 		if (check_cpc_securitypolicy(&conf, n) != 0) {
 			return (CPC_ATTR_REQUIRES_PRIVILEGE);
 		}
@@ -1512,7 +1765,8 @@
 		return (CPC_INVALID_PICNUM);
 	}
 
-	if (strcmp(ffc_names[picnum-num_gpc], event) != 0) {
+	if ((strcmp(ffc_names[picnum-num_gpc], event) != 0) &&
+	    (strcmp(ffc_genericnames[picnum-num_gpc], event) != 0)) {
 		return (CPC_INVALID_EVENT);
 	}