root/arch/i386/i386/pctr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pctrattach
  2. pctropen
  3. pctrclose
  4. p5ctrsel
  5. p5ctrrd
  6. p6ctrsel
  7. p6ctrrd
  8. pctrioctl

    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 }

/* [<][>][^][v][top][bottom][index][help] */