Date: Wed, 24 Sep 2008 02:48:02 +0200 From: "fluffles.net" <bsd@fluffles.net> To: "G .Otsuji" <annona2@gmail.com> Cc: Poul-Henning Kamp <phk@phk.freebsd.dk>, FreeBSD Current <freebsd-current@freebsd.org> Subject: Re: AMD Family 10h cpufreq driver Message-ID: <48D98E42.5040801@fluffles.net> In-Reply-To: <200809232307.m8NN79th001888@softbank219001162114.bbtec.net> References: <200809232121.m8NLLnig001691@softbank219001162114.bbtec.net> <26111.1222205043@critter.freebsd.dk> <200809232307.m8NN79th001888@softbank219001162114.bbtec.net>
next in thread | previous in thread | raw e-mail | index | archive | help
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@gmail.com> > > _______________________________________________ > freebsd-current@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-current > To unsubscribe, send any mail to "freebsd-current-unsubscribe@freebsd.org" > >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?48D98E42.5040801>