はじめましてではないのですが、
はじめまして。尾辻と申します。

Phenom/opteron{1,2,8}3XXなcpufreqを作ってみました。
まだβバージョンですが。

こんな感じです。
マザーボードはBIOSTAR TF8200A2+です。
# dmesgのcpuの部分
CPU: AMD Phenom(tm) 9850 Quad-Core Processor (2500.01-MHz 686-class CPU)
# uname -aの抜きだし
FreeBSD 7.1-PRERELEASE #0 Thu Oct  2 21:20:49 JST 2008 gen@:/tmp/sys/TF8200S 
i386
# kldload cpufreq
hwpstate0: <Cool`n'Quiet 2.0> on cpu0
hwpstate0: SVI mode
hwpstate0: you have 2 P-state.
hwpstate0: freq=2500MHz volts=1300mV
hwpstate0: freq=1250MHz volts=1050mV
hwpstate0: Now P0-state.
hwpstate1: <Cool`n'Quiet 2.0> on cpu1
hwpstate1: SVI mode
hwpstate1: you have 2 P-state.
hwpstate1: freq=2500MHz volts=1300mV
hwpstate1: freq=1250MHz volts=1050mV
hwpstate1: Now P0-state.
hwpstate2: <Cool`n'Quiet 2.0> on cpu2
hwpstate2: SVI mode
hwpstate2: you have 2 P-state.
hwpstate2: freq=2500MHz volts=1300mV
hwpstate2: freq=1250MHz volts=1050mV
hwpstate2: Now P0-state.
hwpstate3: <Cool`n'Quiet 2.0> on cpu3
hwpstate3: SVI mode
hwpstate3: you have 2 P-state.
hwpstate3: freq=2500MHz volts=1300mV
hwpstate3: freq=1250MHz volts=1050mV
hwpstate3: Now P0-state.
# sysctl dev.cpu.0.freq_levels 
dev.cpu.0.freq_levels: 2500/-1 1250/-1
# sysctl dev.cpu.0.freq
dev.cpu.0.freq: 2500
# sysctl dev.cpu.0.freq=1250
dev.cpu.0.freq: 2500 -> 1250
# dmesg
hwpstate0: goto P1-state
hwpstate0: Now P1-state.
hwpstate1: goto P1-state
hwpstate1: Now P1-state.
hwpstate2: goto P1-state
hwpstate2: Now P1-state.
hwpstate3: goto P1-state
hwpstate3: Now P1-state.
# kldunload cpufreq
hwpstate0: Now P0-state.
hwpstate0: detached
hwpstate1: Now P0-state.
hwpstate1: detached
hwpstate2: Now P0-state.
hwpstate2: detached
hwpstate3: Now P0-state.
hwpstate3: detached
# sysctl dev.cpu.0.freq
dev.cpu.0.freq: 1250
(???まだβバージョンです。)
# kldload cpufreq
で元に戻ります。

current mailing listに投稿しても
なんというか、私の英語がひどいのかそれとも、
以前のpstate.cがひどかったのか、それともかなり間があいたからなのか
というかんじなものですから、こちらにも投稿させていただきます。
以前にcurrentメーリングリストに投稿したらkldunloadできない
とかフリーズするとかでしたが。
ベロニカさんの所ではうまくいったのですが、cghostsさんの所では
うまくいかないみたいでした。PHKさんの所ではどうなのかわかりません。
今回のcpufreqはアクロバチックな所がないので大丈夫だと思います。
以前のpstate.cはBIOSがやるべきところをwrmsrをつかって
強引にやってました。ですがwindowsでいう所の
crystal cpuidのようなものだからいいかなとは思っていたのですが
考えてみると400MHzまで下げられたのですが遅すぎです。
そこで#debug.cpufreq.lowest=1200というのを/boot/loader.confに
いれていたのですが、BIOSが作成したhardware pstateは
私の所では1250MHzと2500MHzです。これで十分だと思い直し
妥協しました。

そいうわけでBIOSが作成した Hardware P-state というP-stateを使って
それを遷移させるだけのモジュールです。
ソースを読めば300行くらいで手続き的なところを除くと
半分くらいです。

試してみてください。今度のはkldunload できます。
まだβバージョンなのでdebug message がでますが、
ソース中のhwpstate_verbose=0とすればでなくなります。
またコメントもあります。

