Blame src/libpfm-3.y/lib/pfmlib_gen_ia32.c

Packit 577717
/*
Packit 577717
 * pfmlib_gen_ia32.c : Intel architectural PMU v1, v2, v3
Packit 577717
 *
Packit 577717
 * The file provides support for the Intel architectural PMU v1 and v2.
Packit 577717
 *
Packit 577717
 * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
Packit 577717
 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
Packit 577717
 *
Packit 577717
 *
Packit 577717
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit 577717
 * of this software and associated documentation files (the "Software"), to deal
Packit 577717
 * in the Software without restriction, including without limitation the rights
Packit 577717
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 577717
 * of the Software, and to permit persons to whom the Software is furnished to do so,
Packit 577717
 * subject to the following conditions:
Packit 577717
 *
Packit 577717
 * The above copyright notice and this permission notice shall be included in all
Packit 577717
 * copies or substantial portions of the Software.
Packit 577717
 *
Packit 577717
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
Packit 577717
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
Packit 577717
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 577717
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Packit 577717
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
Packit 577717
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 577717
 *
Packit 577717
 *
Packit 577717
 * This file implements supports for the IA-32 architectural PMU as specified
Packit 577717
 * in the following document:
Packit 577717
 * 	"IA-32 Intel Architecture Software Developer's Manual - Volume 3B: System
Packit 577717
 * 	Programming Guide"
Packit 577717
 */
Packit 577717
#include <sys/types.h>
Packit 577717
#include <ctype.h>
Packit 577717
#include <string.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <stdio.h>
Packit 577717
Packit 577717
/* public headers */
Packit 577717
#include <perfmon/pfmlib_gen_ia32.h>
Packit 577717
Packit 577717
/* private headers */
Packit 577717
#include "pfmlib_priv.h"			/* library private */
Packit 577717
#include "pfmlib_gen_ia32_priv.h"		/* architecture private */
Packit 577717
Packit 577717
#include "gen_ia32_events.h"			/* architected event table */
Packit 577717
Packit 577717
/* let's define some handy shortcuts! */
Packit 577717
#define sel_event_select perfevtsel.sel_event_select
Packit 577717
#define sel_unit_mask	 perfevtsel.sel_unit_mask
Packit 577717
#define sel_usr		 perfevtsel.sel_usr
Packit 577717
#define sel_os		 perfevtsel.sel_os
Packit 577717
#define sel_edge	 perfevtsel.sel_edge
Packit 577717
#define sel_pc		 perfevtsel.sel_pc
Packit 577717
#define sel_int		 perfevtsel.sel_int
Packit 577717
#define sel_any		 perfevtsel.sel_any
Packit 577717
#define sel_en		 perfevtsel.sel_en
Packit 577717
#define sel_inv		 perfevtsel.sel_inv
Packit 577717
#define sel_cnt_mask	 perfevtsel.sel_cnt_mask
Packit 577717
Packit 577717
pfm_pmu_support_t *gen_support;
Packit 577717
Packit 577717
/*
Packit 577717
 * Description of the PMC/PMD register mappings use by
Packit 577717
 * this module (as reported in pfmlib_reg_t.reg_num)
Packit 577717
 *
Packit 577717
 * For V1 (up to 16 generic counters 0-15):
Packit 577717
 *
Packit 577717
 * 	0 -> PMC0 -> PERFEVTSEL0 -> MSR @ 0x186
Packit 577717
 * 	1 -> PMC1 -> PERFEVTSEL1 -> MSR @ 0x187
Packit 577717
 * 	...
Packit 577717
 * 	n -> PMCn -> PERFEVTSELn -> MSR @ 0x186+n
Packit 577717
 *
Packit 577717
 * 	0 -> PMD0 -> IA32_PMC0   -> MSR @ 0xc1
Packit 577717
 * 	1 -> PMD1 -> IA32_PMC1   -> MSR @ 0xc2
Packit 577717
 * 	...
Packit 577717
 * 	n -> PMDn -> IA32_PMCn   -> MSR @ 0xc1+n
Packit 577717
 *
Packit 577717
 * For V2 (up to 16 generic and 16 fixed counters):
Packit 577717
 *
Packit 577717
 * 	0 -> PMC0 -> PERFEVTSEL0 -> MSR @ 0x186
Packit 577717
 * 	1 -> PMC1 -> PERFEVTSEL1 -> MSR @ 0x187
Packit 577717
 * 	...
Packit 577717
 * 	15 -> PMC15 -> PERFEVTSEL15 -> MSR @ 0x186+15
Packit 577717
 *
Packit 577717
 * 	16 -> PMC16 -> IA32_FIXED_CTR_CTRL -> MSR @ 0x38d
Packit 577717
 *
Packit 577717
 * 	0 -> PMD0 -> IA32_PMC0   -> MSR @ 0xc1
Packit 577717
 * 	1 -> PMD1 -> IA32_PMC1   -> MSR @ 0xc2
Packit 577717
 * 	...
Packit 577717
 * 	15 -> PMD15 -> IA32_PMC15   -> MSR @ 0xc1+15
Packit 577717
 *
Packit 577717
 * 	16 -> PMD16 -> IA32_FIXED_CTR0 -> MSR @ 0x309
Packit 577717
 * 	17 -> PMD17 -> IA32_FIXED_CTR1 -> MSR @ 0x30a
Packit 577717
 * 	...
Packit 577717
 * 	n -> PMDn -> IA32_FIXED_CTRn -> MSR @ 0x309+n
Packit 577717
 */
