A slightly-closer-to-working version that includes code appropriate

to regular Pentiums.  Unfortunately, it doesn't work on mine,
but I'm not sure if this is the fault of the driver.
This commit is contained in:
Garrett Wollman 1996-03-27 22:02:18 +00:00
parent b3f735dcfd
commit 650e27cd25
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=14860

View File

@ -26,7 +26,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: perfmon.c,v 1.1 1996/03/26 19:57:53 wollman Exp $
*/
#include <sys/param.h>
@ -43,6 +43,11 @@ static int perfmon_inuse;
static int perfmon_cpuok;
static int msr_ctl[NPMC];
static int msr_pmc[NPMC];
static unsigned int ctl_shadow[NPMC];
static quad_t pmc_shadow[NPMC]; /* used when ctr is stopped on P5 */
static int (*writectl)(int);
static int writectl5(int);
static int writectl6(int);
/*
* Must be called after cpu_class is set up.
@ -51,13 +56,21 @@ void
perfmon_init(void)
{
switch(cpu_class) {
case CPUCLASS_586: /* assume it's the same for now */
case CPUCLASS_586:
perfmon_cpuok = 1;
msr_ctl[0] = 0x11;
msr_ctl[1] = 0x11;
msr_pmc[0] = 0x12;
msr_pmc[1] = 0x13;
writectl = writectl5;
break;
case CPUCLASS_686:
perfmon_cpuok = 1;
msr_ctl[0] = 0x186;
msr_ctl[1] = 0x187;
msr_pmc[0] = 0xc1;
msr_pmc[1] = 0xc2;
writectl = writectl6;
break;
default:
@ -80,8 +93,11 @@ perfmon_setup(int pmc, unsigned int control)
perfmon_inuse |= (1 << pmc);
control &= ~(PMCF_SYS_FLAGS << 16);
wrmsr(msr_ctl[pmc], control);
wrmsr(msr_pmc[pmc], 0);
disable_intr();
ctl_shadow[pmc] = control;
writectl(pmc);
wrmsr(msr_pmc[pmc], pmc_shadow[pmc] = 0);
enable_intr();
return 0;
}
@ -92,7 +108,7 @@ perfmon_get(int pmc, unsigned int *control)
return EINVAL;
if (perfmon_inuse & (1 << pmc)) {
*control = rdmsr(msr_ctl[pmc]);
*control = ctl_shadow[pmc];
return 0;
}
return EBUSY; /* XXX reversed sense */
@ -106,6 +122,7 @@ perfmon_fini(int pmc)
if (perfmon_inuse & (1 << pmc)) {
perfmon_stop(pmc);
ctl_shadow[pmc] = 0;
perfmon_inuse &= ~(1 << pmc);
return 0;
}
@ -115,48 +132,34 @@ perfmon_fini(int pmc)
int
perfmon_start(int pmc)
{
/*
* XXX - Current Intel design does not allow counters to be enabled
* independently.
*/
if (pmc != PMC_ALL)
if (pmc < 0 || pmc >= NPMC)
return EINVAL;
#if 0
if (perfmon_inuse & (1 << pmc)) {
wrmsr(msr_ctl[pmc], rdmsr(msr_ctl[pmc]) | (PMCF_EN << 16));
return 0;
}
#else
if (perfmon_inuse) {
wrmsr(msr_ctl[0], rdmsr(msr_ctl[0]) | (PMCF_EN << 16));
disable_intr();
ctl_shadow[pmc] |= (PMCF_EN << 16);
wrmsr(msr_pmc[pmc], pmc_shadow[pmc]);
writectl(pmc);
enable_intr();
return 0;
}
#endif
return EBUSY;
}
int
perfmon_stop(int pmc)
{
/*
* XXX - Current Intel design does not allow counters to be enabled
* independently.
*/
if (pmc != PMC_ALL)
if (pmc < 0 || pmc >= NPMC)
return EINVAL;
#if 0
if (perfmon_inuse & (1 << pmc)) {
wrmsr(msr_ctl[pmc], rdmsr(msr_ctl[pmc]) & ~(PMCF_EN << 16));
disable_intr();
pmc_shadow[pmc] = rdmsr(msr_pmc[pmc]);
ctl_shadow[pmc] &= ~(PMCF_EN << 16);
writectl(pmc);
enable_intr();
return 0;
}
#else
if (perfmon_inuse) {
wrmsr(msr_ctl[0], rdmsr(msr_ctl[0]) & ~(PMCF_EN << 16));
return 0;
}
#endif
return EBUSY;
}
@ -167,7 +170,10 @@ perfmon_read(int pmc, quad_t *val)
return EINVAL;
if (perfmon_inuse & (1 << pmc)) {
*val = rdmsr(msr_pmc[pmc]);
if (ctl_shadow[pmc] & (PMCF_EN << 16))
*val = rdmsr(msr_pmc[pmc]);
else
*val = pmc_shadow[pmc];
return 0;
}
@ -181,12 +187,64 @@ perfmon_reset(int pmc)
return EINVAL;
if (perfmon_inuse & (1 << pmc)) {
wrmsr(msr_pmc[pmc], 0);
wrmsr(msr_pmc[pmc], pmc_shadow[pmc] = 0);
return 0;
}
return EBUSY;
}
/*
* Unfortunately, the performance-monitoring registers are laid out
* differently in the P5 and P6. We keep everything in P6 format
* internally (except for the event code), and convert to P5
* format as needed on those CPUs. The writectl function pointer
* is set up to point to one of these functions by perfmon_init().
*/
int
writectl6(int pmc)
{
if (pmc > 0 && !(ctl_shadow[pmc] & (PMCF_EN << 16))) {
wrmsr(msr_ctl[pmc], 0);
} else {
wrmsr(msr_ctl[pmc], ctl_shadow[pmc]);
}
return 0;
}
#define P5FLAG_P 0x200
#define P5FLAG_E 0x100
#define P5FLAG_USR 0x80
#define P5FLAG_OS 0x40
int
writectl5(int pmc)
{
quad_t newval = 0;
if (ctl_shadow[1] & (PMCF_EN << 16)) {
if (ctl_shadow[1] & (PMCF_USR << 16))
newval |= P5FLAG_USR << 16;
if (ctl_shadow[1] & (PMCF_OS << 16))
newval |= P5FLAG_OS << 16;
if (ctl_shadow[1] & (PMCF_E << 16))
newval |= P5FLAG_E << 16;
newval |= (ctl_shadow[1] & 0x3f) << 16;
}
if (ctl_shadow[0] & (PMCF_EN << 16)) {
if (ctl_shadow[1] & (PMCF_USR << 16))
newval |= P5FLAG_USR;
if (ctl_shadow[1] & (PMCF_OS << 16))
newval |= P5FLAG_OS;
if (ctl_shadow[1] & (PMCF_E << 16))
newval |= P5FLAG_E;
newval |= ctl_shadow[1] & 0x3f;
}
printf("about to wrmsr(%x, %x)\n", msr_ctl[0], (unsigned)newval);
printf("old value is %x\n", (unsigned)rdmsr(msr_ctl[0]));
wrmsr(msr_ctl[0], newval);
return 0; /* XXX should check for errors */
}
/*
* Now the user-mode interface, called from a subdevice of mem.c.
*/