| /* |
| * pfmlib_intel_snbep_unc.c : Intel SandyBridge-EP uncore PMU common code |
| * |
| * Copyright (c) 2012 Google, Inc |
| * Contributed by Stephane Eranian <eranian@gmail.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
| * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
| * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE |
| * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include <sys/types.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| /* private headers */ |
| #include "pfmlib_priv.h" |
| #include "pfmlib_intel_x86_priv.h" |
| #include "pfmlib_intel_snbep_unc_priv.h" |
| |
| const pfmlib_attr_desc_t snbep_unc_mods[]={ |
| PFM_ATTR_B("e", "edge detect"), /* edge */ |
| PFM_ATTR_B("i", "invert"), /* invert */ |
| PFM_ATTR_I("t", "threshold in range [0-255]"), /* threshold */ |
| PFM_ATTR_I("t", "threshold in range [0-31]"), /* threshold */ |
| PFM_ATTR_I("tf", "thread id filter [0-1]"), /* thread id */ |
| PFM_ATTR_I("cf", "core id filter, includes non-thread data in bit 4 [0-15]"), /* core id (ivbep) */ |
| PFM_ATTR_I("nf", "node id bitmask filter [0-255]"),/* nodeid mask filter0 */ |
| PFM_ATTR_I("ff", "frequency >= 100Mhz * [0-255]"),/* freq filter */ |
| PFM_ATTR_I("addr", "physical address matcher [40 bits]"),/* address matcher */ |
| PFM_ATTR_I("nf", "node id bitmask filter [0-255]"),/* nodeid mask filter1 */ |
| PFM_ATTR_B("isoc", "match isochronous requests"), /* isochronous */ |
| PFM_ATTR_B("nc", "match non-coherent requests"), /* non-coherent */ |
| PFM_ATTR_NULL |
| }; |
| |
| int |
| pfm_intel_snbep_unc_detect(void *this) |
| { |
| int ret; |
| |
| ret = pfm_intel_x86_detect(); |
| if (ret != PFM_SUCCESS) |
| |
| if (pfm_intel_x86_cfg.family != 6) |
| return PFM_ERR_NOTSUPP; |
| |
| switch(pfm_intel_x86_cfg.model) { |
| case 45: /* SandyBridge-EP */ |
| break; |
| default: |
| return PFM_ERR_NOTSUPP; |
| } |
| return PFM_SUCCESS; |
| } |
| |
| int |
| pfm_intel_ivbep_unc_detect(void *this) |
| { |
| int ret; |
| |
| ret = pfm_intel_x86_detect(); |
| if (ret != PFM_SUCCESS) |
| |
| if (pfm_intel_x86_cfg.family != 6) |
| return PFM_ERR_NOTSUPP; |
| |
| switch(pfm_intel_x86_cfg.model) { |
| case 62: /* SandyBridge-EP */ |
| break; |
| default: |
| return PFM_ERR_NOTSUPP; |
| } |
| return PFM_SUCCESS; |
| } |
| |
| static void |
| display_com(void *this, pfmlib_event_desc_t *e, void *val) |
| { |
| const intel_x86_entry_t *pe = this_pe(this); |
| pfm_snbep_unc_reg_t *reg = val; |
| |
| __pfm_vbprintf("[UNC=0x%"PRIx64" event=0x%x umask=0x%x en=%d " |
| "inv=%d edge=%d thres=%d] %s\n", |
| reg->val, |
| reg->com.unc_event, |
| reg->com.unc_umask, |
| reg->com.unc_en, |
| reg->com.unc_inv, |
| reg->com.unc_edge, |
| reg->com.unc_thres, |
| pe[e->event].name); |
| } |
| |
| static void |
| display_reg(void *this, pfmlib_event_desc_t *e, pfm_snbep_unc_reg_t reg) |
| { |
| pfmlib_pmu_t *pmu = this; |
| if (pmu->display_reg) |
| pmu->display_reg(this, e, ®); |
| else |
| display_com(this, e, ®); |
| } |
| |
| static inline int |
| is_occ_event(void *this, int idx) |
| { |
| pfmlib_pmu_t *pmu = this; |
| const intel_x86_entry_t *pe = this_pe(this); |
| |
| return (pmu->flags & INTEL_PMU_FL_UNC_OCC) && (pe[idx].code & 0x80); |
| } |
| |
| static inline int |
| get_pcu_filt_band(void *this, pfm_snbep_unc_reg_t reg) |
| { |
| #define PCU_FREQ_BAND0_CODE 0xb /* event code for UNC_P_FREQ_BAND0_CYCLES */ |
| return reg.pcu.unc_event - PCU_FREQ_BAND0_CODE; |
| } |
| |
| int |
| snbep_unc_add_defaults(void *this, pfmlib_event_desc_t *e, |
| unsigned int msk, |
| uint64_t *umask, |
| pfm_snbep_unc_reg_t *filters, |
| unsigned int max_grpid) |
| { |
| const intel_x86_entry_t *pe = this_pe(this); |
| const intel_x86_entry_t *ent; |
| unsigned int i; |
| int j, k, added, skip; |
| int idx; |
| |
| k = e->nattrs; |
| ent = pe+e->event; |
| |
| for(i=0; msk; msk >>=1, i++) { |
| |
| if (!(msk & 0x1)) |
| continue; |
| |
| added = skip = 0; |
| |
| for (j = 0; j < e->npattrs; j++) { |
| if (e->pattrs[j].ctrl != PFM_ATTR_CTRL_PMU) |
| continue; |
| |
| if (e->pattrs[j].type != PFM_ATTR_UMASK) |
| continue; |
| |
| idx = e->pattrs[j].idx; |
| |
| if (ent->umasks[idx].grpid != i) |
| continue; |
| |
| if (max_grpid != INTEL_X86_MAX_GRPID && i > max_grpid) { |
| skip = 1; |
| continue; |
| } |
| |
| if (intel_x86_uflag(this, e->event, idx, INTEL_X86_GRP_DFL_NONE)) { |
| skip = 1; |
| continue; |
| } |
| |
| /* umask is default for group */ |
| if (intel_x86_uflag(this, e->event, idx, INTEL_X86_DFL)) { |
| DPRINT("added default %s for group %d j=%d idx=%d ucode=0x%"PRIx64"\n", |
| ent->umasks[idx].uname, |
| i, |
| j, |
| idx, |
| ent->umasks[idx].ucode); |
| /* |
| * default could be an alias, but |
| * ucode must reflect actual code |
| */ |
| *umask |= ent->umasks[idx].ucode >> 8; |
| |
| filters[0].val |= pe[e->event].umasks[idx].ufilters[0]; |
| filters[1].val |= pe[e->event].umasks[idx].ufilters[1]; |
| |
| e->attrs[k].id = j; /* pattrs index */ |
| e->attrs[k].ival = 0; |
| k++; |
| |
| added++; |
| if (intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) |
| goto done; |
| |
| if (intel_x86_uflag(this, e->event, idx, INTEL_X86_EXCL_GRP_GT)) { |
| if (max_grpid != INTEL_X86_MAX_GRPID) { |
| DPRINT("two max_grpid, old=%d new=%d\n", max_grpid, ent->umasks[idx].grpid); |
| return PFM_ERR_UMASK; |
| } |
| max_grpid = ent->umasks[idx].grpid; |
| } |
| } |
| } |
| if (!added && !skip) { |
| DPRINT("no default found for event %s unit mask group %d (max_grpid=%d)\n", ent->name, i, max_grpid); |
| return PFM_ERR_UMASK; |
| } |
| } |
| DPRINT("max_grpid=%d nattrs=%d k=%d umask=0x%"PRIx64"\n", max_grpid, e->nattrs, k, *umask); |
| done: |
| e->nattrs = k; |
| return PFM_SUCCESS; |
| } |
| |
| |
| /* |
| * common encoding routine |
| */ |
| int |
| pfm_intel_snbep_unc_get_encoding(void *this, pfmlib_event_desc_t *e) |
| { |
| const intel_x86_entry_t *pe = this_pe(this); |
| unsigned int grpmsk, ugrpmsk = 0; |
| unsigned int max_grpid = INTEL_X86_MAX_GRPID; |
| unsigned int last_grpid = INTEL_X86_MAX_GRPID; |
| int umodmsk = 0, modmsk_r = 0; |
| int pcu_filt_band = -1; |
| pfm_snbep_unc_reg_t reg; |
| pfm_snbep_unc_reg_t filters[INTEL_X86_MAX_FILTERS]; |
| pfm_snbep_unc_reg_t addr; |
| pfm_event_attr_info_t *a; |
| uint64_t val, umask1, umask2; |
| int k, ret; |
| int has_cbo_tid = 0; |
| unsigned int grpid; |
| int grpcounts[INTEL_X86_NUM_GRP]; |
| int ncombo[INTEL_X86_NUM_GRP]; |
| char umask_str[PFMLIB_EVT_MAX_NAME_LEN]; |
| |
| memset(grpcounts, 0, sizeof(grpcounts)); |
| memset(ncombo, 0, sizeof(ncombo)); |
| memset(filters, 0, sizeof(filters)); |
| |
| addr.val = 0; |
| |
| pe = this_pe(this); |
| |
| umask_str[0] = e->fstr[0] = '\0'; |
| |
| reg.val = val = pe[e->event].code; |
| |
| /* take into account hardcoded umask */ |
| umask1 = (val >> 8) & 0xff; |
| umask2 = umask1; |
| |
| grpmsk = (1 << pe[e->event].ngrp)-1; |
| |
| modmsk_r = pe[e->event].modmsk_req; |
| |
| for(k=0; k < e->nattrs; k++) { |
| a = attr(e, k); |
| |
| if (a->ctrl != PFM_ATTR_CTRL_PMU) |
| continue; |
| |
| if (a->type == PFM_ATTR_UMASK) { |
| uint64_t um; |
| |
| grpid = pe[e->event].umasks[a->idx].grpid; |
| |
| /* |
| * certain event groups are meant to be |
| * exclusive, i.e., only unit masks of one group |
| * can be used |
| */ |
| if (last_grpid != INTEL_X86_MAX_GRPID && grpid != last_grpid |
| && intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) { |
| DPRINT("exclusive unit mask group error\n"); |
| return PFM_ERR_FEATCOMB; |
| } |
| |
| /* |
| * selecting certain umasks in a group may exclude any umasks |
| * from any groups with a higher index |
| * |
| * enforcement requires looking at the grpid of all the umasks |
| */ |
| if (intel_x86_uflag(this, e->event, a->idx, INTEL_X86_EXCL_GRP_GT)) |
| max_grpid = grpid; |
| |
| /* |
| * certain event groups are meant to be |
| * exclusive, i.e., only unit masks of one group |
| * can be used |
| */ |
| if (last_grpid != INTEL_X86_MAX_GRPID && grpid != last_grpid |
| && intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) { |
| DPRINT("exclusive unit mask group error\n"); |
| return PFM_ERR_FEATCOMB; |
| } |
| /* |
| * upper layer has removed duplicates |
| * so if we come here more than once, it is for two |
| * disinct umasks |
| * |
| * NCOMBO=no combination of unit masks within the same |
| * umask group |
| */ |
| ++grpcounts[grpid]; |
| |
| /* mark that we have a umask with NCOMBO in this group */ |
| if (intel_x86_uflag(this, e->event, a->idx, INTEL_X86_NCOMBO)) |
| ncombo[grpid] = 1; |
| |
| /* |
| * if more than one umask in this group but one is marked |
| * with ncombo, then fail. It is okay to combine umask within |
| * a group as long as none is tagged with NCOMBO |
| */ |
| if (grpcounts[grpid] > 1 && ncombo[grpid]) { |
| DPRINT("umask %s does not support unit mask combination within group %d\n", pe[e->event].umasks[a->idx].uname, grpid); |
| return PFM_ERR_FEATCOMB; |
| } |
| |
| last_grpid = grpid; |
| |
| um = pe[e->event].umasks[a->idx].ucode; |
| filters[0].val |= pe[e->event].umasks[a->idx].ufilters[0]; |
| filters[1].val |= pe[e->event].umasks[a->idx].ufilters[1]; |
| |
| um >>= 8; |
| umask2 |= um; |
| |
| ugrpmsk |= 1 << pe[e->event].umasks[a->idx].grpid; |
| |
| /* PCU occ event */ |
| if (is_occ_event(this, e->event)) { |
| reg.pcu.unc_occ = umask2 >> 6; |
| umask2 = 0; |
| } else |
| reg.val |= umask2 << 8; |
| |
| evt_strcat(umask_str, ":%s", pe[e->event].umasks[a->idx].uname); |
| |
| modmsk_r |= pe[e->event].umasks[a->idx].umodmsk_req; |
| |
| } else if (a->type == PFM_ATTR_RAW_UMASK) { |
| |
| /* there can only be one RAW_UMASK per event */ |
| |
| /* sanity check */ |
| if (a->idx & ~0xff) { |
| DPRINT("raw umask is 8-bit wide\n"); |
| return PFM_ERR_ATTR; |
| } |
| /* override umask */ |
| umask2 = a->idx & 0xff; |
| ugrpmsk = grpmsk; |
| } else { |
| uint64_t ival = e->attrs[k].ival; |
| switch(a->idx) { |
| case SNBEP_UNC_ATTR_I: /* invert */ |
| if (is_occ_event(this, e->event)) |
| reg.pcu.unc_occ_inv = !!ival; |
| else |
| reg.com.unc_inv = !!ival; |
| umodmsk |= _SNBEP_UNC_ATTR_I; |
| break; |
| case SNBEP_UNC_ATTR_E: /* edge */ |
| if (is_occ_event(this, e->event)) |
| reg.pcu.unc_occ_edge = !!ival; |
| else |
| reg.com.unc_edge = !!ival; |
| umodmsk |= _SNBEP_UNC_ATTR_E; |
| break; |
| case SNBEP_UNC_ATTR_T8: /* counter-mask */ |
| /* already forced, cannot overwrite */ |
| if (ival > 255) |
| return PFM_ERR_ATTR_VAL; |
| reg.com.unc_thres = ival; |
| umodmsk |= _SNBEP_UNC_ATTR_T8; |
| break; |
| case SNBEP_UNC_ATTR_T5: /* pcu counter-mask */ |
| /* already forced, cannot overwrite */ |
| if (ival > 31) |
| return PFM_ERR_ATTR_VAL; |
| reg.pcu.unc_thres = ival; |
| umodmsk |= _SNBEP_UNC_ATTR_T5; |
| break; |
| case SNBEP_UNC_ATTR_TF: /* thread id */ |
| if (ival > 1) { |
| DPRINT("invalid thread id, must be < 1"); |
| return PFM_ERR_ATTR_VAL; |
| } |
| reg.cbo.unc_tid = 1; |
| has_cbo_tid = 1; |
| filters[0].cbo_filt.tid = ival; |
| umodmsk |= _SNBEP_UNC_ATTR_TF; |
| break; |
| case SNBEP_UNC_ATTR_CF: /* core id */ |
| if (ival > 15) |
| return PFM_ERR_ATTR_VAL; |
| reg.cbo.unc_tid = 1; |
| filters[0].cbo_filt.cid = ival; |
| has_cbo_tid = 1; |
| umodmsk |= _SNBEP_UNC_ATTR_CF; |
| break; |
| case SNBEP_UNC_ATTR_NF: /* node id filter0 */ |
| if (ival > 255 || ival == 0) { |
| DPRINT("invalid nf, 0 < nf < 256\n"); |
| return PFM_ERR_ATTR_VAL; |
| } |
| filters[0].cbo_filt.nid = ival; |
| umodmsk |= _SNBEP_UNC_ATTR_NF; |
| break; |
| case SNBEP_UNC_ATTR_NF1: /* node id filter1 */ |
| if (ival > 255 || ival == 0) { |
| DPRINT("invalid nf, 0 < nf < 256\n"); |
| return PFM_ERR_ATTR_VAL; |
| } |
| filters[1].ivbep_cbo_filt1.nid = ival; |
| umodmsk |= _SNBEP_UNC_ATTR_NF1; |
| break; |
| case SNBEP_UNC_ATTR_FF: /* freq band filter */ |
| if (ival > 255) |
| return PFM_ERR_ATTR_VAL; |
| pcu_filt_band = get_pcu_filt_band(this, reg); |
| filters[0].val = ival << (pcu_filt_band * 8); |
| umodmsk |= _SNBEP_UNC_ATTR_FF; |
| break; |
| case SNBEP_UNC_ATTR_A: /* addr filter */ |
| if (ival & ~((1ULL << 40)-1)) { |
| DPRINT("address filter 40bits max\n"); |
| return PFM_ERR_ATTR_VAL; |
| } |
| addr.ha_addr.lo_addr = ival; /* LSB 26 bits */ |
| addr.ha_addr.hi_addr = (ival >> 26) & ((1ULL << 14)-1); |
| umodmsk |= _SNBEP_UNC_ATTR_A; |
| break; |
| case SNBEP_UNC_ATTR_ISOC: /* isoc filter */ |
| filters[1].ivbep_cbo_filt1.isoc = !!ival; |
| break; |
| case SNBEP_UNC_ATTR_NC: /* nc filter */ |
| filters[1].ivbep_cbo_filt1.nc = !!ival; |
| break; |
| } |
| } |
| } |
| /* |
| * check that there is at least of unit mask in each unit mask group |
| */ |
| if (pe[e->event].numasks && (ugrpmsk != grpmsk || ugrpmsk == 0)) { |
| uint64_t um = 0; |
| ugrpmsk ^= grpmsk; |
| ret = snbep_unc_add_defaults(this, e, ugrpmsk, &um, filters, max_grpid); |
| if (ret != PFM_SUCCESS) |
| return ret; |
| umask2 |= um; |
| } |
| |
| /* |
| * nf= is only required on some events in CBO |
| */ |
| if (!(modmsk_r & _SNBEP_UNC_ATTR_NF) && (umodmsk & _SNBEP_UNC_ATTR_NF)) { |
| DPRINT("using nf= on an umask which does not require it\n"); |
| return PFM_ERR_ATTR; |
| } |
| if (!(modmsk_r & _SNBEP_UNC_ATTR_NF1) && (umodmsk & _SNBEP_UNC_ATTR_NF1)) { |
| DPRINT("using nf= on an umask which does not require it\n"); |
| return PFM_ERR_ATTR; |
| } |
| |
| if (modmsk_r && !(umodmsk & modmsk_r)) { |
| DPRINT("required modifiers missing: 0x%x\n", modmsk_r); |
| return PFM_ERR_ATTR; |
| } |
| |
| evt_strcat(e->fstr, "%s", pe[e->event].name); |
| pfmlib_sort_attr(e); |
| |
| for(k = 0; k < e->nattrs; k++) { |
| a = attr(e, k); |
| if (a->ctrl != PFM_ATTR_CTRL_PMU) |
| continue; |
| if (a->type == PFM_ATTR_UMASK) |
| evt_strcat(e->fstr, ":%s", pe[e->event].umasks[a->idx].uname); |
| else if (a->type == PFM_ATTR_RAW_UMASK) |
| evt_strcat(e->fstr, ":0x%x", a->idx); |
| } |
| DPRINT("umask2=0x%"PRIx64" umask1=0x%"PRIx64"\n", umask2, umask1); |
| e->count = 0; |
| reg.val |= (umask1 | umask2) << 8; |
| |
| e->codes[e->count++] = reg.val; |
| |
| /* |
| * handles C-box filter |
| */ |
| if (filters[0].val || filters[1].val || has_cbo_tid) |
| e->codes[e->count++] = filters[0].val; |
| if (filters[1].val) |
| e->codes[e->count++] = filters[1].val; |
| |
| /* HA address matcher */ |
| if (addr.val) |
| e->codes[e->count++] = addr.val; |
| |
| for (k = 0; k < e->npattrs; k++) { |
| int idx; |
| |
| if (e->pattrs[k].ctrl != PFM_ATTR_CTRL_PMU) |
| continue; |
| |
| if (e->pattrs[k].type == PFM_ATTR_UMASK) |
| continue; |
| |
| idx = e->pattrs[k].idx; |
| switch(idx) { |
| case SNBEP_UNC_ATTR_E: |
| if (is_occ_event(this, e->event)) |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_occ_edge); |
| else |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_edge); |
| break; |
| case SNBEP_UNC_ATTR_I: |
| if (is_occ_event(this, e->event)) |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_occ_inv); |
| else |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_inv); |
| break; |
| case SNBEP_UNC_ATTR_T8: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_thres); |
| break; |
| case SNBEP_UNC_ATTR_T5: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_thres); |
| break; |
| case SNBEP_UNC_ATTR_TF: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.cbo.unc_tid); |
| break; |
| case SNBEP_UNC_ATTR_CF: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[0].cbo_filt.cid); |
| break; |
| case SNBEP_UNC_ATTR_FF: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, (filters[0].val >> (pcu_filt_band*8)) & 0xff); |
| break; |
| case SNBEP_UNC_ATTR_ISOC: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.isoc); |
| break; |
| case SNBEP_UNC_ATTR_NC: |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.nc); |
| break; |
| case SNBEP_UNC_ATTR_NF: |
| if (modmsk_r & _SNBEP_UNC_ATTR_NF) |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[0].cbo_filt.nid); |
| break; |
| case SNBEP_UNC_ATTR_NF1: |
| if (modmsk_r & _SNBEP_UNC_ATTR_NF1) |
| evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.nid); |
| break; |
| case SNBEP_UNC_ATTR_A: |
| evt_strcat(e->fstr, ":%s=0x%lx", snbep_unc_mods[idx].name, |
| addr.ha_addr.hi_addr << 26 | addr.ha_addr.lo_addr); |
| break; |
| } |
| } |
| display_reg(this, e, reg); |
| return PFM_SUCCESS; |
| } |
| |
| int |
| pfm_intel_snbep_unc_can_auto_encode(void *this, int pidx, int uidx) |
| { |
| if (intel_x86_eflag(this, pidx, INTEL_X86_NO_AUTOENCODE)) |
| return 0; |
| |
| return !intel_x86_uflag(this, pidx, uidx, INTEL_X86_NO_AUTOENCODE); |
| } |
| |
| int |
| pfm_intel_snbep_unc_get_event_attr_info(void *this, int pidx, int attr_idx, pfm_event_attr_info_t *info) |
| { |
| const intel_x86_entry_t *pe = this_pe(this); |
| const pfmlib_attr_desc_t *atdesc = this_atdesc(this); |
| int numasks, idx; |
| |
| numasks = intel_x86_num_umasks(this, pidx); |
| if (attr_idx < numasks) { |
| idx = intel_x86_attr2umask(this, pidx, attr_idx); |
| info->name = pe[pidx].umasks[idx].uname; |
| info->desc = pe[pidx].umasks[idx].udesc; |
| info->equiv= pe[pidx].umasks[idx].uequiv; |
| |
| info->code = pe[pidx].umasks[idx].ucode; |
| |
| if (!intel_x86_uflag(this, pidx, idx, INTEL_X86_CODE_OVERRIDE)) |
| info->code >>= 8; |
| |
| if (info->code == 0) |
| info->code = pe[pidx].umasks[idx].ufilters[0]; |
| |
| info->type = PFM_ATTR_UMASK; |
| info->is_dfl = intel_x86_uflag(this, pidx, idx, INTEL_X86_DFL); |
| info->is_precise = intel_x86_uflag(this, pidx, idx, INTEL_X86_PEBS); |
| } else { |
| idx = intel_x86_attr2mod(this, pidx, attr_idx); |
| info->name = atdesc[idx].name; |
| info->desc = atdesc[idx].desc; |
| info->type = atdesc[idx].type; |
| info->equiv= NULL; |
| info->code = idx; |
| info->is_dfl = 0; |
| info->is_precise = 0; |
| } |
| |
| info->ctrl = PFM_ATTR_CTRL_PMU; |
| info->idx = idx; /* namespace specific index */ |
| info->dfl_val64 = 0; |
| |
| return PFM_SUCCESS; |
| } |