Annotation of sys/arch/i386/i386/pctr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pctr.c,v 1.22 2006/11/29 20:03:20 dim Exp $ */
! 2:
! 3: /*
! 4: * Pentium performance counter driver for OpenBSD.
! 5: * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
! 6: *
! 7: * Modification and redistribution in source and binary forms is
! 8: * permitted provided that due credit is given to the author and the
! 9: * OpenBSD project by leaving this copyright notice intact.
! 10: */
! 11:
! 12: #include <sys/param.h>
! 13: #include <sys/types.h>
! 14: #include <sys/errno.h>
! 15: #include <sys/fcntl.h>
! 16: #include <sys/ioccom.h>
! 17: #include <sys/systm.h>
! 18:
! 19: #include <machine/cputypes.h>
! 20: #include <machine/psl.h>
! 21: #include <machine/pctr.h>
! 22: #include <machine/cpu.h>
! 23: #include <machine/specialreg.h>
! 24:
! 25: pctrval pctr_idlcnt; /* Gets incremented in locore.s */
! 26:
! 27: int pctr_isintel;
! 28:
! 29: #define usetsc (cpu_feature & CPUID_TSC)
! 30: #define usep5ctr (pctr_isintel && (((cpu_id >> 8) & 15) == 5) && \
! 31: (((cpu_id >> 4) & 15) > 0))
! 32: #define usep6ctr (pctr_isintel && ((cpu_id >> 8) & 15) == 6)
! 33:
! 34: void pctrattach(int);
! 35: int pctropen(dev_t, int, int, struct proc *);
! 36: int pctrclose(dev_t, int, int, struct proc *);
! 37: int pctrioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 38: int p5ctrsel(int fflag, u_int cmd, u_int fn);
! 39: static __inline void p5ctrrd(struct pctrst *st);
! 40: int p6ctrsel(int fflag, u_int cmd, u_int fn);
! 41: static __inline void p6ctrrd(struct pctrst *st);
! 42:
! 43: void
! 44: pctrattach(int num)
! 45: {
! 46: if (num > 1)
! 47: return;
! 48:
! 49: pctr_isintel = (strcmp(cpu_vendor, "GenuineIntel") == 0);
! 50:
! 51: if (usep6ctr)
! 52: /* Enable RDTSC and RDPMC instructions from user-level. */
! 53: __asm __volatile ("movl %%cr4,%%eax\n"
! 54: "\tandl %0,%%eax\n"
! 55: "\torl %1,%%eax\n"
! 56: "\tmovl %%eax,%%cr4"
! 57: :: "i" (~CR4_TSD), "i" (CR4_PCE) : "eax");
! 58: else if (usetsc)
! 59: /* Enable RDTSC instruction from user-level. */
! 60: __asm __volatile ("movl %%cr4,%%eax\n"
! 61: "\tandl %0,%%eax\n"
! 62: "\tmovl %%eax,%%cr4"
! 63: :: "i" (~CR4_TSD) : "eax");
! 64:
! 65: if (usep6ctr)
! 66: printf("pctr: 686-class user-level performance counters enabled\n");
! 67: else if (usep5ctr)
! 68: printf("pctr: 586-class performance counters and user-level cycle counter enabled\n");
! 69: else if (usetsc)
! 70: printf("pctr: user-level cycle counter enabled\n");
! 71: else
! 72: printf("pctr: no performance counters in CPU\n");
! 73: }
! 74:
! 75: int
! 76: pctropen(dev_t dev, int oflags, int devtype, struct proc *p)
! 77: {
! 78: if (minor(dev))
! 79: return ENXIO;
! 80: return 0;
! 81: }
! 82:
! 83: int
! 84: pctrclose(dev_t dev, int oflags, int devtype, struct proc *p)
! 85: {
! 86: return 0;
! 87: }
! 88:
! 89: int
! 90: p5ctrsel(int fflag, u_int cmd, u_int fn)
! 91: {
! 92: pctrval msr11;
! 93: int msr;
! 94: int shift;
! 95:
! 96: cmd -= PCIOCS0;
! 97: if (cmd > 1)
! 98: return EINVAL;
! 99: msr = P5MSR_CTR0 + cmd;
! 100: shift = cmd ? 0x10 : 0;
! 101:
! 102: if (!(fflag & FWRITE))
! 103: return EPERM;
! 104: if (fn >= 0x200)
! 105: return EINVAL;
! 106:
! 107: msr11 = rdmsr(P5MSR_CTRSEL);
! 108: msr11 &= ~(0x1ffLL << shift);
! 109: msr11 |= fn << shift;
! 110: wrmsr(P5MSR_CTRSEL, msr11);
! 111: wrmsr(msr, 0);
! 112:
! 113: return 0;
! 114: }
! 115:
! 116: static __inline void
! 117: p5ctrrd(struct pctrst *st)
! 118: {
! 119: u_int msr11;
! 120:
! 121: msr11 = rdmsr(P5MSR_CTRSEL);
! 122: st->pctr_fn[0] = msr11 & 0xffff;
! 123: st->pctr_fn[1] = msr11 >> 16;
! 124: __asm __volatile("cli");
! 125: st->pctr_tsc = rdtsc();
! 126: st->pctr_hwc[0] = rdmsr(P5MSR_CTR0);
! 127: st->pctr_hwc[1] = rdmsr(P5MSR_CTR1);
! 128: __asm __volatile("sti");
! 129: }
! 130:
! 131: int
! 132: p6ctrsel(int fflag, u_int cmd, u_int fn)
! 133: {
! 134: int msrsel, msrval;
! 135:
! 136: cmd -= PCIOCS0;
! 137: if (cmd > 1)
! 138: return EINVAL;
! 139: msrsel = P6MSR_CTRSEL0 + cmd;
! 140: msrval = P6MSR_CTR0 + cmd;
! 141:
! 142: if (!(fflag & FWRITE))
! 143: return EPERM;
! 144: if (fn & 0x380000)
! 145: return EINVAL;
! 146:
! 147: wrmsr(msrval, 0);
! 148: wrmsr(msrsel, fn);
! 149: wrmsr(msrval, 0);
! 150:
! 151: return 0;
! 152: }
! 153:
! 154: static __inline void
! 155: p6ctrrd(struct pctrst *st)
! 156: {
! 157: st->pctr_fn[0] = rdmsr(P6MSR_CTRSEL0);
! 158: st->pctr_fn[1] = rdmsr(P6MSR_CTRSEL1);
! 159: __asm __volatile("cli");
! 160: st->pctr_tsc = rdtsc();
! 161: st->pctr_hwc[0] = rdpmc(0);
! 162: st->pctr_hwc[1] = rdpmc(1);
! 163: __asm __volatile("sti");
! 164: }
! 165:
! 166:
! 167: int
! 168: pctrioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
! 169: {
! 170: switch (cmd) {
! 171: case PCIOCRD:
! 172: {
! 173: struct pctrst *st = (void *)data;
! 174:
! 175: if (usep6ctr)
! 176: p6ctrrd(st);
! 177: else if (usep5ctr)
! 178: p5ctrrd(st);
! 179: else {
! 180: bzero(st, sizeof(*st));
! 181: if (usetsc)
! 182: st->pctr_tsc = rdtsc();
! 183: }
! 184: st->pctr_idl = pctr_idlcnt;
! 185: return 0;
! 186: }
! 187: case PCIOCS0:
! 188: case PCIOCS1:
! 189: if (usep6ctr)
! 190: return p6ctrsel(fflag, cmd, *(u_int *) data);
! 191: if (usep5ctr)
! 192: return p5ctrsel(fflag, cmd, *(u_int *) data);
! 193: return ENODEV;
! 194: default:
! 195: return EINVAL;
! 196: }
! 197: }
CVSweb