Blame src/perfctr-2.7.x/usr.lib/ppc64.c

Packit 577717
/* 
Packit 577717
 * PPC64-specific perfctr library procedures.
Packit 577717
 * Copyright (C) 2004, 2007  Mikael Pettersson
Packit 577717
 * Copyright (C) 2004  Maynard Johnson
Packit 577717
 *
Packit 577717
 */
Packit 577717
#include <string.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <errno.h>
Packit 577717
#include <asm/unistd.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <fcntl.h>
Packit 577717
#include "libperfctr.h"
Packit 577717
#include "ppc64.h"
Packit 577717
Packit 577717
static unsigned int __NR_vperfctr_open;
Packit 577717
#define __NR_vperfctr_control	(__NR_vperfctr_open+1)
Packit 577717
#define __NR_vperfctr_write	(__NR_vperfctr_open+2)
Packit 577717
#define __NR_vperfctr_read	(__NR_vperfctr_open+3)
Packit 577717
Packit 577717
#include <unistd.h>
Packit 577717
Packit 577717
static void init_sys_vperfctr(void)
Packit 577717
{
Packit 577717
    if (!__NR_vperfctr_open) {
Packit 577717
	unsigned int nr;
Packit 577717
	unsigned int kver = perfctr_linux_version_code();
Packit 577717
Packit 577717
	if (kver >= PERFCTR_KERNEL_VERSION(2,6,18))
Packit 577717
	    nr = 310;
Packit 577717
	else if (kver >= PERFCTR_KERNEL_VERSION(2,6,16))
Packit 577717
	    nr = 301;
Packit 577717
	else
Packit 577717
	    nr = 280;
Packit 577717
	__NR_vperfctr_open = nr;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * The actual syscalls.
Packit 577717
 */
Packit 577717
Packit 577717
int _sys_vperfctr_open(int fd_unused, int tid, int creat)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_open, tid, creat);
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_control(int fd, unsigned int cmd)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_control, fd, cmd);
Packit 577717
}
Packit 577717
Packit 577717
static int _sys_vperfctr_write(int fd, unsigned int domain, const void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_write, fd, domain, arg, argbytes);
Packit 577717
}
Packit 577717
Packit 577717
static int _sys_vperfctr_read(int fd, unsigned int domain, void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    init_sys_vperfctr();
Packit 577717
    return syscall(__NR_vperfctr_read, fd, domain, arg, argbytes);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * Simple syscall wrappers.
Packit 577717
 */
Packit 577717
Packit 577717
int _sys_vperfctr_read_sum(int fd, struct perfctr_sum_ctrs *arg)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_read(fd, VPERFCTR_DOMAIN_SUM, arg, sizeof(*arg));
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_read_children(int fd, struct perfctr_sum_ctrs *arg)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_read(fd, VPERFCTR_DOMAIN_CHILDREN, arg, sizeof(*arg));
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_unlink(int fd)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_UNLINK);
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_iresume(int fd)
Packit 577717
{
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_RESUME);
Packit 577717
}
Packit 577717
Packit 577717
#define	SPRN_PVR	0x11F	/* Processor Version Register */
Packit 577717
#define SPRN_MMCRA	786
Packit 577717
#define SPRN_MMCR0	795
Packit 577717
#define SPRN_MMCR1	798
Packit 577717
#define SPRN_PMC1	787
Packit 577717
#define SPRN_PMC2	788
Packit 577717
#define SPRN_PMC3	789
Packit 577717
#define SPRN_PMC4	790
Packit 577717
#define SPRN_PMC5	791
Packit 577717
#define SPRN_PMC6	792
Packit 577717
#define SPRN_PMC7	793
Packit 577717
#define SPRN_PMC8	794
Packit 577717
Packit 577717
#if 0
Packit 577717
static void show_regs(const struct perfctr_cpu_reg *regs, unsigned int n)
Packit 577717
{
Packit 577717
    unsigned int i;
Packit 577717
Packit 577717
    fprintf(stderr, "CPU Register Values:\n");
Packit 577717
    for(i = 0; i < n; ++i)
Packit 577717
	fprintf(stderr, "SPR %#x\t0x%08x\n", regs[i].nr, regs[i].value);
Packit 577717
}
Packit 577717
#else
Packit 577717
#define show_regs(regs, n) do{}while(0)
Packit 577717
#endif
Packit 577717
Packit 577717
static int read_packet(int fd, unsigned int domain, void *arg, unsigned int argbytes)
Packit 577717
{
Packit 577717
    int ret;
Packit 577717
Packit 577717
    ret = _sys_vperfctr_read(fd, domain, arg, argbytes);
Packit 577717
    if (ret != argbytes && ret >= 0) {
Packit 577717
	errno = EPROTO;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
    return ret;
Packit 577717
}
Packit 577717
Packit 577717
static unsigned int pmc_to_spr(unsigned int pmc)
Packit 577717
{
Packit 577717
    switch (pmc) {
Packit 577717
    default: /* impossible, but silences gcc warning */
Packit 577717
    case (1-1): return SPRN_PMC1;
Packit 577717
    case (2-1): return SPRN_PMC2;
Packit 577717
    case (3-1): return SPRN_PMC3;
Packit 577717
    case (4-1): return SPRN_PMC4;
Packit 577717
    case (5-1): return SPRN_PMC5;
Packit 577717
    case (6-1): return SPRN_PMC6;
Packit 577717
    case (7-1): return SPRN_PMC7;
Packit 577717
    case (8-1): return SPRN_PMC8;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
static int write_cpu_regs(int fd, const struct perfctr_cpu_control *control)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg regs[3+8];
Packit 577717
    unsigned int nrctrs, nractrs, pmc_mask, nr_regs, i, pmc;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrctrs = nractrs + control->nrictrs;
Packit 577717
    if (nrctrs < nractrs || nrctrs > 8) {
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
Packit 577717
    if (!nrctrs)
Packit 577717
	return 0;
Packit 577717
Packit 577717
    nr_regs = 0;
Packit 577717
    pmc_mask = 0;
Packit 577717
    for (i = 0; i < nrctrs; ++i) {
Packit 577717
	pmc = control->pmc_map[i];
Packit 577717
	if (pmc >= 8 || (pmc_mask & (1<
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	pmc_mask |= (1<
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    unsigned int j = 3 + (i - nractrs);
Packit 577717
	    regs[j].nr = pmc_to_spr(pmc);
Packit 577717
	    regs[j].value = control->ireset[i];
Packit 577717
	}
Packit 577717
    }
Packit 577717
    regs[0].nr = SPRN_MMCR0;
Packit 577717
    regs[0].value = control->ppc64.mmcr0;
Packit 577717
    regs[1].nr = SPRN_MMCR1;
Packit 577717
    regs[1].value = control->ppc64.mmcr1;
Packit 577717
    regs[2].nr = SPRN_MMCRA;
Packit 577717
    regs[2].value = control->ppc64.mmcra;
Packit 577717
    nr_regs = 3 + (nrctrs - nractrs);
Packit 577717
    show_regs(regs, nr_regs);
Packit 577717
    return _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
}
Packit 577717
Packit 577717
static int read_cpu_regs(int fd, struct perfctr_cpu_control *control)
Packit 577717
{
Packit 577717
    struct perfctr_cpu_reg regs[3+8];
Packit 577717
    unsigned int nrctrs, nractrs, pmc_mask, nr_regs, i, pmc;
Packit 577717
    int ret;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrctrs = nractrs + control->nrictrs;
Packit 577717
    if (nrctrs < nractrs || nrctrs > 8) {
Packit 577717
	errno = EINVAL;
Packit 577717
	return -1;
Packit 577717
    }
Packit 577717
Packit 577717
    if (!nrctrs)
Packit 577717
	return 0;
Packit 577717
Packit 577717
    nr_regs = 0;
Packit 577717
    pmc_mask = 0;
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	pmc = control->pmc_map[i];
Packit 577717
	if (pmc >= 8 || (pmc_mask & (1<
Packit 577717
	    errno = EINVAL;
Packit 577717
	    return -1;
Packit 577717
	}
Packit 577717
	pmc_mask |= (1<
Packit 577717
	if (i >= nractrs) {
Packit 577717
	    unsigned int j = 3 + (i - nractrs);
Packit 577717
	    regs[j].nr = pmc_to_spr(pmc);
Packit 577717
	}
Packit 577717
    }
Packit 577717
    regs[0].nr = SPRN_MMCR0;
Packit 577717
    regs[1].nr = SPRN_MMCR1;
Packit 577717
    regs[2].nr = SPRN_MMCRA;
Packit 577717
    nr_regs = 3 + (nrctrs - nractrs);
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_REGS, regs, nr_regs*sizeof(regs[0]));
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    show_regs(regs, nr_regs);
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	if (i >= nractrs)
Packit 577717
	    control->ireset[i] = regs[3 + (i - nractrs)].value;
Packit 577717
    }
Packit 577717
    control->ppc64.mmcr0 = regs[0].value;
Packit 577717
    control->ppc64.mmcr1 = regs[1].value;
Packit 577717
    control->ppc64.mmcra = regs[2].value;
Packit 577717
Packit 577717
    return 0;
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_write_control(int fd, unsigned int cpu_type, const struct vperfctr_control *control)
Packit 577717
{
Packit 577717
    union {
Packit 577717
	struct vperfctr_control_kernel control;
Packit 577717
	struct perfctr_cpu_control_header header;
Packit 577717
    } u;
Packit 577717
    unsigned int nrctrs;
Packit 577717
    int ret;
Packit 577717
    
Packit 577717
    ret = _sys_vperfctr_control(fd, VPERFCTR_CONTROL_CLEAR);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    u.control.si_signo = control->si_signo;
Packit 577717
    u.control.preserve = control->preserve;
Packit 577717
    ret = _sys_vperfctr_write(fd, VPERFCTR_DOMAIN_CONTROL,
Packit 577717
			      &u.control, sizeof u.control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    u.header.tsc_on = control->cpu_control.tsc_on;
Packit 577717
    u.header.nractrs = control->cpu_control.nractrs;
Packit 577717
    u.header.nrictrs = control->cpu_control.nrictrs;
Packit 577717
    ret = _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_CONTROL,
Packit 577717
			      &u.header, sizeof u.header);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    nrctrs = control->cpu_control.nractrs + control->cpu_control.nrictrs;
Packit 577717
    ret = _sys_vperfctr_write(fd, PERFCTR_DOMAIN_CPU_MAP,
Packit 577717
			      &control->cpu_control.pmc_map,
Packit 577717
			      nrctrs * sizeof control->cpu_control.pmc_map[0]);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    ret = write_cpu_regs(fd, &control->cpu_control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    return _sys_vperfctr_control(fd, VPERFCTR_CONTROL_RESUME);
Packit 577717
}
Packit 577717
Packit 577717
int _sys_vperfctr_read_control(int fd, unsigned int cpu_type, struct vperfctr_control *control)
Packit 577717
{
Packit 577717
    union {
Packit 577717
	struct vperfctr_control_kernel control;
Packit 577717
	struct perfctr_cpu_control_header header;
Packit 577717
    } u;
Packit 577717
    unsigned int nrctrs;
Packit 577717
    int ret;
Packit 577717
    
Packit 577717
    memset(control, 0, sizeof *control);
Packit 577717
Packit 577717
    ret = read_packet(fd, VPERFCTR_DOMAIN_CONTROL,
Packit 577717
		      &u.control, sizeof u.control);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    control->si_signo = u.control.si_signo;
Packit 577717
    control->preserve = u.control.preserve;
Packit 577717
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_CONTROL,
Packit 577717
		      &u.header, sizeof u.header);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
    control->cpu_control.tsc_on = u.header.tsc_on;
Packit 577717
    control->cpu_control.nractrs = u.header.nractrs;
Packit 577717
    control->cpu_control.nrictrs = u.header.nrictrs;
Packit 577717
Packit 577717
    nrctrs = control->cpu_control.nractrs + control->cpu_control.nrictrs;
Packit 577717
    ret = read_packet(fd, PERFCTR_DOMAIN_CPU_MAP,
Packit 577717
		      &control->cpu_control.pmc_map,
Packit 577717
		      nrctrs * sizeof control->cpu_control.pmc_map[0]);
Packit 577717
    if (ret < 0)
Packit 577717
	return ret;
Packit 577717
Packit 577717
    return read_cpu_regs(fd, &control->cpu_control);
Packit 577717
}
Packit 577717
Packit 577717
#define PVR_VER(pvr)	(((pvr) >>  16) & 0xFFFF)	/* Version field */
Packit 577717
#define PVR_REV(pvr)	(((pvr) >>   0) & 0xFFFF)	/* Revison field */
Packit 577717
Packit 577717
/* Processor Version Numbers */
Packit 577717
#define PV_NORTHSTAR	0x0033
Packit 577717
#define PV_PULSAR	0x0034
Packit 577717
#define PV_POWER4	0x0035
Packit 577717
#define PV_ICESTAR	0x0036
Packit 577717
#define PV_SSTAR	0x0037
Packit 577717
#define PV_POWER4p	0x0038
Packit 577717
#define PV_970		0x0039
Packit 577717
#define PV_POWER5	0x003A
Packit 577717
#define PV_POWER5p	0x003B
Packit 577717
#define PV_970FX	0x003C
Packit 577717
#define PV_630        	0x0040
Packit 577717
#define PV_630p	        0x0041
Packit 577717
#define PV_970MP	0x0044
Packit 577717
#define PV_970GX	0x0045
Packit 577717
Packit 577717
static unsigned int mfpvr(void)
Packit 577717
{
Packit 577717
    unsigned long pvr;
Packit 577717
Packit 577717
    asm("mfspr	%0,%1" : "=r"(pvr) : "i"(SPRN_PVR));
Packit 577717
    return pvr;
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_info_cpu_init(struct perfctr_info *info)
Packit 577717
{
Packit 577717
    unsigned int pvr = mfpvr();
Packit 577717
    int cpu_type;
Packit 577717
Packit 577717
    switch (PVR_VER(pvr)) {
Packit 577717
      case PV_POWER4:
Packit 577717
	cpu_type = PERFCTR_PPC64_POWER4;
Packit 577717
	break;
Packit 577717
      case PV_POWER4p:
Packit 577717
	cpu_type = PERFCTR_PPC64_POWER4p;
Packit 577717
	break;
Packit 577717
      case PV_970:
Packit 577717
      case PV_970FX:
Packit 577717
	cpu_type = PERFCTR_PPC64_970;
Packit 577717
	break;
Packit 577717
      case PV_970MP:
Packit 577717
	cpu_type = PERFCTR_PPC64_970MP;
Packit 577717
	break;
Packit 577717
      case PV_POWER5:
Packit 577717
      case PV_POWER5p: 
Packit 577717
	cpu_type = PERFCTR_PPC64_POWER5;
Packit 577717
	break;
Packit 577717
Packit 577717
      default:
Packit 577717
	cpu_type = PERFCTR_PPC64_GENERIC;
Packit 577717
	break;
Packit 577717
    }
Packit 577717
Packit 577717
    info->cpu_type = cpu_type;
Packit 577717
    return;
Packit 577717
}
Packit 577717
Packit 577717
unsigned int perfctr_info_nrctrs(const struct perfctr_info *info)
Packit 577717
{
Packit 577717
    switch( info->cpu_type ) {
Packit 577717
      case PERFCTR_PPC64_POWER4:
Packit 577717
      case PERFCTR_PPC64_POWER4p:
Packit 577717
      case PERFCTR_PPC64_970:
Packit 577717
      case PERFCTR_PPC64_970MP:
Packit 577717
      	return 8;
Packit 577717
      case PERFCTR_PPC64_POWER5:
Packit 577717
      	return 6;
Packit 577717
      default:
Packit 577717
	return 0;
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
const char *perfctr_info_cpu_name(const struct perfctr_info *info)
Packit 577717
{
Packit 577717
    switch( info->cpu_type ) {
Packit 577717
      case PERFCTR_PPC64_GENERIC:
Packit 577717
	return "Generic PowerPC64";
Packit 577717
      case PERFCTR_PPC64_POWER4:
Packit 577717
	return "POWER4";
Packit 577717
      case PERFCTR_PPC64_POWER4p:
Packit 577717
	return "POWER4+";
Packit 577717
      case PERFCTR_PPC64_970:
Packit 577717
	return "PowerPC 970";
Packit 577717
      case PERFCTR_PPC64_970MP:
Packit 577717
	return "PowerPC 970MP";
Packit 577717
      case PERFCTR_PPC64_POWER5:
Packit 577717
	return "POWER5";
Packit 577717
      default:
Packit 577717
	return "?";
Packit 577717
    }
Packit 577717
}
Packit 577717
Packit 577717
void perfctr_cpu_control_print(const struct perfctr_cpu_control *control)
Packit 577717
{
Packit 577717
    unsigned int i, nractrs, nrictrs, nrctrs;
Packit 577717
Packit 577717
    nractrs = control->nractrs;
Packit 577717
    nrictrs = control->nrictrs;
Packit 577717
    nrctrs = control->nractrs + nrictrs;
Packit 577717
Packit 577717
    printf("tsc_on\t\t\t%u\n", control->tsc_on);
Packit 577717
    printf("nractrs\t\t\t%u\n", nractrs);
Packit 577717
    if( nrictrs )
Packit 577717
	printf("nrictrs\t\t\t%u\n", nrictrs);
Packit 577717
    for(i = 0; i < nrctrs; ++i) {
Packit 577717
	printf("pmc[%u].map\t\t%u\n", i, control->pmc_map[i]);
Packit 577717
	if( i >= nractrs )
Packit 577717
	    printf("pmc[%u].ireset\t\t%d\n", i, control->ireset[i]);
Packit 577717
    }
Packit 577717
    if( control->ppc64.mmcr0 )
Packit 577717
	printf("mmcr0\t\t\t0x%08X\n", control->ppc64.mmcr0);
Packit 577717
    if( control->ppc64.mmcr1 )
Packit 577717
	printf("mmcr1\t\t\t0x%016llX\n",
Packit 577717
	       (unsigned long long)control->ppc64.mmcr1);
Packit 577717
    if( control->ppc64.mmcra )
Packit 577717
	printf("mmcra\t\t\t0x%08X\n", control->ppc64.mmcra);
Packit 577717
}
Packit 577717