AMD Family 10h cpufreq driver
fluffles.net
bsd at fluffles.net
Wed Sep 24 00:45:34 UTC 2008
G .Otsuji wrote:
> Could you please try following patch to isolate the problem ,
>
Hi G. Otsuji,
Thanks for the tip. One thing though, you forgot to alter the setting
for 9350e in your patch:
+ } else if (strstr(cpu_model, "9350e")) {
+ sc->mof_id = 25; /* 2.5 GHz */
should be:
+ } else if (strstr(cpu_model, "9350e")) {
+ sc->mof_id = 20; /* 2.0 GHz */
Else it'll try to run your cpu at 2.5GHz which i'm not sure it will like. :)
For a complete addition of all Phenom models, i created the following list:
+ if (strstr(cpu_model, "Phenom")) {
+ if (strstr(cpu_model, "9100")) {
+ sc->mof_id = 18; /* 1.8 GHz */
+ } else if (strstr(cpu_model, "9150e")) {
+ sc->mof_id = 18; /* 1.8 GHz */
+ } else if (strstr(cpu_model, "9300e")) {
+ sc->mof_id = 20; /* 2.0 GHz */
+ } else if (strstr(cpu_model, "9350e")) {
+ sc->mof_id = 20; /* 2.0 GHz */
+ } else if (strstr(cpu_model, "9500")) {
+ sc->mof_id = 22; /* 2.2 GHz */
+ } else if (strstr(cpu_model, "9550")) {
+ sc->mof_id = 22; /* 2.2 GHz */
+ } else if (strstr(cpu_model, "9600")) {
+ sc->mof_id = 23; /* 2.3 GHz */
+ } else if (strstr(cpu_model, "9650")) {
+ sc->mof_id = 23; /* 2.3 GHz */
+ } else if (strstr(cpu_model, "9700")) {
+ sc->mof_id = 24; /* 2.4 GHz */
+ } else if (strstr(cpu_model, "9750")) {
+ sc->mof_id = 24; /* 2.4 GHz */
+ } else if (strstr(cpu_model, "9800")) {
+ sc->mof_id = 25; /* 2.5 GHz */
+ } else if (strstr(cpu_model, "9850")) {
+ sc->mof_id = 25; /* 2.5 GHz */
+ } else if (strstr(cpu_model, "9900")) {
+ sc->mof_id = 26; /* 2.6 GHz */
+ } else if (strstr(cpu_model, "9950")) {
+ sc->mof_id = 26; /* 2.6 GHz */
+ } else if (strstr(cpu_model, "8250e")) {
+ sc->mof_id = 19; /* 1.9 GHz */
+ } else if (strstr(cpu_model, "8400")) {
+ sc->mof_id = 21; /* 2.1 GHz */
+ } else if (strstr(cpu_model, "8450")) {
+ sc->mof_id = 21; /* 2.1 GHz */
+ } else if (strstr(cpu_model, "8450e")) {
+ sc->mof_id = 21; /* 2.1 GHz */
+ } else if (strstr(cpu_model, "8600")) {
+ sc->mof_id = 23; /* 2.3 GHz */
+ } else if (strstr(cpu_model, "8650")) {
+ sc->mof_id = 23; /* 2.3 GHz */
+ } else if (strstr(cpu_model, "8700")) {
+ sc->mof_id = 24; /* 2.4 GHz */
+ } else if (strstr(cpu_model, "8750")) {
+ sc->mof_id = 24; /* 2.4 GHz */
+ } else if (strstr(cpu_model, "8400")) {
+ sc->mof_id = 26; /* 2.6 GHz */
+ } else if (strstr(cpu_model, "8450")) {
+ sc->mof_id = 26; /* 2.6 GHz */
+ } else if (strstr(cpu_model, "6400")) {
+ sc->mof_id = 19; /* 1.9 GHz */
+ } else if (strstr(cpu_model, "6500")) {
+ sc->mof_id = 21; /* 2.1 GHz */
+ } else if (strstr(cpu_model, "6600")) {
+ sc->mof_id = 23; /* 2.3 GHz */
+ }
+ }
The 9000-series are Quadcore, the 8000-series are Tripe-core, the 6000-series are Dualcore. Source:
http://en.wikipedia.org/wiki/List_of_AMD_Phenom_microprocessors
Good luck with your driver!
Kind Regards,
Veronica
> 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>
>
> _______________________________________________
> freebsd-current at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-current
> To unsubscribe, send any mail to "freebsd-current-unsubscribe at freebsd.org"
>
>
More information about the freebsd-current
mailing list