currentのamd64でもためしているのでamd64でも大丈夫だと思います。
なにぶんはじめてのカーネルモジュールなのでいたらないところ
こうしたほうがいいところなど指摘してくださると
うれしいです。
よろしくお願いします。
#人柱をお願いしているようでもしわけありませんが、
#自分の環境ではすくなくとも大丈夫です。

尾辻 <[&#x30E1;&#x30FC;&#x30EB;&#x30A2;&#x30C9;&#x30EC;&#x30B9;&#x4FDD;&#x8B77;] 
あの夏!>

P.S. 以下ソースです。file名はhwpstate.cなのですが。
/sys/module/cpufreq/MakefileのSRCS=にhwpstate.cを追加して、
/sys/i386/cpufre/に以下のファイルhwpstate.cでおいてください。
kerenelにはcpufreqが標準でついているので
それを除いたカーネルをつくらないと試せないと思います。
/sys/module/cpuferqでmake && make installすると使えるようになります。
=====================================================
/**
 * Reference:
 *  Rev 3.06  March 26, 2008 - BIOS and Kernel Developer's Guide(BKDG)
 *  for AMD Family 10h Processors
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <dev/pci/pcivar.h>
#include <machine/md_var.h>

#include <contrib/dev/acpica/acpi.h>
#include <dev/acpica/acpivar.h>

#include "acpi_if.h"
#include "cpufreq_if.h"

#define MSR_AMD10H_LIMIT    0xc0010061
#define MSR_AMD10H_CONTROL  0xc0010062
#define MSR_AMD10H_STATUS   0xc0010063
#define MSR_AMD10H_CONFIG   0xc0010064
#define AMD10H_PVI_MODE     1
#define AMD10H_SVI_MODE     0
#define AMD10H_MAX_STATES   16

/* for MSR_AMD10H_LIMIT C001_0061 */
#define AMD10H_GET_PSTATE_MAX_VAL(msr)      (((msr) >> 4) & 0xF)
/* for MSR_AMD10H_CONFIG C001_0064:68 */
#define MSR_AMD10H_CUR_VID(msr)             (((msr) >> 9) & 0x3F)
#define MSR_AMD10H_CUR_DID(msr)             (((msr) >> 6) & 0x07)
#define MSR_AMD10H_CUR_FID(msr)             ((msr) & 0x3F)

/**
 * setting this to 0 can hush up verbose messages.
 */
static int hwpstate_verbose = 1;

struct hwpstate_setting {
        int freq;               /* CPU clock in Mhz or 100ths of a percent. */
        int volts;              /* Voltage in mV. */
        int power;              /* Power consumed in mW. */
        int lat;                /* Transition latency in us. */
        int pstate_id;
        device_t dev;           /* Driver providing this setting. */
};

struct hwpstate_softc {
        device_t dev;
        struct hwpstate_setting hwpstate_settings[AMD10H_MAX_STATES];
        int cfnum;
        int voltage_mode;       /* for AMD10H_PVI_MODE / AMD10H_SVI_MODE */
        int curpstate;
};

static void hwpstate_identify(driver_t * driver, device_t parent);
static int hwpstate_probe(device_t dev);
static int hwpstate_attach(device_t dev);
static int hwpstate_detach(device_t dev);
static int hwpstate_set(device_t dev, const struct cf_setting *cf);
static int hwpstate_get(device_t dev, struct cf_setting *cf);
static int hwpstate_settings(device_t dev, struct cf_setting *sets, int *count);
static int hwpstate_type(device_t dev, int *type);
static int hwpstate_shutdown(device_t dev);
static int hwpstate_features(driver_t * driver, u_int * features);

static device_method_t hwpstate_methods[] = {
        /* Device interface */
        DEVMETHOD(device_identify, hwpstate_identify),
        DEVMETHOD(device_probe, hwpstate_probe),
        DEVMETHOD(device_attach, hwpstate_attach),
        DEVMETHOD(device_detach, hwpstate_detach),
        DEVMETHOD(device_shutdown, hwpstate_shutdown),

        /* cpufreq interface */
        DEVMETHOD(cpufreq_drv_set, hwpstate_set),
        DEVMETHOD(cpufreq_drv_get, hwpstate_get),
        DEVMETHOD(cpufreq_drv_settings, hwpstate_settings),
        DEVMETHOD(cpufreq_drv_type, hwpstate_type),

        /* ACPI interface */
        DEVMETHOD(acpi_get_features, hwpstate_features),

        {0, 0}
};

static devclass_t hwpstate_devclass;
static driver_t hwpstate_driver = {
        "hwpstate",
        hwpstate_methods,
        sizeof(struct hwpstate_softc),
};
DRIVER_MODULE(hwpstate, cpu, hwpstate_driver, hwpstate_devclass, 0, 0);

static void
hwpstate_goto_pstate(device_t dev,int pstate)
{
        struct hwpstate_softc *sc;
        uint64_t msr;
        int i;
        sc = device_get_softc(dev);
        sc->curpstate = pstate;
        wrmsr(MSR_AMD10H_CONTROL, pstate);
        for(i=0;i<1000;i++){
                msr=rdmsr(MSR_AMD10H_STATUS);
                if(msr==pstate){
                        break;
                }
                DELAY(100);
        }
        msr=rdmsr(MSR_AMD10H_STATUS);
        if(hwpstate_verbose)
                device_printf(dev,"Now P%d-state.\n",(int)msr);
        return;
}

static int
hwpstate_set(device_t dev, const struct cf_setting *cf)
{
        struct hwpstate_softc *sc;
        struct hwpstate_setting *set;
        int i;
        if (cf == NULL)
                return (EINVAL);
        sc = device_get_softc(dev);
        set = sc->hwpstate_settings;
        for (i = 0; i < sc->cfnum; i++)
                if (cf->freq == set[i].freq)
                        break;
        if (i == sc->cfnum)
                return EINVAL;
        if(hwpstate_verbose)
                device_printf(dev,"goto P%d-state\n",set[i].pstate_id);
        sc->curpstate = set[i].pstate_id;
        hwpstate_goto_pstate(dev,set[i].pstate_id);
        return (0);
}

static int
hwpstate_get(device_t dev, struct cf_setting *cf)
{
        struct hwpstate_softc *sc;
        struct hwpstate_setting set;
        sc = device_get_softc(dev);
        if (cf == NULL)
                return (EINVAL);
        set = sc->hwpstate_settings[sc->curpstate];
        cf->freq = set.freq;
        cf->volts = set.volts;
        cf->power = CPUFREQ_VAL_UNKNOWN;
        cf->lat = 16;
        cf->dev = dev;
        return (0);
}

static int
hwpstate_settings(device_t dev, struct cf_setting *sets, int *count)
{
        struct hwpstate_softc *sc;
        struct hwpstate_setting set;
        int i;
        if (sets == NULL || count == NULL)
                return (EINVAL);
        sc = device_get_softc(dev);
        if (*count < sc->cfnum)
                return (E2BIG);
        for (i = 0; i < sc->cfnum; i++, sets++) {
                set = sc->hwpstate_settings[i];
                sets->freq = set.freq;
                sets->volts = set.volts;
                sets->power = set.power;
                sets->lat = set.lat;
                sets->dev = set.dev;
        }
        *count = sc->cfnum;
        return (0);
}

static int
hwpstate_type(device_t dev, int *type)
{

        if (type == NULL)
                return (EINVAL);
        *type = CPUFREQ_TYPE_ABSOLUTE;
        return (0);
}

static int
hwpstate_is_capable(void)
{
        u_int regs[4];
        if (strcmp(cpu_vendor, "AuthenticAMD") != 0 ||
            cpu_exthigh < 0x80000007)
                return (FALSE);
        do_cpuid(0x80000007, regs);
        if (regs[3] & 0x80) {   /* HwPstate Enable bit */
                return (TRUE);
        }
        return (FALSE);
}

static void
hwpstate_identify(driver_t * driver, device_t parent)
{
        device_t child;
        if (device_find_child(parent, "hwpstate", -1) != NULL) {
                return;
        }
        if ((child = BUS_ADD_CHILD(parent, 10, "hwpstate", -1)) == NULL)
                device_printf(parent, "hwpstate: add child failed\n");
}

static int
hwpstate_probe(device_t dev)
{
        struct hwpstate_softc *sc;
        device_t perf_dev;
        uint64_t msr;
        int error, type;
        if (resource_disabled("hwpstate", 0))
                return (ENXIO);

        /* this had not to be in hwpstate_identify() */
        if (hwpstate_is_capable() == FALSE) {
                return (ENXIO);
        }
        perf_dev = device_find_child(device_get_parent(dev), "acpi_perf", -1);
        if (perf_dev && device_is_attached(perf_dev)) {
                error = CPUFREQ_DRV_TYPE(perf_dev, &type);
                if (error == 0 && (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
                        return (ENXIO);
        }
        sc = device_get_softc(dev);
        switch (cpu_id) {
        case 0x100f2A:          /* family 10h rev.DR-BA */
        case 0x100f22:          /* family 10h rev.DR-B2 */
        case 0x100f23:          /* family 10h rev.DR-B3 */
                break;
        default:
                return (ENXIO);
        }
        msr = rdmsr(MSR_AMD10H_LIMIT);
        sc->cfnum = AMD10H_GET_PSTATE_MAX_VAL(msr);
        if (sc->cfnum == 0) {
                device_printf(dev, "hardware-pstate is not supported by the 
bios.\n");
                return ENXIO;
        }
        device_set_desc(dev, "Cool`n'Quiet 2.0");
        return (0);
}

static int
hwpstate_attach(device_t dev)
{
        struct hwpstate_softc *sc;
        struct hwpstate_setting *set;
        device_t F3;
        uint64_t msr;
        uint32_t cfg;
        int i, vid, did, fid;
        sc = device_get_softc(dev);

        /**
         * following 24 means the 1st cpu. 25-31 instead of 24 is MP system.
         * I don't have MP system . But only for reading from 1st cpu.
         * so if the same 2*cpu , 4*cpu ,or 8*cpu , this can work , I think.
         */
        F3 = pci_find_bsf(0, 24, 3);
        cfg = pci_read_config(F3, 0xA0, 4);
        if (cfg & 0x10) {       /* PVI mode */
                if (hwpstate_verbose)
                        device_printf(dev, "PVI mode\n");
                sc->voltage_mode = AMD10H_PVI_MODE;
        } else {                /* SVI mode */
                if (hwpstate_verbose)
                        device_printf(dev, "SVI mode\n");
                sc->voltage_mode = AMD10H_SVI_MODE;
        }
        msr = rdmsr(MSR_AMD10H_LIMIT);
        sc->cfnum = 1 + AMD10H_GET_PSTATE_MAX_VAL(msr);
        if (hwpstate_verbose)
                device_printf(dev, "you have %d P-state.\n", sc->cfnum);
        set = sc->hwpstate_settings;
        for (i = 0; i < sc->cfnum; i++, set++) {
                msr = rdmsr(MSR_AMD10H_CONFIG + i);
                if ((msr & 0x8000000000000000)) {
                        vid = MSR_AMD10H_CUR_VID(msr);
                        did = MSR_AMD10H_CUR_DID(msr);
                        fid = MSR_AMD10H_CUR_FID(msr);
                        set->freq = 100 * (fid + 0x10) / (1 << did);
                        if (sc->voltage_mode == AMD10H_PVI_MODE) {
                                /* 2.4.1.6.2 Parallel VID Encodings */
                                if (vid >= 0x20)
                                        set->volts = (7625 - 125 * (vid - 
0x20)) / 10;
                                else
                                        set->volts = 1550 - 25 * vid;
                        } else {
                                /* 2.4.1.6.3 Serial VID Encodings */
                                if (vid >= 0x7F)
                                        set->volts = 0;
                                else
                                        set->volts = (15500 - 125 * vid) / 10;
                        }
                        if (hwpstate_verbose)
                                device_printf(dev, "freq=%dMHz volts=%dmV\n", 
set->freq, set->volts);
                        set->pstate_id = i;
                        set->power = CPUFREQ_VAL_UNKNOWN;
                        set->lat = 16;
                        set->dev = dev;
                }
        }
        cpufreq_register(dev);
        hwpstate_goto_pstate(dev,0);
        return (0);
}

static int
hwpstate_detach(device_t dev)
{

        hwpstate_goto_pstate(dev,0);
        return (cpufreq_unregister(dev));
}

static int
hwpstate_shutdown(device_t dev)
{

        hwpstate_goto_pstate(dev,0);
        return (0);
}

static int
hwpstate_features(driver_t * driver, u_int * features)
{

        *features = ACPI_CAP_PERF_MSRS;
        return (0);
}

メールによる返信