Packit 577717
#define GEN_IA32_SEL_BASE	  0x186
Packit 577717
#define GEN_IA32_CTR_BASE	  0xc1
Packit 577717
#define GEN_IA32_FIXED_CTR_BASE	  0x309
Packit 577717
Packit 577717
#define FIXED_PMD_BASE		16
Packit 577717
Packit 577717
#define PFMLIB_GEN_IA32_ALL_FLAGS \
Packit 577717
	(PFM_GEN_IA32_SEL_INV|PFM_GEN_IA32_SEL_EDGE|PFM_GEN_IA32_SEL_ANYTHR)
Packit 577717
Packit 577717
static char * pfm_gen_ia32_get_event_name(unsigned int i);
Packit 577717
Packit 577717
static pme_gen_ia32_entry_t *gen_ia32_pe;
Packit 577717
Packit 577717
static int gen_ia32_cycle_event, gen_ia32_inst_retired_event;
Packit 577717
static unsigned int num_fixed_cnt, num_gen_cnt, pmu_version;
Packit 577717
Packit 577717
#ifdef __i386__
Packit 577717
static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
Packit 577717
			 unsigned int *ecx, unsigned int *edx)
Packit 577717
{
Packit 577717
	/*
Packit 577717
	 * because ebx is used in Pic mode, we need to save/restore because
Packit 577717
	 * cpuid clobbers it. I could not figure out a way to get ebx out in
Packit 577717
	 * one cpuid instruction. To extract ebx, we need to  move it to another
Packit 577717
	 * register (here eax)
Packit 577717
	 */
Packit 577717
	__asm__("pushl %%ebx;cpuid; popl %%ebx"
Packit 577717
			:"=a" (*eax)
Packit 577717
			: "a" (op)
Packit 577717
			: "ecx", "edx");
Packit 577717
Packit 577717
	__asm__("pushl %%ebx;cpuid; movl %%ebx, %%eax;popl %%ebx"
Packit 577717
			:"=a" (*ebx)
Packit 577717
			: "a" (op)
Packit 577717
			: "ecx", "edx");
Packit 577717
}
Packit 577717
#else
Packit 577717
static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
Packit 577717
			 unsigned int *ecx, unsigned int *edx)
Packit 577717
{
Packit 577717
        __asm__("cpuid"
Packit 577717
                        : "=a" (*eax),
Packit 577717
                        "=b" (*ebx),
Packit 577717
                        "=c" (*ecx),
Packit 577717
                        "=d" (*edx)
Packit 577717
                        : "0" (op), "c"(0));
Packit 577717
}
Packit 577717
#endif
Packit 577717
Packit 577717
static pfmlib_regmask_t gen_ia32_impl_pmcs, gen_ia32_impl_pmds;
Packit 577717
Packit 577717
/*
Packit 577717
 * create architected event table
Packit 577717
 */
