Annotation of sys/arch/i386/i386/powernow.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: powernow.c,v 1.3 2006/12/12 23:14:27 dim Exp $ */
! 2: /*
! 3: * Copyright (c) 2004 Ted Unangst
! 4: * All rights reserved.
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * AMD K6 PowerNow driver, see AMD tech doc #23525
! 21: * Numerous hints from Linux cpufreq driver
! 22: */
! 23:
! 24: #include <sys/param.h>
! 25: #include <sys/sysctl.h>
! 26:
! 27: #include <machine/cpu.h>
! 28: #include <machine/cpufunc.h>
! 29: #include <machine/specialreg.h>
! 30: #include <machine/pio.h>
! 31:
! 32: /* table 27 in amd 23535. entries after 45 taken from linux cpufreq */
! 33: struct {
! 34: int mult; /* not actually used, maybe for cpuspeed */
! 35: int magic;
! 36: } k6_multipliers[] = {
! 37: { 20, 4 },
! 38: { 30, 5 },
! 39: { 35, 7 },
! 40: { 40, 2 },
! 41: { 45, 0 },
! 42: { 55, 3 },
! 43: { 50, 1 },
! 44: { 60, 6 },
! 45: };
! 46: #define NUM_K6_ENTRIES (sizeof k6_multipliers / sizeof k6_multipliers[0])
! 47:
! 48: int k6_maxindex; /* no setting higher than this */
! 49:
! 50: /* linux says: "it doesn't matter where, as long as it is unused */
! 51: #define K6PORT 0xfff0
! 52:
! 53: void
! 54: k6_powernow_init(void)
! 55: {
! 56: uint64_t msrval;
! 57: uint32_t portval;
! 58: int i;
! 59:
! 60: /* on */
! 61: msrval = K6PORT | 0x1;
! 62: wrmsr(MSR_K6_EPMR, msrval);
! 63: /* read */
! 64: portval = inl(K6PORT + 8);
! 65: /* off */
! 66: wrmsr(MSR_K6_EPMR, 0LL);
! 67:
! 68: portval = (portval >> 5) & 7;
! 69:
! 70: for (i = 0; i < NUM_K6_ENTRIES; i++)
! 71: if (portval == k6_multipliers[i].magic) {
! 72: k6_maxindex = i;
! 73: break;
! 74: }
! 75: if (i == NUM_K6_ENTRIES) {
! 76: printf("bad value for current multiplier\n");
! 77: return;
! 78: }
! 79:
! 80: cpu_setperf = k6_powernow_setperf;
! 81: }
! 82:
! 83: void
! 84: k6_powernow_setperf(int level)
! 85: {
! 86: uint64_t msrval;
! 87: uint32_t portval;
! 88: int index;
! 89:
! 90: index = level * k6_maxindex / 100;
! 91:
! 92: /* on */
! 93: msrval = K6PORT | 0x1;
! 94: wrmsr(MSR_K6_EPMR, msrval);
! 95: /* read and update */
! 96: portval = inl(K6PORT + 8);
! 97: portval &= 0xf;
! 98: portval |= 1 << 12 | 1 << 10 | 1 << 9 |
! 99: k6_multipliers[index].magic << 5;
! 100: outl(K6PORT + 8, portval);
! 101: /* off */
! 102: wrmsr(MSR_K6_EPMR, 0LL);
! 103: }
CVSweb