From owner-freebsd-current@FreeBSD.ORG Tue Sep 23 23:07:24 2008 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4DCA11065677 for ; Tue, 23 Sep 2008 23:07:24 +0000 (UTC) (envelope-from annona2@gmail.com) Received: from ti-out-0910.google.com (ti-out-0910.google.com [209.85.142.186]) by mx1.freebsd.org (Postfix) with ESMTP id 8A6318FC13 for ; Tue, 23 Sep 2008 23:07:23 +0000 (UTC) (envelope-from annona2@gmail.com) Received: by ti-out-0910.google.com with SMTP id d27so1279243tid.3 for ; Tue, 23 Sep 2008 16:07:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:message-id:date:from :to:cc:subject:in-reply-to:references:user-agent:mime-version :content-type; bh=VtTaSvanzjEkqZENod4cFZoXCgeXupnPUZStgWw3vKU=; b=EQ4WGau5wj7e6JXLYePOsw8ujQ1yqDCK29iwM0fftiR8emmInWSMUMd7XDGTlZUSRP WBXtXMePQ+S1mFZrRBSeKfdLwCdspTxJpI3NvNeHgC7oBuAWB67arBvhAcD5cXAn6UG/ RzzIuf8v2XmTthV6g+8K3jlPoAIz5wlQt0taI= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:cc:subject:in-reply-to:references :user-agent:mime-version:content-type; b=r/KtmACG4hjBGn9T0JWDqQALDqVI6l3FwFZ4ESNRTWBdl11x2GjBcqou7ym/xbbsJP OfLK1BGKjNAnfDkX1ff1T+SrBoI32aMmhZTL8Exmp6wWL4wF+BKijS3AabYbN875ZmhK LK3SmtYOrNPUpF7aPIjnBrAnxsyzFZANOF7ZU= Received: by 10.110.40.8 with SMTP id n8mr5485846tin.50.1222211242354; Tue, 23 Sep 2008 16:07:22 -0700 (PDT) Received: from softbank219001162114.bbtec.net ( [219.1.162.114]) by mx.google.com with ESMTPS id y5sm2471489tia.15.2008.09.23.16.07.11 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 23 Sep 2008 16:07:21 -0700 (PDT) Received: from softbank219001162114.bbtec.net (localhost [127.0.0.1]) by softbank219001162114.bbtec.net (8.14.3/8.14.3) with ESMTP id m8NN79th001888; Wed, 24 Sep 2008 08:07:09 +0900 (JST) (envelope-from annona2@gmail.com) Message-Id: <200809232307.m8NN79th001888@softbank219001162114.bbtec.net> Date: Wed, 24 Sep 2008 08:07:09 +0900 From: "G .Otsuji" To: "Poul-Henning Kamp" In-Reply-To: <26111.1222205043@critter.freebsd.dk> References: <200809232121.m8NLLnig001691@softbank219001162114.bbtec.net> <26111.1222205043@critter.freebsd.dk> User-Agent: Wanderlust/2.15.5 (Almost Unreal) SEMI/1.14.6 (Maruoka) FLIM/1.14.8 (=?ISO-8859-4?Q?Shij=F2?=) APEL/10.7 Emacs/22.2 (i386-portbld-freebsd7.1) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset=US-ASCII Cc: "G .Otsuji" , FreeBSD Current Subject: Re: AMD Family 10h cpufreq driver X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Sep 2008 23:07:24 -0000 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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