AMD Family 10h cpufreq driver
G .Otsuji
annona2 at gmail.com
Tue Sep 23 23:07:24 UTC 2008
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 at gmail.com>
More information about the freebsd-current
mailing list