Date: Wed, 24 Sep 2008 08:07:09 +0900 From: "G .Otsuji" <annona2@gmail.com> To: "Poul-Henning Kamp" <phk@phk.freebsd.dk> Cc: "G .Otsuji" <annona2@gmail.com>, FreeBSD Current <freebsd-current@freebsd.org> Subject: Re: AMD Family 10h cpufreq driver Message-ID: <200809232307.m8NN79th001888@softbank219001162114.bbtec.net> In-Reply-To: <26111.1222205043@critter.freebsd.dk> References: <200809232121.m8NLLnig001691@softbank219001162114.bbtec.net> <26111.1222205043@critter.freebsd.dk>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi, Thank you . Ummm, I wanted to know the pstate module loaded message, anyway thank you. Could you please try following patch to isolate the problem , voltage regulation is wrong or not, or swithching between p0 and p1 state is wrong or not . I added the comment and changed the vid_list to be mild voltage down-regulation. /** * vid list: 1550 - 25 * listvid is the [mV] . * change will be needed. I think. * pstate_vid_list[25] means 2.5GHz's listvid. and so on. * ( by the way limitation of 3.2 GHz . 3.3 GHz will be over flow ! * but there is no 3.3GHz over i think. ) */ static const int pstate_vid_list[33] = { 18, 18, 18, 18, 18, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5 }; from the comment , understanding is easier I think. sorry for few comment in the source. please try to change the vidlist if it goes wrong at the point which is threshold. here's pstate.c patch with /dev/null. --- /dev/null 2008-09-24 07:47:01.000000000 +0900 +++ pstate.c 2008-09-24 07:44:43.000000000 +0900 @@ -0,0 +1,448 @@ +/*- + * Copyright (c) 2008 Gen Otsuji + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Reference: Rev 3.06 - March 26, 2008 AMD Family 10h Processor BKDG + */ + +#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 <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/types.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_PSTATE_LIMIT 0xc0010061 +#define MSR_PSTATE_CONTROL 0xc0010062 +#define MSR_PSTATE_STATUS 0xc0010063 +#define MSR_PSTATE_CONFIG 0xc0010064 +#define MSR_PSTATE_COFVID 0xc0010071 + +#define MSR_PSTATE_MOF(msr) (((uint64_t)(msr)>>49)&0x3F) +#define MSR_PSTATE_CUR_VID(msr) (((msr) >> 9) & 0x3F) +#define MSR_PSTATE_CUR_DID(msr) (((msr) >> 6) & 0x07) +#define MSR_PSTATE_CUR_FID(msr) ((msr) & 0x3F) +#define PSTATE_LISTVID_TO_VID(listvid,mult) ((listvid) * (mult)) +#define PSTATE_VID_TO_LISTVID(vid,mult) ((vid) / (mult)) +#define PSTATE_LISTVID_TO_VOLTS(listvid) (1550 - 25 * (listvid)) +#define PSTATE_VID_TO_VOLTS(vid,mult) (1550 - 250 * (vid) / (mult) /10) +#define PSTATE_MK_PSTATE(msr,listvid,mult) \ + (((msr) & 0xFFFFFFFFFFFF0000) | \ + (((PSTATE_LISTVID_TO_VID(listvid,mult)) & 0x7F) << 9) | \ + ((pstate_did_list[id] & 0x07) << 6) | \ + ((pstate_fid_list[id] & 0x3F))) + +/** + * vid list: 1550 - 25 * listvid is the [mV] . + * change will be needed. I think. + * pstate_vid_list[25] means 2.5GHz's listvid. and so on. + * ( by the way limitation of 3.2 GHz . 3.3 GHz will be over flow ! + * but there is no 3.3GHz over i think. ) + */ +static const int pstate_vid_list[33] = { + 18, 18, 18, 18, 18, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, + 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5 +}; +static const int pstate_fid_list[33] = { + 0, 0, 0, 0, 4, 8, 12, 0, 2, 4, 6, 8, 10, 12, 14, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 +}; +static const int pstate_did_list[33] = { + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const int pstate_did_to_div[] = { + 1, 2, 4, 8, 16, 16, 16, 16 +}; +#define PSTATE_MAX_STATES 64 + +struct pstate_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. */ + device_t dev; /* Driver providing this setting. */ +}; + +struct pstate_softc { + device_t dev; + struct pstate_setting pstate_settings[PSTATE_MAX_STATES]; + int cfnum; + int mof_id; /* Maximum Operating Frequency / 100 */ + int mult; /* 2(in svi mode) 1(in pvi mode) */ + uint64_t backup [5]; + device_t F3; +}; + +static void pstate_identify(driver_t * driver, device_t parent); +static int pstate_probe(device_t dev); +static int pstate_attach(device_t dev); +static int pstate_detach(device_t dev); +static int pstate_set(device_t dev, const struct cf_setting *cf); +static int pstate_get(device_t dev, struct cf_setting *cf); +static int pstate_settings(device_t dev, struct cf_setting *sets, int *count); +static int pstate_type(device_t dev, int *type); +static int pstate_shutdown(device_t dev); +static int pstate_features(driver_t * driver, u_int * features); + +static device_method_t pstate_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, pstate_identify), + DEVMETHOD(device_probe, pstate_probe), + DEVMETHOD(device_attach, pstate_attach), + DEVMETHOD(device_detach, pstate_detach), + DEVMETHOD(device_shutdown, pstate_shutdown), + + /* cpufreq interface */ + DEVMETHOD(cpufreq_drv_set, pstate_set), + DEVMETHOD(cpufreq_drv_get, pstate_get), + DEVMETHOD(cpufreq_drv_settings, pstate_settings), + DEVMETHOD(cpufreq_drv_type, pstate_type), + + /* ACPI interface */ + DEVMETHOD(acpi_get_features, pstate_features), + + {0, 0} +}; + +static devclass_t pstate_devclass; +static driver_t pstate_driver = { + "pstate", + pstate_methods, + sizeof(struct pstate_softc), +}; +DRIVER_MODULE(pstate, cpu, pstate_driver, pstate_devclass, 0, 0); + +static int +pstate_cur_cpu_freq(void) +{ + uint64_t msr; + int did, fid; + msr = rdmsr(MSR_PSTATE_COFVID); + did = MSR_PSTATE_CUR_DID(msr); + fid = MSR_PSTATE_CUR_FID(msr); + if (bootverbose) + printf("pstate: DID=%d,FID=%d\n", did, fid); + return (100 * (fid + 16) / pstate_did_to_div[did]); +} + +static int +pstate_cur_cpu_volts(int mult) +{ + uint64_t msr; + int vid; + msr = rdmsr(MSR_PSTATE_COFVID); + vid = MSR_PSTATE_CUR_VID(msr); + if (bootverbose) + printf("pstate: VID=%d\n", vid); + return (PSTATE_VID_TO_VOLTS(vid, mult)); +} + +static int +pstate_set(device_t dev, const struct cf_setting *cf) +{ + struct pstate_softc *sc; + struct pstate_setting *ps; + uint64_t msr; + int i, id, setfreq, curfreq, curvolts; + if (cf == NULL) + return (EINVAL); + msr = rdmsr(MSR_PSTATE_CONFIG + 1); + if (!(msr & 0x8000000000000000)) { + if (bootverbose) + device_printf(dev, "P1 not supported by hardware.\n"); + return (ENODEV); + } + sc = device_get_softc(dev); + ps = sc->pstate_settings; + for (i = 0; i < sc->cfnum; i++, ps++) + if (cf->freq == ps->freq) { + break; + } + setfreq = ps->freq; + if (i == sc->cfnum) { + if (bootverbose) + device_printf(dev, "%d MHz is not supported.\n", + cf->freq); + return (EINVAL); + } + /* go to P0 */ + wrmsr(MSR_PSTATE_CONTROL, 0); + DELAY(3000); + if (setfreq / 100 == sc->mof_id) { + if (bootverbose) + device_printf(dev, "going back to default setting.\n"); + for (i = 1; i < 5; i++) + wrmsr(MSR_PSTATE_CONFIG + i, sc->backup[i]); + return (0); + } + /* copy config val from P0 to P1 */ + msr = rdmsr(MSR_PSTATE_CONFIG); + wrmsr(MSR_PSTATE_CONFIG + 1, msr); + /* make pstate */ + id = sc->mof_id - i - 1; + msr = PSTATE_MK_PSTATE(msr, pstate_vid_list[id], sc->mult); + wrmsr(MSR_PSTATE_CONFIG + 1, msr); + if (bootverbose) + device_printf(dev, "going to %dMHz\n", setfreq); + /* go to P1 */ + wrmsr(MSR_PSTATE_CONTROL, 1); + for (i = 0; i < 1000; i++) { + DELAY(3000); + curfreq = pstate_cur_cpu_freq(); + curvolts = pstate_cur_cpu_volts(sc->mult); + if (setfreq == curfreq) + break; + } + if (setfreq != curfreq && bootverbose) { + device_printf(dev, "current %dMHz and set %dMHz differ.\n", + curfreq, setfreq); + return (0); + } + if (bootverbose) + device_printf(dev, "Now: %d MHz %d mV\n", curfreq, curvolts); + + msr = rdmsr(MSR_PSTATE_STATUS); + if (msr != 1 && bootverbose) + device_printf(dev, "P1 is not enabled.\n"); + return (0); +} + +static int +pstate_get(device_t dev, struct cf_setting *cf) +{ + struct pstate_softc *sc; + sc = device_get_softc(dev); + if (cf == NULL) + return (EINVAL); + cf->freq = pstate_cur_cpu_freq(); + cf->volts = pstate_cur_cpu_volts(sc->mult); + cf->power = CPUFREQ_VAL_UNKNOWN; + cf->lat = 16; + cf->dev = dev; + return (0); +} + +static int +pstate_settings(device_t dev, struct cf_setting *sets, int *count) +{ + struct pstate_softc *sc; + 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++) { + sets->freq = sc->pstate_settings[i].freq; + sets->volts = sc->pstate_settings[i].volts; + sets->power = sc->pstate_settings[i].power; + sets->lat = sc->pstate_settings[i].lat; + sets->dev = sc->pstate_settings[i].dev; + } + *count = sc->cfnum; + return (0); +} + +static int +pstate_type(device_t dev, int *type) +{ + + if (type == NULL) + return (EINVAL); + *type = CPUFREQ_TYPE_ABSOLUTE; + return (0); +} + +static int +pstate_is_capable(void) +{ + u_int regs[4]; + if (strcmp(cpu_vendor, "AuthenticAMD") != 0 || + cpu_exthigh < 0x80000007) + return (FALSE); + switch (cpu_id) { + case 0x100f2A: + case 0x100f22: + case 0x100f23: + break; + default: + return (FALSE); + } + do_cpuid(0x80000007, regs); + if (regs[3] & 0x80) { + return (TRUE); + } + return (FALSE); +} + +static void +pstate_identify(driver_t * driver, device_t parent) +{ + device_t child; + if (device_find_child(parent, "pstate", -1) != NULL) + return; + if (pstate_is_capable() == FALSE) + return; + if ((child = BUS_ADD_CHILD(parent, 10, "pstate", -1)) == NULL) + device_printf(parent, "pstate: add child failed\n"); +} + +static int +pstate_probe(device_t dev) +{ + device_t perf_dev; + int error, type; + if (resource_disabled("pstate", 0)) + 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); + } + device_set_desc(dev, "Cool`n'Quiet 2.0"); + return (0); +} + +static int +pstate_attach(device_t dev) +{ + struct pstate_softc *sc; + uint64_t msr; + uint32_t cfg; + int i , j, listvid; + u_int regs[4], reg; + char cpu_model[48], *p = cpu_model; + sc = device_get_softc(dev); + for (i = 0; i < 5; i++) + sc->backup[i] = rdmsr(MSR_PSTATE_CONFIG + i); + msr = rdmsr(MSR_PSTATE_COFVID); + sc->mof_id = MSR_PSTATE_MOF(msr) / 100; + if (sc->mof_id == 0) { + for (i = 0; i < 3; i++) { + do_cpuid(0x80000002 + i, regs); + for (j = 0; j < 4; j++) { + reg = regs[j]; + *p++ = (char)(reg & 0xff); + *p++ = (char)((reg >> 8) & 0xff); + *p++ = (char)((reg >> 16) & 0xff); + *p++ = (char)((reg >> 24) & 0xff); + } + } + if (strstr(cpu_model, "Phenom")) { + if (strstr(cpu_model, "9600")) { + sc->mof_id = 23; /* 2.3 GHz */ + } else if (strstr(cpu_model, "9850")) { + sc->mof_id = 25; /* 2.5 GHz */ + } else if (strstr(cpu_model, "9350e")) { + sc->mof_id = 25; /* 2.5 GHz */ + } else if (strstr(cpu_model, "9950")) { + sc->mof_id = 26; /* 2.6 GHz */ + } + } + if (sc->mof_id == 0) { + device_printf(dev,"msr = %x\n",msr); + device_printf(dev,"cpu = %s\n",cpu_model); + device_printf(dev,"no limit of max freq.\n"); + device_printf(dev,"change lines near the \"Phenom\" ,sorry :)\n"); + return (ENODEV); + } + } + /* if 2500,..600,500,400 MHz => sc->mof_id=25; sc->cfnum=22; */ + sc->cfnum = sc->mof_id - 3; + /** + * following 24 means the 1st cpu. 25-31 instead of 24 is MP system. + * I don't have MP system :-< . + * But only for reading , so MP system will work? + */ + sc->F3 = pci_find_bsf(0, 24, 3); + cfg = pci_read_config(sc->F3, 0xA0, 4); + if (cfg & 0x10) /* PVI mode */ + sc->mult = 1; + else /* SVI mode */ + sc->mult = 2; + for (i = 0; i < sc->cfnum; i++) { + sc->pstate_settings[i].freq = 100 * (sc->mof_id - i); + listvid = pstate_vid_list[sc->mof_id - i]; + sc->pstate_settings[i].volts = PSTATE_LISTVID_TO_VOLTS(listvid); + sc->pstate_settings[i].power = CPUFREQ_VAL_UNKNOWN; + sc->pstate_settings[i].lat = 16; + sc->pstate_settings[i].dev = dev; + } + cpufreq_register(dev); + return (0); +} + +static int +pstate_detach(device_t dev) +{ + struct pstate_softc *sc; + int new; + sc = device_get_softc(dev); + new = sc->mof_id * 100; + if (new != 0) + kernel_sysctlbyname(&thread0, "dev.cpu.0.freq", + 0, 0, &new, sizeof(new), NULL, 0); + return (cpufreq_unregister(dev)); +} + +static int +pstate_shutdown(device_t dev) +{ + struct pstate_softc *sc; + int new; + sc = device_get_softc(dev); + new = sc->mof_id * 100; + if (new != 0) + kernel_sysctlbyname(&thread0, "dev.cpu.0.freq", + 0, 0, &new, sizeof(new), NULL, 0); + return (0); +} + +static int +pstate_features(driver_t * driver, u_int * features) +{ + + *features = ACPI_CAP_PERF_MSRS; + return (0); +} Regards, G. Otsuji<annona2@gmail.com>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809232307.m8NN79th001888>