Re: AMD Family 10h cpufreq driver

From: G .Otsuji <annona2_at_gmail.com>
Date: Wed, 24 Sep 2008 08:07:09 +0900
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
_at__at_ -0,0 +1,448 _at__at_
+/*-
+ * 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>
Received on Tue Sep 23 2008 - 21:07:24 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:35 UTC