parlib: Expand our printf hacks
[akaros.git] / user / perfmon / pfmlib_intel_snbep_unc.c
1 /*
2  * pfmlib_intel_snbep_unc.c : Intel SandyBridge-EP uncore PMU common code
3  *
4  * Copyright (c) 2012 Google, Inc
5  * Contributed by Stephane Eranian <eranian@gmail.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11  * of the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
19  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <sys/types.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 /* private headers */
31 #include "pfmlib_priv.h"
32 #include "pfmlib_intel_x86_priv.h"
33 #include "pfmlib_intel_snbep_unc_priv.h"
34
35 const pfmlib_attr_desc_t snbep_unc_mods[]={
36         PFM_ATTR_B("e", "edge detect"),                 /* edge */
37         PFM_ATTR_B("i", "invert"),                      /* invert */
38         PFM_ATTR_I("t", "threshold in range [0-255]"),  /* threshold */
39         PFM_ATTR_I("t", "threshold in range [0-31]"),   /* threshold */
40         PFM_ATTR_I("tf", "thread id filter [0-1]"),     /* thread id */
41         PFM_ATTR_I("cf", "core id filter, includes non-thread data in bit 4 [0-15]"),   /* core id (ivbep) */
42         PFM_ATTR_I("nf", "node id bitmask filter [0-255]"),/* nodeid mask filter0 */
43         PFM_ATTR_I("ff", "frequency >= 100Mhz * [0-255]"),/* freq filter */
44         PFM_ATTR_I("addr", "physical address matcher [40 bits]"),/* address matcher */
45         PFM_ATTR_I("nf", "node id bitmask filter [0-255]"),/* nodeid mask filter1 */
46         PFM_ATTR_B("isoc", "match isochronous requests"),   /* isochronous */
47         PFM_ATTR_B("nc", "match non-coherent requests"),   /* non-coherent */
48         PFM_ATTR_NULL
49 };
50
51 int
52 pfm_intel_snbep_unc_detect(void *this)
53 {
54         int ret;
55
56         ret = pfm_intel_x86_detect();
57         if (ret != PFM_SUCCESS)
58
59         if (pfm_intel_x86_cfg.family != 6)
60                 return PFM_ERR_NOTSUPP;
61
62         switch(pfm_intel_x86_cfg.model) {
63                 case 45: /* SandyBridge-EP */
64                           break;
65                 default:
66                         return PFM_ERR_NOTSUPP;
67         }
68         return PFM_SUCCESS;
69 }
70
71 int
72 pfm_intel_ivbep_unc_detect(void *this)
73 {
74        int ret;
75
76        ret = pfm_intel_x86_detect();
77        if (ret != PFM_SUCCESS)
78
79        if (pfm_intel_x86_cfg.family != 6)
80                return PFM_ERR_NOTSUPP;
81
82        switch(pfm_intel_x86_cfg.model) {
83                case 62: /* SandyBridge-EP */
84                          break;
85                default:
86                        return PFM_ERR_NOTSUPP;
87        }
88        return PFM_SUCCESS;
89 }
90
91 static void
92 display_com(void *this, pfmlib_event_desc_t *e, void *val)
93 {
94         const intel_x86_entry_t *pe = this_pe(this);
95         pfm_snbep_unc_reg_t *reg = val;
96
97         __pfm_vbprintf("[UNC=0x%"PRIx64" event=0x%x umask=0x%x en=%d "
98                        "inv=%d edge=%d thres=%d] %s\n",
99                         reg->val,
100                         reg->com.unc_event,
101                         reg->com.unc_umask,
102                         reg->com.unc_en,
103                         reg->com.unc_inv,
104                         reg->com.unc_edge,
105                         reg->com.unc_thres,
106                         pe[e->event].name);
107 }
108
109 static void
110 display_reg(void *this, pfmlib_event_desc_t *e, pfm_snbep_unc_reg_t reg)
111 {
112         pfmlib_pmu_t *pmu = this;
113         if (pmu->display_reg)
114                 pmu->display_reg(this, e, &reg);
115         else
116                 display_com(this, e, &reg);
117 }
118
119 static inline int
120 is_occ_event(void *this, int idx)
121 {
122         pfmlib_pmu_t *pmu = this;
123         const intel_x86_entry_t *pe = this_pe(this);
124
125         return (pmu->flags & INTEL_PMU_FL_UNC_OCC) && (pe[idx].code & 0x80);
126 }
127
128 static inline int
129 get_pcu_filt_band(void *this, pfm_snbep_unc_reg_t reg)
130 {
131 #define PCU_FREQ_BAND0_CODE     0xb /* event code for UNC_P_FREQ_BAND0_CYCLES */
132         return reg.pcu.unc_event - PCU_FREQ_BAND0_CODE;
133 }
134
135 int
136 snbep_unc_add_defaults(void *this, pfmlib_event_desc_t *e,
137                            unsigned int msk,
138                            uint64_t *umask,
139                            pfm_snbep_unc_reg_t *filters,
140                            unsigned int max_grpid)
141 {
142         const intel_x86_entry_t *pe = this_pe(this);
143         const intel_x86_entry_t *ent;
144         unsigned int i;
145         int j, k, added, skip;
146         int idx;
147
148         k = e->nattrs;
149         ent = pe+e->event;
150
151         for(i=0; msk; msk >>=1, i++) {
152
153                 if (!(msk & 0x1))
154                         continue;
155
156                 added = skip = 0;
157
158                 for (j = 0; j < e->npattrs; j++) {
159                         if (e->pattrs[j].ctrl != PFM_ATTR_CTRL_PMU)
160                                 continue;
161
162                         if (e->pattrs[j].type != PFM_ATTR_UMASK)
163                                 continue;
164
165                         idx = e->pattrs[j].idx;
166
167                         if (ent->umasks[idx].grpid != i)
168                                 continue;
169
170                         if (max_grpid != INTEL_X86_MAX_GRPID && i > max_grpid) {
171                                 skip = 1;
172                                 continue;
173                         }
174
175                         if (intel_x86_uflag(this, e->event, idx, INTEL_X86_GRP_DFL_NONE)) {
176                                 skip = 1;
177                                 continue;
178                         }
179
180                         /* umask is default for group */
181                         if (intel_x86_uflag(this, e->event, idx, INTEL_X86_DFL)) {
182                                 DPRINT("added default %s for group %d j=%d idx=%d ucode=0x%"PRIx64"\n",
183                                         ent->umasks[idx].uname,
184                                         i,      
185                                         j,
186                                         idx,
187                                         ent->umasks[idx].ucode);
188                                 /*
189                                  * default could be an alias, but
190                                  * ucode must reflect actual code
191                                  */
192                                 *umask |= ent->umasks[idx].ucode >> 8;
193
194                                 filters[0].val |= pe[e->event].umasks[idx].ufilters[0];
195                                 filters[1].val |= pe[e->event].umasks[idx].ufilters[1];
196
197                                 e->attrs[k].id = j; /* pattrs index */
198                                 e->attrs[k].ival = 0;
199                                 k++;
200
201                                 added++;
202                                 if (intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL))
203                                         goto done;
204
205                                 if (intel_x86_uflag(this, e->event, idx, INTEL_X86_EXCL_GRP_GT)) {
206                                         if (max_grpid != INTEL_X86_MAX_GRPID) {
207                                                 DPRINT("two max_grpid, old=%d new=%d\n", max_grpid, ent->umasks[idx].grpid);
208                                                 return PFM_ERR_UMASK;
209                                         }
210                                         max_grpid = ent->umasks[idx].grpid;
211                                 }
212                         }
213                 }
214                 if (!added && !skip) {
215                         DPRINT("no default found for event %s unit mask group %d (max_grpid=%d)\n", ent->name, i, max_grpid);
216                         return PFM_ERR_UMASK;
217                 }
218         }
219         DPRINT("max_grpid=%d nattrs=%d k=%d umask=0x%"PRIx64"\n", max_grpid, e->nattrs, k, *umask);
220 done:
221         e->nattrs = k;
222         return PFM_SUCCESS;
223 }
224
225
226 /*
227  * common encoding routine
228  */
229 int
230 pfm_intel_snbep_unc_get_encoding(void *this, pfmlib_event_desc_t *e)
231 {
232         const intel_x86_entry_t *pe = this_pe(this);
233         unsigned int grpmsk, ugrpmsk = 0;
234         unsigned int max_grpid = INTEL_X86_MAX_GRPID;
235         unsigned int last_grpid =  INTEL_X86_MAX_GRPID;
236         int umodmsk = 0, modmsk_r = 0;
237         int pcu_filt_band = -1;
238         pfm_snbep_unc_reg_t reg;
239         pfm_snbep_unc_reg_t filters[INTEL_X86_MAX_FILTERS];
240         pfm_snbep_unc_reg_t addr;
241         pfm_event_attr_info_t *a;
242         uint64_t val, umask1, umask2;
243         int k, ret;
244         int has_cbo_tid = 0;
245         unsigned int grpid;
246         int grpcounts[INTEL_X86_NUM_GRP];
247         int ncombo[INTEL_X86_NUM_GRP];
248         char umask_str[PFMLIB_EVT_MAX_NAME_LEN];
249
250         memset(grpcounts, 0, sizeof(grpcounts));
251         memset(ncombo, 0, sizeof(ncombo));
252         memset(filters, 0, sizeof(filters));
253
254         addr.val = 0;
255
256         pe = this_pe(this);
257
258         umask_str[0] = e->fstr[0] = '\0';
259
260         reg.val = val = pe[e->event].code;
261
262         /* take into account hardcoded umask */
263         umask1 = (val >> 8) & 0xff;
264         umask2 = umask1;
265
266         grpmsk = (1 << pe[e->event].ngrp)-1;
267
268         modmsk_r = pe[e->event].modmsk_req;
269
270         for(k=0; k < e->nattrs; k++) {
271                 a = attr(e, k);
272
273                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
274                         continue;
275
276                 if (a->type == PFM_ATTR_UMASK) {
277                         uint64_t um;
278
279                         grpid = pe[e->event].umasks[a->idx].grpid;
280
281                         /*
282                          * certain event groups are meant to be
283                          * exclusive, i.e., only unit masks of one group
284                          * can be used
285                          */
286                         if (last_grpid != INTEL_X86_MAX_GRPID && grpid != last_grpid
287                             && intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) {
288                                 DPRINT("exclusive unit mask group error\n");
289                                 return PFM_ERR_FEATCOMB;
290                         }
291
292                         /*
293                          * selecting certain umasks in a group may exclude any umasks
294                          * from any groups with a higher index
295                          *
296                          * enforcement requires looking at the grpid of all the umasks
297                          */
298                         if (intel_x86_uflag(this, e->event, a->idx, INTEL_X86_EXCL_GRP_GT))
299                                 max_grpid = grpid;
300
301                         /*
302                          * certain event groups are meant to be
303                          * exclusive, i.e., only unit masks of one group
304                          * can be used
305                          */
306                         if (last_grpid != INTEL_X86_MAX_GRPID && grpid != last_grpid
307                             && intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) {
308                                 DPRINT("exclusive unit mask group error\n");
309                                 return PFM_ERR_FEATCOMB;
310                         }
311                         /*
312                          * upper layer has removed duplicates
313                          * so if we come here more than once, it is for two
314                          * disinct umasks
315                          *
316                          * NCOMBO=no combination of unit masks within the same
317                          * umask group
318                          */
319                         ++grpcounts[grpid];
320
321                         /* mark that we have a umask with NCOMBO in this group */
322                         if (intel_x86_uflag(this, e->event, a->idx, INTEL_X86_NCOMBO))
323                                 ncombo[grpid] = 1;
324
325                         /*
326                          * if more than one umask in this group but one is marked
327                          * with ncombo, then fail. It is okay to combine umask within
328                          * a group as long as none is tagged with NCOMBO
329                          */
330                         if (grpcounts[grpid] > 1 && ncombo[grpid])  {
331                                 DPRINT("umask %s does not support unit mask combination within group %d\n", pe[e->event].umasks[a->idx].uname, grpid);
332                                 return PFM_ERR_FEATCOMB;
333                         }
334
335                         last_grpid = grpid;
336
337                         um = pe[e->event].umasks[a->idx].ucode;
338                         filters[0].val |= pe[e->event].umasks[a->idx].ufilters[0];
339                         filters[1].val |= pe[e->event].umasks[a->idx].ufilters[1];
340
341                         um >>= 8;
342                         umask2  |= um;
343
344                         ugrpmsk |= 1 << pe[e->event].umasks[a->idx].grpid;
345
346                         /* PCU occ event */
347                         if (is_occ_event(this, e->event)) {
348                                 reg.pcu.unc_occ = umask2 >> 6;
349                                 umask2 = 0;
350                         } else
351                                 reg.val |= umask2 << 8;
352
353                         evt_strcat(umask_str, ":%s", pe[e->event].umasks[a->idx].uname);
354
355                         modmsk_r |= pe[e->event].umasks[a->idx].umodmsk_req;
356
357                 } else if (a->type == PFM_ATTR_RAW_UMASK) {
358
359                         /* there can only be one RAW_UMASK per event */
360
361                         /* sanity check */
362                         if (a->idx & ~0xff) {
363                                 DPRINT("raw umask is 8-bit wide\n");
364                                 return PFM_ERR_ATTR;
365                         }
366                         /* override umask */
367                         umask2 = a->idx & 0xff;
368                         ugrpmsk = grpmsk;
369                 } else {
370                         uint64_t ival = e->attrs[k].ival;
371                         switch(a->idx) {
372                                 case SNBEP_UNC_ATTR_I: /* invert */
373                                         if (is_occ_event(this, e->event))
374                                                 reg.pcu.unc_occ_inv = !!ival;
375                                         else
376                                                 reg.com.unc_inv = !!ival;
377                                         umodmsk |= _SNBEP_UNC_ATTR_I;
378                                         break;
379                                 case SNBEP_UNC_ATTR_E: /* edge */
380                                         if (is_occ_event(this, e->event))
381                                                 reg.pcu.unc_occ_edge = !!ival;
382                                         else
383                                                 reg.com.unc_edge = !!ival;
384                                         umodmsk |= _SNBEP_UNC_ATTR_E;
385                                         break;
386                                 case SNBEP_UNC_ATTR_T8: /* counter-mask */
387                                         /* already forced, cannot overwrite */
388                                         if (ival > 255)
389                                                 return PFM_ERR_ATTR_VAL;
390                                         reg.com.unc_thres = ival;
391                                         umodmsk |= _SNBEP_UNC_ATTR_T8;
392                                         break;
393                                 case SNBEP_UNC_ATTR_T5: /* pcu counter-mask */
394                                         /* already forced, cannot overwrite */
395                                         if (ival > 31)
396                                                 return PFM_ERR_ATTR_VAL;
397                                         reg.pcu.unc_thres = ival;
398                                         umodmsk |= _SNBEP_UNC_ATTR_T5;
399                                         break;
400                                 case SNBEP_UNC_ATTR_TF: /* thread id */
401                                         if (ival > 1) {
402                                                 DPRINT("invalid thread id, must be < 1");
403                                                 return PFM_ERR_ATTR_VAL;
404                                         }
405                                         reg.cbo.unc_tid = 1;
406                                         has_cbo_tid = 1;
407                                         filters[0].cbo_filt.tid = ival;
408                                         umodmsk |= _SNBEP_UNC_ATTR_TF;
409                                         break;
410                                 case SNBEP_UNC_ATTR_CF: /* core id */
411                                         if (ival > 15)
412                                                 return PFM_ERR_ATTR_VAL;
413                                         reg.cbo.unc_tid = 1;
414                                         filters[0].cbo_filt.cid = ival;
415                                         has_cbo_tid = 1;
416                                         umodmsk |= _SNBEP_UNC_ATTR_CF;
417                                         break;
418                                 case SNBEP_UNC_ATTR_NF: /* node id filter0 */
419                                         if (ival > 255 || ival == 0) {
420                                                 DPRINT("invalid nf,  0 < nf < 256\n");
421                                                 return PFM_ERR_ATTR_VAL;
422                                         }
423                                         filters[0].cbo_filt.nid = ival;
424                                         umodmsk |= _SNBEP_UNC_ATTR_NF;
425                                         break;
426                                 case SNBEP_UNC_ATTR_NF1: /* node id filter1 */
427                                         if (ival > 255 || ival == 0) {
428                                                 DPRINT("invalid nf,  0 < nf < 256\n");
429                                                 return PFM_ERR_ATTR_VAL;
430                                         }
431                                         filters[1].ivbep_cbo_filt1.nid = ival;
432                                         umodmsk |= _SNBEP_UNC_ATTR_NF1;
433                                         break;
434                                 case SNBEP_UNC_ATTR_FF: /* freq band filter */
435                                         if (ival > 255)
436                                                 return PFM_ERR_ATTR_VAL;
437                                         pcu_filt_band = get_pcu_filt_band(this, reg);
438                                         filters[0].val = ival << (pcu_filt_band * 8);
439                                         umodmsk |= _SNBEP_UNC_ATTR_FF;
440                                         break;
441                                 case SNBEP_UNC_ATTR_A: /* addr filter */
442                                         if (ival & ~((1ULL << 40)-1)) {
443                                                 DPRINT("address filter 40bits max\n");
444                                                 return PFM_ERR_ATTR_VAL;
445                                         }
446                                         addr.ha_addr.lo_addr = ival; /* LSB 26 bits */
447                                         addr.ha_addr.hi_addr = (ival >> 26) & ((1ULL << 14)-1);
448                                         umodmsk |= _SNBEP_UNC_ATTR_A;
449                                         break;
450                                 case SNBEP_UNC_ATTR_ISOC: /* isoc filter */
451                                         filters[1].ivbep_cbo_filt1.isoc = !!ival;
452                                         break;
453                                 case SNBEP_UNC_ATTR_NC: /* nc filter */
454                                         filters[1].ivbep_cbo_filt1.nc = !!ival;
455                                         break;
456                         }
457                 }
458         }
459         /*
460          * check that there is at least of unit mask in each unit mask group
461          */
462         if (pe[e->event].numasks && (ugrpmsk != grpmsk || ugrpmsk == 0)) {
463                 uint64_t um = 0;
464                 ugrpmsk ^= grpmsk;
465                 ret = snbep_unc_add_defaults(this, e, ugrpmsk, &um, filters, max_grpid);
466                 if (ret != PFM_SUCCESS)
467                         return ret;
468                 umask2 |= um;
469         }
470
471         /*
472          * nf= is only required on some events in CBO
473          */
474         if (!(modmsk_r & _SNBEP_UNC_ATTR_NF) && (umodmsk & _SNBEP_UNC_ATTR_NF)) {
475                 DPRINT("using nf= on an umask which does not require it\n");
476                 return PFM_ERR_ATTR;
477         }
478         if (!(modmsk_r & _SNBEP_UNC_ATTR_NF1) && (umodmsk & _SNBEP_UNC_ATTR_NF1)) {
479                 DPRINT("using nf= on an umask which does not require it\n");
480                 return PFM_ERR_ATTR;
481         }
482
483         if (modmsk_r && !(umodmsk & modmsk_r)) {
484                 DPRINT("required modifiers missing: 0x%x\n", modmsk_r);
485                 return PFM_ERR_ATTR;
486         }
487
488         evt_strcat(e->fstr, "%s", pe[e->event].name);
489         pfmlib_sort_attr(e);
490
491         for(k = 0; k < e->nattrs; k++) {
492                 a = attr(e, k);
493                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
494                         continue;
495                 if (a->type == PFM_ATTR_UMASK)
496                         evt_strcat(e->fstr, ":%s", pe[e->event].umasks[a->idx].uname);
497                 else if (a->type == PFM_ATTR_RAW_UMASK)
498                         evt_strcat(e->fstr, ":0x%x", a->idx);
499         }
500         DPRINT("umask2=0x%"PRIx64" umask1=0x%"PRIx64"\n", umask2, umask1);
501         e->count = 0;
502         reg.val |= (umask1 | umask2)  << 8;
503
504         e->codes[e->count++] = reg.val;
505
506         /*
507          * handles C-box filter
508          */
509         if (filters[0].val || filters[1].val || has_cbo_tid)
510                 e->codes[e->count++] = filters[0].val;
511         if (filters[1].val)
512                 e->codes[e->count++] = filters[1].val;
513
514         /* HA address matcher */
515         if (addr.val)
516                 e->codes[e->count++] = addr.val;
517
518         for (k = 0; k < e->npattrs; k++) {
519                 int idx;
520
521                 if (e->pattrs[k].ctrl != PFM_ATTR_CTRL_PMU)
522                         continue;
523
524                 if (e->pattrs[k].type == PFM_ATTR_UMASK)
525                         continue;
526
527                 idx = e->pattrs[k].idx;
528                 switch(idx) {
529                 case SNBEP_UNC_ATTR_E:
530                         if (is_occ_event(this, e->event))
531                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_occ_edge);
532                         else
533                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_edge);
534                         break;
535                 case SNBEP_UNC_ATTR_I:
536                         if (is_occ_event(this, e->event))
537                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_occ_inv);
538                         else
539                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_inv);
540                         break;
541                 case SNBEP_UNC_ATTR_T8:
542                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.com.unc_thres);
543                         break;
544                 case SNBEP_UNC_ATTR_T5:
545                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.pcu.unc_thres);
546                         break;
547                 case SNBEP_UNC_ATTR_TF:
548                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, reg.cbo.unc_tid);
549                         break;
550                 case SNBEP_UNC_ATTR_CF:
551                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[0].cbo_filt.cid);
552                         break;
553                 case SNBEP_UNC_ATTR_FF:
554                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, (filters[0].val >> (pcu_filt_band*8)) & 0xff);
555                         break;
556                 case SNBEP_UNC_ATTR_ISOC:
557                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.isoc);
558                         break;
559                 case SNBEP_UNC_ATTR_NC:
560                         evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.nc);
561                         break;
562                 case SNBEP_UNC_ATTR_NF:
563                         if (modmsk_r & _SNBEP_UNC_ATTR_NF)
564                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[0].cbo_filt.nid);
565                         break;
566                 case SNBEP_UNC_ATTR_NF1:
567                         if (modmsk_r & _SNBEP_UNC_ATTR_NF1)
568                                 evt_strcat(e->fstr, ":%s=%lu", snbep_unc_mods[idx].name, filters[1].ivbep_cbo_filt1.nid);
569                         break;
570                 case SNBEP_UNC_ATTR_A:
571                         evt_strcat(e->fstr, ":%s=0x%lx", snbep_unc_mods[idx].name,
572                                    addr.ha_addr.hi_addr << 26 | addr.ha_addr.lo_addr);
573                         break;
574                 }
575         }
576         display_reg(this, e, reg);
577         return PFM_SUCCESS;
578 }
579
580 int
581 pfm_intel_snbep_unc_can_auto_encode(void *this, int pidx, int uidx)
582 {
583         if (intel_x86_eflag(this, pidx, INTEL_X86_NO_AUTOENCODE))
584                 return 0;
585
586         return !intel_x86_uflag(this, pidx, uidx, INTEL_X86_NO_AUTOENCODE);
587 }
588
589 int
590 pfm_intel_snbep_unc_get_event_attr_info(void *this, int pidx, int attr_idx, pfm_event_attr_info_t *info)
591 {
592         const intel_x86_entry_t *pe = this_pe(this);
593         const pfmlib_attr_desc_t *atdesc = this_atdesc(this);
594         int numasks, idx;
595
596         numasks = intel_x86_num_umasks(this, pidx);
597         if (attr_idx < numasks) {
598                 idx = intel_x86_attr2umask(this, pidx, attr_idx);
599                 info->name = pe[pidx].umasks[idx].uname;
600                 info->desc = pe[pidx].umasks[idx].udesc;
601                 info->equiv= pe[pidx].umasks[idx].uequiv;
602
603                 info->code = pe[pidx].umasks[idx].ucode;
604
605                 if (!intel_x86_uflag(this, pidx, idx, INTEL_X86_CODE_OVERRIDE))
606                         info->code >>= 8;
607
608                 if (info->code == 0)
609                         info->code = pe[pidx].umasks[idx].ufilters[0];
610
611                 info->type = PFM_ATTR_UMASK;
612                 info->is_dfl = intel_x86_uflag(this, pidx, idx, INTEL_X86_DFL);
613                 info->is_precise = intel_x86_uflag(this, pidx, idx, INTEL_X86_PEBS);
614         } else {
615                 idx = intel_x86_attr2mod(this, pidx, attr_idx);
616                 info->name = atdesc[idx].name;
617                 info->desc = atdesc[idx].desc;
618                 info->type = atdesc[idx].type;
619                 info->equiv= NULL;
620                 info->code = idx;
621                 info->is_dfl = 0;
622                 info->is_precise = 0;
623         }
624
625         info->ctrl = PFM_ATTR_CTRL_PMU;
626         info->idx = idx; /* namespace specific index */
627         info->dfl_val64 = 0;
628
629         return PFM_SUCCESS;
630 }