Packit 577717
static int
Packit 577717
create_arch_event_table(unsigned int mask)
Packit 577717
{
Packit 577717
	pme_gen_ia32_entry_t *pe;
Packit 577717
	unsigned int i, num_events = 0;
Packit 577717
	unsigned int m;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * first pass: count the number of supported events
Packit 577717
	 */
Packit 577717
	m = mask;
Packit 577717
	for(i=0; i < 7; i++, m>>=1) {
Packit 577717
		if ((m & 0x1)  == 0)
Packit 577717
			num_events++;
Packit 577717
	}
Packit 577717
	gen_ia32_support.pme_count = num_events;
Packit 577717
Packit 577717
	gen_ia32_pe = calloc(num_events, sizeof(pme_gen_ia32_entry_t));
Packit 577717
	if (gen_ia32_pe == NULL)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * second pass: populate the table
Packit 577717
	 */
Packit 577717
	gen_ia32_cycle_event = gen_ia32_inst_retired_event = -1;
Packit 577717
	m = mask;
Packit 577717
	for(i=0, pe = gen_ia32_pe; i < 7; i++, m>>=1) {
Packit 577717
		if ((m & 0x1)  == 0) {
Packit 577717
			*pe = gen_ia32_all_pe[i];
Packit 577717
			/*
Packit 577717
			 * setup default event: cycles and inst_retired
Packit 577717
			 */
Packit 577717
			if (i == PME_GEN_IA32_UNHALTED_CORE_CYCLES)
Packit 577717
				gen_ia32_cycle_event = pe - gen_ia32_pe;
Packit 577717
			if (i == PME_GEN_IA32_INSTRUCTIONS_RETIRED)
Packit 577717
				gen_ia32_inst_retired_event = pe - gen_ia32_pe;
Packit 577717
			pe++;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
check_arch_pmu(int family)
Packit 577717
{
Packit 577717
	union {
Packit 577717
		unsigned int val;
Packit 577717
		pmu_eax_t eax;
Packit 577717
		pmu_edx_t edx;
Packit 577717
	} eax, ecx, edx, ebx;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check family number to reject for processors
Packit 577717
	 * older than Pentium (family=5). Those processors
Packit 577717
	 * did not have the CPUID instruction
Packit 577717
	 */
Packit 577717
	if (family < 5)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * check if CPU supports 0xa function of CPUID
Packit 577717
	 * 0xa started with Core Duo. Needed to detect if
Packit 577717
	 * architected PMU is present
Packit 577717
	 */
Packit 577717
	cpuid(0x0, &eax.val, &ebx.val, &ecx.val, &edx.val);
Packit 577717
	if (eax.val < 0xa)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * extract architected PMU information
Packit 577717
	 */
Packit 577717
	cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * version must be greater than zero
Packit 577717
	 */
Packit 577717
	return eax.eax.version < 1 ? PFMLIB_ERR_NOTSUPP : PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_detect(void)
Packit 577717
{
Packit 577717
	int ret, family;
Packit 577717
	char buffer[128];
Packit 577717
Packit 577717
	ret = __pfm_getcpuinfo_attr("vendor_id", buffer, sizeof(buffer));
Packit 577717
	if (ret == -1)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	if (strcmp(buffer, "GenuineIntel"))
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	ret = __pfm_getcpuinfo_attr("cpu family", buffer, sizeof(buffer));
Packit 577717
	if (ret == -1)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	family = atoi(buffer);
Packit 577717
Packit 577717
	return check_arch_pmu(family);
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_init(void)
Packit 577717
{
Packit 577717
	union {
Packit 577717
		unsigned int val;
Packit 577717
		pmu_eax_t eax;
Packit 577717
		pmu_edx_t edx;
Packit 577717
	} eax, ecx, edx, ebx;
Packit 577717
	unsigned int num_cnt, i;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * extract architected PMU information
Packit 577717
	 */
Packit 577717
	if (forced_pmu == PFMLIB_NO_PMU) {
Packit 577717
		cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
Packit 577717
	} else {
Packit 577717
		/*
Packit 577717
		 * when forced, simulate v2
Packit 577717
		 * with 2 generic and 3 fixed counters
Packit 577717
		 */
Packit 577717
		eax.eax.version = 3;
Packit 577717
		eax.eax.num_cnt = 2;
Packit 577717
		eax.eax.cnt_width = 40;
Packit 577717
		eax.eax.ebx_length = 0; /* unused */
Packit 577717
		ebx.val = 0;
Packit 577717
		edx.edx.num_cnt = 3;
Packit 577717
		edx.edx.cnt_width = 40;
Packit 577717
	}
Packit 577717
Packit 577717
	num_cnt = eax.eax.num_cnt;
Packit 577717
	pmu_version = eax.eax.version;
Packit 577717
Packit 577717
	/* 
Packit 577717
	 * populate impl_pm* bitmasks for generic counters
Packit 577717
	 */
Packit 577717
	for(i=0; i < num_cnt; i++) {
Packit 577717
		pfm_regmask_set(&gen_ia32_impl_pmcs, i);
Packit 577717
		pfm_regmask_set(&gen_ia32_impl_pmds, i);
Packit 577717
	}
Packit 577717
Packit 577717
	/* check for fixed counters */
Packit 577717
	if (pmu_version >= 2) {
Packit 577717
		/*
Packit 577717
		 * As described in IA-32 Developer's manual vol 3b
Packit 577717
		 * in section 18.12.2.1, early processors supporting
Packit 577717
		 * V2 may report invalid information concerning the fixed
Packit 577717
		 * counters. So we compensate for this here by forcing
Packit 577717
		 * num_cnt to 3.
Packit 577717
		 */
Packit 577717
		if (edx.edx.num_cnt == 0)
Packit 577717
			edx.edx.num_cnt = 3;
Packit 577717
Packit 577717
		for(i=0; i < edx.edx.num_cnt; i++)
Packit 577717
			pfm_regmask_set(&gen_ia32_impl_pmds, FIXED_PMD_BASE+i);
Packit 577717
		if (i)
Packit 577717
			pfm_regmask_set(&gen_ia32_impl_pmcs, 16);
Packit 577717
Packit 577717
	}
Packit 577717
Packit 577717
	num_gen_cnt = eax.eax.num_cnt;
Packit 577717
	num_fixed_cnt = edx.edx.num_cnt;
Packit 577717
Packit 577717
	gen_ia32_support.pmc_count = num_gen_cnt + (num_fixed_cnt > 0);
Packit 577717
	gen_ia32_support.pmd_count = num_gen_cnt + num_fixed_cnt;
Packit 577717
	gen_ia32_support.num_cnt   = num_gen_cnt + num_fixed_cnt;
Packit 577717
Packit 577717
	__pfm_vbprintf("Intel architected PMU: version=%d num_gen=%u num_fixed=%u pmc=%u pmd=%d\n",
Packit 577717
		pmu_version,
Packit 577717
		num_gen_cnt,num_fixed_cnt,
Packit 577717
		gen_ia32_support.pmc_count,
Packit 577717
		gen_ia32_support.pmd_count);
Packit 577717
Packit 577717
	ret = create_arch_event_table(ebx.val);
Packit 577717
	if (ret != PFMLIB_SUCCESS)
Packit 577717
		return ret;
Packit 577717
Packit 577717
	gen_support = &gen_ia32_support;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_dispatch_counters_v1(pfmlib_input_param_t *inp, pfmlib_gen_ia32_input_param_t *mod_in, pfmlib_output_param_t *outp)
Packit 577717
{
Packit 577717
	pfmlib_gen_ia32_input_param_t *param = mod_in;
Packit 577717
	pfmlib_gen_ia32_counter_t *cntrs;
Packit 577717
	pfm_gen_ia32_sel_reg_t reg;
Packit 577717
	pfmlib_event_t *e;
Packit 577717
	pfmlib_reg_t *pc, *pd;
Packit 577717
	pfmlib_regmask_t *r_pmcs;
Packit 577717
	unsigned long plm;
Packit 577717
	unsigned int i, j, cnt, k, ucode, val;
Packit 577717
	unsigned int assign[PMU_GEN_IA32_MAX_COUNTERS];
Packit 577717
Packit 577717
	e      = inp->pfp_events;
Packit 577717
	pc     = outp->pfp_pmcs;
Packit 577717
	pd     = outp->pfp_pmds;
Packit 577717
	cnt    = inp->pfp_event_count;
Packit 577717
	r_pmcs = &inp->pfp_unavail_pmcs;
Packit 577717
	cntrs  = param ? param->pfp_gen_ia32_counters : NULL;
Packit 577717
Packit 577717
	if (PFMLIB_DEBUG()) {
Packit 577717
		for (j=0; j < cnt; j++) {
Packit 577717
			DPRINT("ev[%d]=%s\n", j, gen_ia32_pe[e[j].event].pme_name);
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if (cnt > gen_support->pmd_count)
Packit 577717
		return PFMLIB_ERR_TOOMANY;
Packit 577717
Packit 577717
	for(i=0, j=0; j < cnt; j++) {
Packit 577717
		if (e[j].plm & (PFM_PLM1|PFM_PLM2)) {
Packit 577717
			DPRINT("event=%d invalid plm=%d\n", e[j].event, e[j].plm);
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
		}
Packit 577717
Packit 577717
		if (e[j].flags & ~PFMLIB_GEN_IA32_ALL_FLAGS) {
Packit 577717
			DPRINT("event=%d invalid flags=0x%lx\n", e[j].event, e[j].flags);
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
		}
Packit 577717
Packit 577717
		if (cntrs && pmu_version != 3 && (cntrs[j].flags & PFM_GEN_IA32_SEL_ANYTHR)) {
Packit 577717
			DPRINT("event=%d anythread requires architectural perfmon v3", e[j].event);
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
		}
Packit 577717
		/*
Packit 577717
		 * exclude restricted registers from assignment
Packit 577717
		 */
Packit 577717
		while(i < gen_support->pmc_count && pfm_regmask_isset(r_pmcs, i)) i++;
Packit 577717
Packit 577717
		if (i == gen_support->pmc_count)
Packit 577717
			return PFMLIB_ERR_TOOMANY;
Packit 577717
Packit 577717
		/*
Packit 577717
		 * events can be assigned to any counter
Packit 577717
		 */
Packit 577717
		assign[j] = i++;
Packit 577717
	}
Packit 577717
Packit 577717
	for (j=0; j < cnt ; j++ ) {
Packit 577717
		reg.val = 0; /* assume reserved bits are zerooed */
Packit 577717
Packit 577717
		/* if plm is 0, then assume not specified per-event and use default */
Packit 577717
		plm = e[j].plm ? e[j].plm : inp->pfp_dfl_plm;
Packit 577717
Packit 577717
		val = gen_ia32_pe[e[j].event].pme_code;
Packit 577717
Packit 577717
		reg.sel_event_select = val & 0xff;
Packit 577717
Packit 577717
		ucode = (val >> 8) & 0xff;
Packit 577717
Packit 577717
		for(k=0; k < e[j].num_masks; k++)
Packit 577717
			ucode |= gen_ia32_pe[e[j].event].pme_umasks[e[j].unit_masks[k]].pme_ucode;
Packit 577717
Packit 577717
		val |= ucode << 8;
Packit 577717
Packit 577717
		reg.sel_unit_mask  = ucode; /* use 8 least significant bits */
Packit 577717
		reg.sel_usr        = plm & PFM_PLM3 ? 1 : 0;
Packit 577717
		reg.sel_os         = plm & PFM_PLM0 ? 1 : 0;
Packit 577717
		reg.sel_en         = 1; /* force enable bit to 1 */
Packit 577717
		reg.sel_int        = 1; /* force APIC int to 1 */
Packit 577717
Packit 577717
		reg.sel_cnt_mask = val >>24;
Packit 577717
		reg.sel_inv = val >> 23;
Packit 577717
		reg.sel_any = val >> 21;;
Packit 577717
		reg.sel_edge = val >> 18;
Packit 577717
Packit 577717
		if (cntrs) {
Packit 577717
			if (!reg.sel_cnt_mask) {
Packit 577717
				/*
Packit 577717
			 	 * counter mask is 8-bit wide, do not silently
Packit 577717
			 	 * wrap-around
Packit 577717
			 	 */
Packit 577717
				if (cntrs[i].cnt_mask > 255)
Packit 577717
					return PFMLIB_ERR_INVAL;
Packit 577717
				reg.sel_cnt_mask = cntrs[j].cnt_mask;
Packit 577717
			}
Packit 577717
Packit 577717
			if (!reg.sel_edge)
Packit 577717
				reg.sel_edge = cntrs[j].flags & PFM_GEN_IA32_SEL_EDGE ? 1 : 0;
Packit 577717
			if (!reg.sel_inv)
Packit 577717
				reg.sel_inv = cntrs[j].flags & PFM_GEN_IA32_SEL_INV ? 1 : 0;
Packit 577717
		}
Packit 577717
Packit 577717
		pc[j].reg_num     = assign[j];
Packit 577717
		pc[j].reg_addr    = GEN_IA32_SEL_BASE+assign[j];
Packit 577717
		pc[j].reg_value   = reg.val;
Packit 577717
Packit 577717
		pd[j].reg_num  = assign[j];
Packit 577717
		pd[j].reg_addr = GEN_IA32_CTR_BASE+assign[j];
Packit 577717
Packit 577717
		__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%llx event_sel=0x%x umask=0x%x os=%d usr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d] %s\n",
Packit 577717
			assign[j],
Packit 577717
			assign[j],
Packit 577717
			reg.val,
Packit 577717
			reg.sel_event_select,
Packit 577717
			reg.sel_unit_mask,
Packit 577717
			reg.sel_os,
Packit 577717
			reg.sel_usr,
Packit 577717
			reg.sel_en,
Packit 577717
			reg.sel_int,
Packit 577717
			reg.sel_inv,
Packit 577717
			reg.sel_edge,
Packit 577717
			reg.sel_cnt_mask,
Packit 577717
			gen_ia32_pe[e[j].event].pme_name);
Packit 577717
Packit 577717
		__pfm_vbprintf("[PMC%u(pmd%u)]\n", pd[j].reg_num, pd[j].reg_num);
Packit 577717
	}
Packit 577717
	/* number of evtsel registers programmed */
Packit 577717
	outp->pfp_pmc_count = cnt;
Packit 577717
	outp->pfp_pmd_count = cnt;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static const char *fixed_event_names[]={ "INSTRUCTIONS_RETIRED", "UNHALTED_CORE_CYCLES ", "UNHALTED_REFERENCE_CYCLES " };
Packit 577717
#define MAX_EVENT_NAMES (sizeof(fixed_event_names)/sizeof(char *))
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_dispatch_counters_v23(pfmlib_input_param_t *inp, pfmlib_gen_ia32_input_param_t *param, pfmlib_output_param_t *outp)
Packit 577717
{
Packit 577717
#define HAS_OPTIONS(x)	(cntrs && (cntrs[i].flags || cntrs[i].cnt_mask))
Packit 577717
#define is_fixed_pmc(a) (a > 15)
Packit 577717
Packit 577717
	pfmlib_gen_ia32_counter_t *cntrs;
Packit 577717
	pfm_gen_ia32_sel_reg_t reg;
Packit 577717
	pfmlib_event_t *e;
Packit 577717
	pfmlib_reg_t *pc, *pd;
Packit 577717
	pfmlib_regmask_t *r_pmcs;
Packit 577717
	uint64_t val;
Packit 577717
	unsigned long plm;
Packit 577717
	unsigned int fixed_ctr_mask;
Packit 577717
	unsigned int npc = 0;
Packit 577717
	unsigned int i, j, n, k, ucode;
Packit 577717
	unsigned int assign[PMU_GEN_IA32_MAX_COUNTERS];
Packit 577717
	unsigned int next_gen, last_gen;
Packit 577717
Packit 577717
	e      = inp->pfp_events;
Packit 577717
	pc     = outp->pfp_pmcs;
Packit 577717
	pd     = outp->pfp_pmds;
Packit 577717
	n      = inp->pfp_event_count;
Packit 577717
	r_pmcs = &inp->pfp_unavail_pmcs;
Packit 577717
	cntrs  = param ? param->pfp_gen_ia32_counters : NULL;
Packit 577717
Packit 577717
	if (n > gen_support->pmd_count)
Packit 577717
		return PFMLIB_ERR_TOOMANY;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * initilize to empty
Packit 577717
	 */
Packit 577717
	for(i=0; i < n; i++)
Packit 577717
		assign[i] = -1;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * error checking
Packit 577717
	 */
Packit 577717
	for(j=0; j < n; j++) {
Packit 577717
		/*
Packit 577717
		 * only supports two priv levels for perf counters
Packit 577717
		 */
Packit 577717
		if (e[j].plm & (PFM_PLM1|PFM_PLM2))
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
		/*
Packit 577717
		 * check for valid flags
Packit 577717
		 */
Packit 577717
		if (cntrs && cntrs[j].flags & ~PFMLIB_GEN_IA32_ALL_FLAGS)
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
		if (cntrs && pmu_version != 3 && (cntrs[j].flags & PFM_GEN_IA32_SEL_ANYTHR)) {
Packit 577717
			DPRINT("event=%d anythread requires architectural perfmon v3", e[j].event);
Packit 577717
			return PFMLIB_ERR_INVAL;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	next_gen = 0; /* first generic counter */
Packit 577717
	last_gen = num_gen_cnt - 1; /* last generic counter */
Packit 577717
Packit 577717
	fixed_ctr_mask = (1 << num_fixed_cnt) - 1;
Packit 577717
	/*
Packit 577717
	 * first constraint: fixed counters (try using them first)
Packit 577717
	 */
Packit 577717
	if (fixed_ctr_mask) {
Packit 577717
		for(i=0; i < n; i++) {
Packit 577717
			/* fixed counters do not support event options (filters) */
Packit 577717
			if (HAS_OPTIONS(i)) {
Packit 577717
				if (pmu_version != 3)
Packit 577717
					continue;
Packit 577717
				if (cntrs[i].flags != PFM_GEN_IA32_SEL_ANYTHR)
Packit 577717
					continue;
Packit 577717
				/* ok for ANYTHR */
Packit 577717
			}
Packit 577717
			for(j=0; j < num_fixed_cnt; j++) {
Packit 577717
				if ((fixed_ctr_mask & (1<
Packit 577717
					assign[i] = FIXED_PMD_BASE+j;
Packit 577717
					fixed_ctr_mask &= ~(1<
Packit 577717
					break;
Packit 577717
				}
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * assign what is left
Packit 577717
	 */
Packit 577717
	for(i=0; i < n; i++) {
Packit 577717
		if (assign[i] == -1) {
Packit 577717
			for(; next_gen <= last_gen; next_gen++) {
Packit 577717
				if (!pfm_regmask_isset(r_pmcs, next_gen))
Packit 577717
					break;
Packit 577717
			}
Packit 577717
			if (next_gen <= last_gen)
Packit 577717
				assign[i] = next_gen++;
Packit 577717
			else
Packit 577717
				return PFMLIB_ERR_NOASSIGN;
Packit 577717
		}
Packit 577717
	}
Packit 577717
	j = 0;
Packit 577717
Packit 577717
	/* setup fixed counters */
Packit 577717
	reg.val = 0;
Packit 577717
	k = 0;
Packit 577717
	for (i=0; i < n ; i++ ) {
Packit 577717
		if (!is_fixed_pmc(assign[i]))
Packit 577717
			continue;
Packit 577717
		val = 0;
Packit 577717
		/* if plm is 0, then assume not specified per-event and use default */
Packit 577717
		plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
Packit 577717
		if (plm & PFM_PLM0)
Packit 577717
			val |= 1ULL;
Packit 577717
		if (plm & PFM_PLM3)
Packit 577717
			val |= 2ULL;
Packit 577717
Packit 577717
		/* only possible for v3 */
Packit 577717
		if (cntrs && cntrs[i].flags & PFM_GEN_IA32_SEL_ANYTHR)
Packit 577717
			val |= 4ULL;
Packit 577717
Packit 577717
		val |= 1ULL << 3;	 /* force APIC int (kernel may force it anyway) */
Packit 577717
Packit 577717
		reg.val |= val << ((assign[i]-FIXED_PMD_BASE)<<2);
Packit 577717
Packit 577717
		/* setup pd array */
Packit 577717
		pd[i].reg_num = assign[i];
Packit 577717
		pd[i].reg_addr = GEN_IA32_FIXED_CTR_BASE+assign[i]-FIXED_PMD_BASE;
Packit 577717
	}
Packit 577717
Packit 577717
	if (reg.val) {
Packit 577717
		pc[npc].reg_num   = 16;
Packit 577717
		pc[npc].reg_value = reg.val;
Packit 577717
		pc[npc].reg_addr  = 0x38D;
Packit 577717
Packit 577717
		__pfm_vbprintf("[FIXED_CTRL(pmc%u)=0x%"PRIx64,
Packit 577717
				pc[npc].reg_num,
Packit 577717
				reg.val);
Packit 577717
Packit 577717
		for(i=0; i < num_fixed_cnt; i++) {
Packit 577717
			if (pmu_version != 3) 
Packit 577717
				__pfm_vbprintf(" pmi%d=1 en%d=0x%"PRIx64,
Packit 577717
					i, i,
Packit 577717
					(reg.val >> (i*4)) & 0x3ULL);
Packit 577717
			else
Packit 577717
				__pfm_vbprintf(" pmi%d=1 en%d=0x%"PRIx64 " any%d=%"PRId64,
Packit 577717
					i, i,
Packit 577717
					(reg.val >> (i*4)) & 0x3ULL,
Packit 577717
					i,
Packit 577717
					!!((reg.val >> (i*4)) & 0x4ULL));
Packit 577717
		}
Packit 577717
Packit 577717
		__pfm_vbprintf("] ");
Packit 577717
		for(i=0; i < num_fixed_cnt; i++) {
Packit 577717
			if ((fixed_ctr_mask & (0x1 << i)) == 0) {
Packit 577717
				if (i < MAX_EVENT_NAMES)
Packit 577717
					__pfm_vbprintf("%s ", fixed_event_names[i]);
Packit 577717
				else
Packit 577717
					__pfm_vbprintf("??? ");
Packit 577717
			}
Packit 577717
		}
Packit 577717
		__pfm_vbprintf("\n");
Packit 577717
Packit 577717
		npc++;
Packit 577717
Packit 577717
		for (i=0; i < n ; i++ ) {
Packit 577717
			if (!is_fixed_pmc(assign[i]))
Packit 577717
				continue;
Packit 577717
			__pfm_vbprintf("[FIXED_CTR%u(pmd%u)]\n", pd[i].reg_num, pd[i].reg_num);
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	for (i=0; i < n ; i++ ) {
Packit 577717
		/* skip fixed counters */
Packit 577717
		if (is_fixed_pmc(assign[i]))
Packit 577717
			continue;
Packit 577717
Packit 577717
		reg.val = 0; /* assume reserved bits are zerooed */
Packit 577717
Packit 577717
		/* if plm is 0, then assume not specified per-event and use default */
Packit 577717
		plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
Packit 577717
Packit 577717
		val = gen_ia32_pe[e[i].event].pme_code;
Packit 577717
Packit 577717
		reg.sel_event_select = val & 0xff;
Packit 577717
Packit 577717
		ucode = (val >> 8) & 0xff;
Packit 577717
Packit 577717
		for(k=0; k < e[i].num_masks; k++)
Packit 577717
			ucode |= gen_ia32_pe[e[i].event].pme_umasks[e[i].unit_masks[k]].pme_ucode;
Packit 577717
Packit 577717
		val |= ucode << 8;
Packit 577717
Packit 577717
		reg.sel_unit_mask  = ucode;
Packit 577717
		reg.sel_usr        = plm & PFM_PLM3 ? 1 : 0;
Packit 577717
		reg.sel_os         = plm & PFM_PLM0 ? 1 : 0;
Packit 577717
		reg.sel_en         = 1; /* force enable bit to 1 */
Packit 577717
		reg.sel_int        = 1; /* force APIC int to 1 */
Packit 577717
Packit 577717
		reg.sel_cnt_mask = val >>24;
Packit 577717
		reg.sel_inv = val >> 23;
Packit 577717
		reg.sel_any = val >> 21;;
Packit 577717
		reg.sel_edge = val >> 18;
Packit 577717
Packit 577717
		if (cntrs) {
Packit 577717
			if (!reg.sel_cnt_mask) {
Packit 577717
				/*
Packit 577717
			 	 * counter mask is 8-bit wide, do not silently
Packit 577717
			 	 * wrap-around
Packit 577717
			 	 */
Packit 577717
				if (cntrs[i].cnt_mask > 255)
Packit 577717
					return PFMLIB_ERR_INVAL;
Packit 577717
				reg.sel_cnt_mask = cntrs[i].cnt_mask;
Packit 577717
			}
Packit 577717
			if (!reg.sel_edge)
Packit 577717
				reg.sel_edge = cntrs[i].flags & PFM_GEN_IA32_SEL_EDGE ? 1 : 0;
Packit 577717
			if (!reg.sel_inv)
Packit 577717
				reg.sel_inv = cntrs[i].flags & PFM_GEN_IA32_SEL_INV ? 1 : 0;
Packit 577717
			if (!reg.sel_any)
Packit 577717
				reg.sel_any = cntrs[i].flags & PFM_GEN_IA32_SEL_ANYTHR? 1 : 0;
Packit 577717
		}
Packit 577717
Packit 577717
		pc[npc].reg_num     = assign[i];
Packit 577717
		pc[npc].reg_value   = reg.val;
Packit 577717
		pc[npc].reg_addr    = GEN_IA32_SEL_BASE+assign[i];
Packit 577717
		pd[i].reg_num  = assign[i];
Packit 577717
		pd[i].reg_addr = GEN_IA32_CTR_BASE+assign[i];
Packit 577717
Packit 577717
		if (pmu_version < 3)
Packit 577717
			__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%"PRIx64" event_sel=0x%x umask=0x%x os=%d usr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d] %s\n",
Packit 577717
					pc[npc].reg_num,
Packit 577717
					pc[npc].reg_num,
Packit 577717
					reg.val,
Packit 577717
					reg.sel_event_select,
Packit 577717
					reg.sel_unit_mask,
Packit 577717
					reg.sel_os,
Packit 577717
					reg.sel_usr,
Packit 577717
					reg.sel_en,
Packit 577717
					reg.sel_int,
Packit 577717
					reg.sel_inv,
Packit 577717
					reg.sel_edge,
Packit 577717
					reg.sel_cnt_mask,
Packit 577717
					gen_ia32_pe[e[i].event].pme_name);
Packit 577717
		else
Packit 577717
			__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%"PRIx64" event_sel=0x%x umask=0x%x os=%d usr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d anythr=%d] %s\n",
Packit 577717
					pc[npc].reg_num,
Packit 577717
					pc[npc].reg_num,
Packit 577717
					reg.val,
Packit 577717
					reg.sel_event_select,
Packit 577717
					reg.sel_unit_mask,
Packit 577717
					reg.sel_os,
Packit 577717
					reg.sel_usr,
Packit 577717
					reg.sel_en,
Packit 577717
					reg.sel_int,
Packit 577717
					reg.sel_inv,
Packit 577717
					reg.sel_edge,
Packit 577717
					reg.sel_cnt_mask,
Packit 577717
					reg.sel_any,
Packit 577717
					gen_ia32_pe[e[i].event].pme_name);
Packit 577717
Packit 577717
		__pfm_vbprintf("[PMC%u(pmd%u)]\n",
Packit 577717
				pd[i].reg_num,
Packit 577717
				pd[i].reg_num);
Packit 577717
Packit 577717
		npc++;
Packit 577717
	}
Packit 577717
	/* number of evtsel/ctr registers programmed */
Packit 577717
	outp->pfp_pmc_count = npc;
Packit 577717
	outp->pfp_pmd_count = n;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_dispatch_events(pfmlib_input_param_t *inp, void *model_in, pfmlib_output_param_t *outp, void *model_out)
Packit 577717
{
Packit 577717
	pfmlib_gen_ia32_input_param_t *mod_in  = model_in;
Packit 577717
Packit 577717
	if (inp->pfp_dfl_plm & (PFM_PLM1|PFM_PLM2)) {
Packit 577717
		DPRINT("invalid plm=%x\n", inp->pfp_dfl_plm);
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
	}
Packit 577717
Packit 577717
	/* simplfied v1 (no fixed counters */
Packit 577717
	if (pmu_version == 1)
Packit 577717
		return pfm_gen_ia32_dispatch_counters_v1(inp, mod_in, outp);
Packit 577717
	/* v2 or above */
Packit 577717
	return pfm_gen_ia32_dispatch_counters_v23(inp, mod_in, outp);
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_event_code(unsigned int i, unsigned int cnt, int *code)
Packit 577717
{
Packit 577717
	if (cnt != PFMLIB_CNT_FIRST && cnt > gen_support->pmc_count)
Packit 577717
		return PFMLIB_ERR_INVAL;
Packit 577717
Packit 577717
	*code = gen_ia32_pe[i].pme_code;
Packit 577717
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_gen_ia32_get_event_counters(unsigned int j, pfmlib_regmask_t *counters)
Packit 577717
{
Packit 577717
	unsigned int i;
Packit 577717
Packit 577717
	memset(counters, 0, sizeof(*counters));
Packit 577717
	for(i=0; i < num_gen_cnt; i++)
Packit 577717
		pfm_regmask_set(counters, i);
Packit 577717
Packit 577717
	for(i=0; i < num_fixed_cnt; i++) {
Packit 577717
		if (gen_ia32_pe[j].pme_fixed == (FIXED_PMD_BASE+i))
Packit 577717
			pfm_regmask_set(counters, FIXED_PMD_BASE+i);
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_gen_ia32_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs)
Packit 577717
{
Packit 577717
	*impl_pmcs = gen_ia32_impl_pmcs;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_gen_ia32_get_impl_pmds(pfmlib_regmask_t *impl_pmds)
Packit 577717
{
Packit 577717
	*impl_pmds = gen_ia32_impl_pmds;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_gen_ia32_get_impl_counters(pfmlib_regmask_t *impl_counters)
Packit 577717
{
Packit 577717
	/* all pmds are counters */
Packit 577717
	*impl_counters = gen_ia32_impl_pmds;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
pfm_gen_ia32_get_hw_counter_width(unsigned int *width)
Packit 577717
{
Packit 577717
	/*
Packit 577717
	 * Even though, CPUID 0xa returns in eax the actual counter
Packit 577717
	 * width, the architecture specifies that writes are limited
Packit 577717
	 * to lower 32-bits. As such, only the lower 31 bits have full
Packit 577717
	 * degree of freedom. That is the "useable" counter width.
Packit 577717
	 */
Packit 577717
	*width = PMU_GEN_IA32_COUNTER_WIDTH;
Packit 577717
}
Packit 577717
Packit 577717
static char *
Packit 577717
pfm_gen_ia32_get_event_name(unsigned int i)
Packit 577717
{
Packit 577717
	return gen_ia32_pe[i].pme_name;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_event_description(unsigned int ev, char **str)
Packit 577717
{
Packit 577717
	char *s;
Packit 577717
	s = gen_ia32_pe[ev].pme_desc;
Packit 577717
	if (s) {
Packit 577717
		*str = strdup(s);
Packit 577717
	} else {
Packit 577717
		*str = NULL;
Packit 577717
	}
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static char *
Packit 577717
pfm_gen_ia32_get_event_mask_name(unsigned int ev, unsigned int midx)
Packit 577717
{
Packit 577717
	return gen_ia32_pe[ev].pme_umasks[midx].pme_uname;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_event_mask_desc(unsigned int ev, unsigned int midx, char **str)
Packit 577717
{
Packit 577717
	char *s;
Packit 577717
Packit 577717
	s = gen_ia32_pe[ev].pme_umasks[midx].pme_udesc;
Packit 577717
	if (s) {
Packit 577717
		*str = strdup(s);
Packit 577717
	} else {
Packit 577717
		*str = NULL;
Packit 577717
	}
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int
Packit 577717
pfm_gen_ia32_get_num_event_masks(unsigned int ev)
Packit 577717
{
Packit 577717
	return gen_ia32_pe[ev].pme_numasks;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_event_mask_code(unsigned int ev, unsigned int midx, unsigned int *code)
Packit 577717
{
Packit 577717
	*code =gen_ia32_pe[ev].pme_umasks[midx].pme_ucode;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_cycle_event(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	if (gen_ia32_cycle_event == -1)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	e->event = gen_ia32_cycle_event;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
pfm_gen_ia32_get_inst_retired(pfmlib_event_t *e)
Packit 577717
{
Packit 577717
	if (gen_ia32_inst_retired_event == -1)
Packit 577717
		return PFMLIB_ERR_NOTSUPP;
Packit 577717
Packit 577717
	e->event = gen_ia32_inst_retired_event;
Packit 577717
	return PFMLIB_SUCCESS;
Packit 577717
}
Packit 577717
Packit 577717
/* architected PMU */
Packit 577717
pfm_pmu_support_t gen_ia32_support={
Packit 577717
	.pmu_name		= "Intel architectural PMU",
Packit 577717
	.pmu_type		= PFMLIB_GEN_IA32_PMU,
Packit 577717
	.pme_count		= 0,
Packit 577717
	.pmc_count		= 0,
Packit 577717
	.pmd_count		= 0,
Packit 577717
	.num_cnt		= 0,
Packit 577717
	.get_event_code		= pfm_gen_ia32_get_event_code,
Packit 577717
	.get_event_name		= pfm_gen_ia32_get_event_name,
Packit 577717
	.get_event_counters	= pfm_gen_ia32_get_event_counters,
Packit 577717
	.dispatch_events	= pfm_gen_ia32_dispatch_events,
Packit 577717
	.pmu_detect		= pfm_gen_ia32_detect,
Packit 577717
	.pmu_init		= pfm_gen_ia32_init,
Packit 577717
	.get_impl_pmcs		= pfm_gen_ia32_get_impl_pmcs,
Packit 577717
	.get_impl_pmds		= pfm_gen_ia32_get_impl_pmds,
Packit 577717
	.get_impl_counters	= pfm_gen_ia32_get_impl_counters,
Packit 577717
	.get_hw_counter_width	= pfm_gen_ia32_get_hw_counter_width,
Packit 577717
	.get_event_desc         = pfm_gen_ia32_get_event_description,
Packit 577717
	.get_cycle_event	= pfm_gen_ia32_get_cycle_event,
Packit 577717
	.get_inst_retired_event = pfm_gen_ia32_get_inst_retired,
Packit 577717
	.get_num_event_masks	= pfm_gen_ia32_get_num_event_masks,
Packit 577717
	.get_event_mask_name	= pfm_gen_ia32_get_event_mask_name,
Packit 577717
	.get_event_mask_code	= pfm_gen_ia32_get_event_mask_code,
Packit 577717
	.get_event_mask_desc	= pfm_gen_ia32_get_event_mask_desc
Packit 577717
};