1/*- 2 * Copyright (c) 2004-2005 Bruno Ducrot 3 * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26/* 27 * Many thanks to Nate Lawson for his helpful comments on this driver and 28 * to Jung-uk Kim for testing. 29 */ 30 31#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2004-2005 Bruno Ducrot 3 * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26/* 27 * Many thanks to Nate Lawson for his helpful comments on this driver and 28 * to Jung-uk Kim for testing. 29 */ 30 31#include <sys/cdefs.h>
|
32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 158651 2006-05-16 14:37:58Z phk $");
| 32__FBSDID("$FreeBSD: head/sys/i386/cpufreq/powernow.c 166197 2007-01-23 19:20:30Z bruno $");
|
33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/cpu.h> 37#include <sys/kernel.h> 38#include <sys/malloc.h> 39#include <sys/module.h> 40#include <sys/pcpu.h> 41#include <sys/systm.h> 42 43#include <machine/pc/bios.h> 44#include <machine/md_var.h> 45#include <machine/specialreg.h> 46#include <machine/cputypes.h> 47#include <machine/vmparam.h> 48#include <sys/rman.h> 49 50#include <vm/vm.h> 51#include <vm/pmap.h> 52 53#include "cpufreq_if.h" 54 55#define PN7_TYPE 0 56#define PN8_TYPE 1 57
| 33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/cpu.h> 37#include <sys/kernel.h> 38#include <sys/malloc.h> 39#include <sys/module.h> 40#include <sys/pcpu.h> 41#include <sys/systm.h> 42 43#include <machine/pc/bios.h> 44#include <machine/md_var.h> 45#include <machine/specialreg.h> 46#include <machine/cputypes.h> 47#include <machine/vmparam.h> 48#include <sys/rman.h> 49 50#include <vm/vm.h> 51#include <vm/pmap.h> 52 53#include "cpufreq_if.h" 54 55#define PN7_TYPE 0 56#define PN8_TYPE 1 57
|
| 58/* Flags for some hardware bugs. */ 59#define A0_ERRATA 0x1 /* Bugs for the rev. A0 of Athlon (K7): 60 * Interrupts must be disabled and no half 61 * multipliers are allowed */ 62#define PENDING_STUCK 0x2 /* With some buggy chipset and some newer AMD64 63 * processor (Rev. G?): 64 * the pending bit from the msr FIDVID_STATUS 65 * is set forever. No workaround :( */ 66
|
58/* Legacy configuration via BIOS table PSB. */ 59#define PSB_START 0 60#define PSB_STEP 0x10 61#define PSB_SIG "AMDK7PNOW!" 62#define PSB_LEN 10 63#define PSB_OFF 0 64 65struct psb_header { 66 char signature[10]; 67 uint8_t version; 68 uint8_t flags; 69 uint16_t settlingtime; 70 uint8_t res1; 71 uint8_t numpst; 72} __packed; 73 74struct pst_header { 75 uint32_t cpuid; 76 uint8_t fsb; 77 uint8_t maxfid; 78 uint8_t startvid; 79 uint8_t numpstates; 80} __packed; 81 82/* 83 * MSRs and bits used by Powernow technology 84 */ 85#define MSR_AMDK7_FIDVID_CTL 0xc0010041 86#define MSR_AMDK7_FIDVID_STATUS 0xc0010042 87 88/* Bitfields used by K7 */ 89 90#define PN7_CTR_FID(x) ((x) & 0x1f) 91#define PN7_CTR_VID(x) (((x) & 0x1f) << 8) 92#define PN7_CTR_FIDC 0x00010000 93#define PN7_CTR_VIDC 0x00020000 94#define PN7_CTR_FIDCHRATIO 0x00100000 95#define PN7_CTR_SGTC(x) (((uint64_t)(x) & 0x000fffff) << 32) 96 97#define PN7_STA_CFID(x) ((x) & 0x1f) 98#define PN7_STA_SFID(x) (((x) >> 8) & 0x1f) 99#define PN7_STA_MFID(x) (((x) >> 16) & 0x1f) 100#define PN7_STA_CVID(x) (((x) >> 32) & 0x1f) 101#define PN7_STA_SVID(x) (((x) >> 40) & 0x1f) 102#define PN7_STA_MVID(x) (((x) >> 48) & 0x1f) 103 104/* ACPI ctr_val status register to powernow k7 configuration */ 105#define ACPI_PN7_CTRL_TO_FID(x) ((x) & 0x1f) 106#define ACPI_PN7_CTRL_TO_VID(x) (((x) >> 5) & 0x1f) 107#define ACPI_PN7_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff) 108 109/* Bitfields used by K8 */ 110 111#define PN8_CTR_FID(x) ((x) & 0x3f) 112#define PN8_CTR_VID(x) (((x) & 0x1f) << 8) 113#define PN8_CTR_PENDING(x) (((x) & 1) << 32) 114 115#define PN8_STA_CFID(x) ((x) & 0x3f) 116#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f) 117#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f) 118#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01) 119#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f) 120#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f) 121#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f) 122 123/* Reserved1 to powernow k8 configuration */ 124#define PN8_PSB_TO_RVO(x) ((x) & 0x03) 125#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03) 126#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03) 127#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03) 128 129/* ACPI ctr_val status register to powernow k8 configuration */ 130#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f) 131#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f) 132#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f) 133#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03) 134#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f) 135#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03) 136#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03) 137 138 139#define WRITE_FIDVID(fid, vid, ctrl) \ 140 wrmsr(MSR_AMDK7_FIDVID_CTL, \ 141 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) 142
| 67/* Legacy configuration via BIOS table PSB. */ 68#define PSB_START 0 69#define PSB_STEP 0x10 70#define PSB_SIG "AMDK7PNOW!" 71#define PSB_LEN 10 72#define PSB_OFF 0 73 74struct psb_header { 75 char signature[10]; 76 uint8_t version; 77 uint8_t flags; 78 uint16_t settlingtime; 79 uint8_t res1; 80 uint8_t numpst; 81} __packed; 82 83struct pst_header { 84 uint32_t cpuid; 85 uint8_t fsb; 86 uint8_t maxfid; 87 uint8_t startvid; 88 uint8_t numpstates; 89} __packed; 90 91/* 92 * MSRs and bits used by Powernow technology 93 */ 94#define MSR_AMDK7_FIDVID_CTL 0xc0010041 95#define MSR_AMDK7_FIDVID_STATUS 0xc0010042 96 97/* Bitfields used by K7 */ 98 99#define PN7_CTR_FID(x) ((x) & 0x1f) 100#define PN7_CTR_VID(x) (((x) & 0x1f) << 8) 101#define PN7_CTR_FIDC 0x00010000 102#define PN7_CTR_VIDC 0x00020000 103#define PN7_CTR_FIDCHRATIO 0x00100000 104#define PN7_CTR_SGTC(x) (((uint64_t)(x) & 0x000fffff) << 32) 105 106#define PN7_STA_CFID(x) ((x) & 0x1f) 107#define PN7_STA_SFID(x) (((x) >> 8) & 0x1f) 108#define PN7_STA_MFID(x) (((x) >> 16) & 0x1f) 109#define PN7_STA_CVID(x) (((x) >> 32) & 0x1f) 110#define PN7_STA_SVID(x) (((x) >> 40) & 0x1f) 111#define PN7_STA_MVID(x) (((x) >> 48) & 0x1f) 112 113/* ACPI ctr_val status register to powernow k7 configuration */ 114#define ACPI_PN7_CTRL_TO_FID(x) ((x) & 0x1f) 115#define ACPI_PN7_CTRL_TO_VID(x) (((x) >> 5) & 0x1f) 116#define ACPI_PN7_CTRL_TO_SGTC(x) (((x) >> 10) & 0xffff) 117 118/* Bitfields used by K8 */ 119 120#define PN8_CTR_FID(x) ((x) & 0x3f) 121#define PN8_CTR_VID(x) (((x) & 0x1f) << 8) 122#define PN8_CTR_PENDING(x) (((x) & 1) << 32) 123 124#define PN8_STA_CFID(x) ((x) & 0x3f) 125#define PN8_STA_SFID(x) (((x) >> 8) & 0x3f) 126#define PN8_STA_MFID(x) (((x) >> 16) & 0x3f) 127#define PN8_STA_PENDING(x) (((x) >> 31) & 0x01) 128#define PN8_STA_CVID(x) (((x) >> 32) & 0x1f) 129#define PN8_STA_SVID(x) (((x) >> 40) & 0x1f) 130#define PN8_STA_MVID(x) (((x) >> 48) & 0x1f) 131 132/* Reserved1 to powernow k8 configuration */ 133#define PN8_PSB_TO_RVO(x) ((x) & 0x03) 134#define PN8_PSB_TO_IRT(x) (((x) >> 2) & 0x03) 135#define PN8_PSB_TO_MVS(x) (((x) >> 4) & 0x03) 136#define PN8_PSB_TO_BATT(x) (((x) >> 6) & 0x03) 137 138/* ACPI ctr_val status register to powernow k8 configuration */ 139#define ACPI_PN8_CTRL_TO_FID(x) ((x) & 0x3f) 140#define ACPI_PN8_CTRL_TO_VID(x) (((x) >> 6) & 0x1f) 141#define ACPI_PN8_CTRL_TO_VST(x) (((x) >> 11) & 0x1f) 142#define ACPI_PN8_CTRL_TO_MVS(x) (((x) >> 18) & 0x03) 143#define ACPI_PN8_CTRL_TO_PLL(x) (((x) >> 20) & 0x7f) 144#define ACPI_PN8_CTRL_TO_RVO(x) (((x) >> 28) & 0x03) 145#define ACPI_PN8_CTRL_TO_IRT(x) (((x) >> 30) & 0x03) 146 147 148#define WRITE_FIDVID(fid, vid, ctrl) \ 149 wrmsr(MSR_AMDK7_FIDVID_CTL, \ 150 (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) 151
|
143#define READ_PENDING_WAIT(status) \ 144 do { \ 145 (status) = rdmsr(MSR_AMDK7_FIDVID_STATUS); \ 146 } while (PN8_STA_PENDING(status)) 147
| |
148#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt))) 149#define COUNT_OFF_VST(vst) DELAY(20 * (vst)) 150 151#define FID_TO_VCO_FID(fid) \ 152 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) 153 154/* 155 * Divide each value by 10 to get the processor multiplier. 156 * Some of those tables are the same as the Linux powernow-k7 157 * implementation by Dave Jones. 158 */ 159static int pn7_fid_to_mult[32] = { 160 110, 115, 120, 125, 50, 55, 60, 65, 161 70, 75, 80, 85, 90, 95, 100, 105, 162 30, 190, 40, 200, 130, 135, 140, 210, 163 150, 225, 160, 165, 170, 180, 0, 0, 164}; 165 166
| 152#define COUNT_OFF_IRT(irt) DELAY(10 * (1 << (irt))) 153#define COUNT_OFF_VST(vst) DELAY(20 * (vst)) 154 155#define FID_TO_VCO_FID(fid) \ 156 (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) 157 158/* 159 * Divide each value by 10 to get the processor multiplier. 160 * Some of those tables are the same as the Linux powernow-k7 161 * implementation by Dave Jones. 162 */ 163static int pn7_fid_to_mult[32] = { 164 110, 115, 120, 125, 50, 55, 60, 65, 165 70, 75, 80, 85, 90, 95, 100, 105, 166 30, 190, 40, 200, 130, 135, 140, 210, 167 150, 225, 160, 165, 170, 180, 0, 0, 168}; 169 170
|
167static int pn8_fid_to_mult[32] = { 168 40, 50, 60, 70, 80, 90, 100, 110, 169 120, 130, 140, 150, 160, 170, 180, 190, 170 220, 230, 240, 250, 260, 270, 280, 290, 171 300, 310, 320, 330, 340, 350,
| 171static int pn8_fid_to_mult[64] = { 172 40, 45, 50, 55, 60, 65, 70, 75, 173 80, 85, 90, 95, 100, 105, 110, 115, 174 120, 125, 130, 135, 140, 145, 150, 155, 175 160, 165, 170, 175, 180, 185, 190, 195, 176 200, 205, 210, 215, 220, 225, 230, 235, 177 240, 245, 250, 255, 260, 265, 270, 275, 178 280, 285, 290, 295, 300, 305, 310, 315, 179 320, 325, 330, 335, 340, 345, 350, 355,
|
172}; 173 174/* 175 * Units are in mV. 176 */ 177/* Mobile VRM (K7) */ 178static int pn7_mobile_vid_to_volts[] = { 179 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 180 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 181 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 182 1075, 1050, 1025, 1000, 975, 950, 925, 0, 183}; 184/* Desktop VRM (K7) */ 185static int pn7_desktop_vid_to_volts[] = { 186 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 187 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 188 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 189 1075, 1050, 1025, 1000, 975, 950, 925, 0, 190}; 191/* Desktop and Mobile VRM (K8) */ 192static int pn8_vid_to_volts[] = { 193 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375, 194 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175, 195 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 196 950, 925, 900, 875, 850, 825, 800, 0, 197}; 198 199#define POWERNOW_MAX_STATES 16 200 201struct powernow_state { 202 int freq; 203 int power; 204 int fid; 205 int vid; 206}; 207 208struct pn_softc { 209 device_t dev; 210 int pn_type; 211 struct powernow_state powernow_states[POWERNOW_MAX_STATES]; 212 u_int fsb; 213 u_int sgtc; 214 u_int vst; 215 u_int mvs; 216 u_int pll; 217 u_int rvo; 218 u_int irt; 219 int low; 220 int powernow_max_states; 221 u_int powernow_state;
| 180}; 181 182/* 183 * Units are in mV. 184 */ 185/* Mobile VRM (K7) */ 186static int pn7_mobile_vid_to_volts[] = { 187 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 188 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 189 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 190 1075, 1050, 1025, 1000, 975, 950, 925, 0, 191}; 192/* Desktop VRM (K7) */ 193static int pn7_desktop_vid_to_volts[] = { 194 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 195 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 196 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 197 1075, 1050, 1025, 1000, 975, 950, 925, 0, 198}; 199/* Desktop and Mobile VRM (K8) */ 200static int pn8_vid_to_volts[] = { 201 1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375, 202 1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175, 203 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 204 950, 925, 900, 875, 850, 825, 800, 0, 205}; 206 207#define POWERNOW_MAX_STATES 16 208 209struct powernow_state { 210 int freq; 211 int power; 212 int fid; 213 int vid; 214}; 215 216struct pn_softc { 217 device_t dev; 218 int pn_type; 219 struct powernow_state powernow_states[POWERNOW_MAX_STATES]; 220 u_int fsb; 221 u_int sgtc; 222 u_int vst; 223 u_int mvs; 224 u_int pll; 225 u_int rvo; 226 u_int irt; 227 int low; 228 int powernow_max_states; 229 u_int powernow_state;
|
222 int errata_a0;
| 230 u_int errata;
|
223 int *vid_to_volts; 224}; 225 226/* 227 * Offsets in struct cf_setting array for private values given by 228 * acpi_perf driver. 229 */ 230#define PX_SPEC_CONTROL 0 231#define PX_SPEC_STATUS 1 232 233static void pn_identify(driver_t *driver, device_t parent); 234static int pn_probe(device_t dev); 235static int pn_attach(device_t dev); 236static int pn_detach(device_t dev); 237static int pn_set(device_t dev, const struct cf_setting *cf); 238static int pn_get(device_t dev, struct cf_setting *cf); 239static int pn_settings(device_t dev, struct cf_setting *sets, 240 int *count); 241static int pn_type(device_t dev, int *type); 242 243static device_method_t pn_methods[] = { 244 /* Device interface */ 245 DEVMETHOD(device_identify, pn_identify), 246 DEVMETHOD(device_probe, pn_probe), 247 DEVMETHOD(device_attach, pn_attach), 248 DEVMETHOD(device_detach, pn_detach), 249 250 /* cpufreq interface */ 251 DEVMETHOD(cpufreq_drv_set, pn_set), 252 DEVMETHOD(cpufreq_drv_get, pn_get), 253 DEVMETHOD(cpufreq_drv_settings, pn_settings), 254 DEVMETHOD(cpufreq_drv_type, pn_type), 255 256 {0, 0} 257}; 258 259static devclass_t pn_devclass; 260static driver_t pn_driver = { 261 "powernow", 262 pn_methods, 263 sizeof(struct pn_softc), 264}; 265 266DRIVER_MODULE(powernow, cpu, pn_driver, pn_devclass, 0, 0); 267 268static int 269pn7_setfidvid(struct pn_softc *sc, int fid, int vid) 270{ 271 int cfid, cvid; 272 uint64_t status, ctl; 273 274 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 275 cfid = PN7_STA_CFID(status); 276 cvid = PN7_STA_CVID(status); 277 278 /* We're already at the requested level. */ 279 if (fid == cfid && vid == cvid) 280 return (0); 281 282 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO; 283 284 ctl |= PN7_CTR_FID(fid); 285 ctl |= PN7_CTR_VID(vid); 286 ctl |= PN7_CTR_SGTC(sc->sgtc); 287
| 231 int *vid_to_volts; 232}; 233 234/* 235 * Offsets in struct cf_setting array for private values given by 236 * acpi_perf driver. 237 */ 238#define PX_SPEC_CONTROL 0 239#define PX_SPEC_STATUS 1 240 241static void pn_identify(driver_t *driver, device_t parent); 242static int pn_probe(device_t dev); 243static int pn_attach(device_t dev); 244static int pn_detach(device_t dev); 245static int pn_set(device_t dev, const struct cf_setting *cf); 246static int pn_get(device_t dev, struct cf_setting *cf); 247static int pn_settings(device_t dev, struct cf_setting *sets, 248 int *count); 249static int pn_type(device_t dev, int *type); 250 251static device_method_t pn_methods[] = { 252 /* Device interface */ 253 DEVMETHOD(device_identify, pn_identify), 254 DEVMETHOD(device_probe, pn_probe), 255 DEVMETHOD(device_attach, pn_attach), 256 DEVMETHOD(device_detach, pn_detach), 257 258 /* cpufreq interface */ 259 DEVMETHOD(cpufreq_drv_set, pn_set), 260 DEVMETHOD(cpufreq_drv_get, pn_get), 261 DEVMETHOD(cpufreq_drv_settings, pn_settings), 262 DEVMETHOD(cpufreq_drv_type, pn_type), 263 264 {0, 0} 265}; 266 267static devclass_t pn_devclass; 268static driver_t pn_driver = { 269 "powernow", 270 pn_methods, 271 sizeof(struct pn_softc), 272}; 273 274DRIVER_MODULE(powernow, cpu, pn_driver, pn_devclass, 0, 0); 275 276static int 277pn7_setfidvid(struct pn_softc *sc, int fid, int vid) 278{ 279 int cfid, cvid; 280 uint64_t status, ctl; 281 282 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 283 cfid = PN7_STA_CFID(status); 284 cvid = PN7_STA_CVID(status); 285 286 /* We're already at the requested level. */ 287 if (fid == cfid && vid == cvid) 288 return (0); 289 290 ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO; 291 292 ctl |= PN7_CTR_FID(fid); 293 ctl |= PN7_CTR_VID(vid); 294 ctl |= PN7_CTR_SGTC(sc->sgtc); 295
|
288 if (sc->errata_a0)
| 296 if (sc->errata & A0_ERRATA)
|
289 disable_intr(); 290 291 if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) { 292 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 293 if (vid != cvid) 294 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 295 } else { 296 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 297 if (fid != cfid) 298 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 299 } 300
| 297 disable_intr(); 298 299 if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) { 300 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 301 if (vid != cvid) 302 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 303 } else { 304 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); 305 if (fid != cfid) 306 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); 307 } 308
|
301 if (sc->errata_a0)
| 309 if (sc->errata & A0_ERRATA)
|
302 enable_intr(); 303 304 return (0); 305} 306 307static int
| 310 enable_intr(); 311 312 return (0); 313} 314 315static int
|
| 316pn8_read_pending_wait(uint64_t *status) 317{ 318 int i = 10000; 319 320 do 321 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 322 while (PN8_STA_PENDING(*status) && --i); 323 324 return (i == 0 ? ENXIO : 0); 325} 326 327static int 328pn8_write_fidvid(u_int fid, u_int vid, uint64_t ctrl, uint64_t *status) 329{ 330 int i = 100; 331 332 do 333 WRITE_FIDVID(fid, vid, ctrl); 334 while (pn8_read_pending_wait(status) && --i); 335 336 return (i == 0 ? ENXIO : 0); 337} 338 339static int
|
308pn8_setfidvid(struct pn_softc *sc, int fid, int vid) 309{ 310 uint64_t status; 311 int cfid, cvid; 312 int rvo;
| 340pn8_setfidvid(struct pn_softc *sc, int fid, int vid) 341{ 342 uint64_t status; 343 int cfid, cvid; 344 int rvo;
|
| 345 int rv;
|
313 u_int val; 314
| 346 u_int val; 347
|
315 READ_PENDING_WAIT(status);
| 348 rv = pn8_read_pending_wait(&status); 349 if (rv) 350 return (rv); 351
|
316 cfid = PN8_STA_CFID(status); 317 cvid = PN8_STA_CVID(status); 318 319 if (fid == cfid && vid == cvid) 320 return (0); 321 322 /* 323 * Phase 1: Raise core voltage to requested VID if frequency is 324 * going up. 325 */ 326 while (cvid > vid) { 327 val = cvid - (1 << sc->mvs);
| 352 cfid = PN8_STA_CFID(status); 353 cvid = PN8_STA_CVID(status); 354 355 if (fid == cfid && vid == cvid) 356 return (0); 357 358 /* 359 * Phase 1: Raise core voltage to requested VID if frequency is 360 * going up. 361 */ 362 while (cvid > vid) { 363 val = cvid - (1 << sc->mvs);
|
328 WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL); 329 READ_PENDING_WAIT(status);
| 364 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status); 365 if (rv) { 366 sc->errata |= PENDING_STUCK; 367 return (rv); 368 }
|
330 cvid = PN8_STA_CVID(status); 331 COUNT_OFF_VST(sc->vst); 332 } 333 334 /* ... then raise to voltage + RVO (if required) */ 335 for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) { 336 /* XXX It's not clear from spec if we have to do that 337 * in 0.25 step or in MVS. Therefore do it as it's done 338 * under Linux */
| 369 cvid = PN8_STA_CVID(status); 370 COUNT_OFF_VST(sc->vst); 371 } 372 373 /* ... then raise to voltage + RVO (if required) */ 374 for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) { 375 /* XXX It's not clear from spec if we have to do that 376 * in 0.25 step or in MVS. Therefore do it as it's done 377 * under Linux */
|
339 WRITE_FIDVID(cfid, cvid - 1, 1ULL); 340 READ_PENDING_WAIT(status);
| 378 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status); 379 if (rv) { 380 sc->errata |= PENDING_STUCK; 381 return (rv); 382 }
|
341 cvid = PN8_STA_CVID(status); 342 COUNT_OFF_VST(sc->vst); 343 } 344 345 /* Phase 2: change to requested core frequency */ 346 if (cfid != fid) {
| 383 cvid = PN8_STA_CVID(status); 384 COUNT_OFF_VST(sc->vst); 385 } 386 387 /* Phase 2: change to requested core frequency */ 388 if (cfid != fid) {
|
347 u_int vco_fid, vco_cfid;
| 389 u_int vco_fid, vco_cfid, fid_delta;
|
348 349 vco_fid = FID_TO_VCO_FID(fid); 350 vco_cfid = FID_TO_VCO_FID(cfid); 351 352 while (abs(vco_fid - vco_cfid) > 2) {
| 390 391 vco_fid = FID_TO_VCO_FID(fid); 392 vco_cfid = FID_TO_VCO_FID(cfid); 393 394 while (abs(vco_fid - vco_cfid) > 2) {
|
| 395 fid_delta = (vco_cfid & 1) ? 1 : 2;
|
353 if (fid > cfid) {
| 396 if (fid > cfid) {
|
354 if (cfid > 6) 355 val = cfid + 2;
| 397 if (cfid > 7) 398 val = cfid + fid_delta;
|
356 else
| 399 else
|
357 val = FID_TO_VCO_FID(cfid) + 2;
| 400 val = FID_TO_VCO_FID(cfid) + fid_delta;
|
358 } else
| 401 } else
|
359 val = cfid - 2; 360 WRITE_FIDVID(val, cvid, sc->pll * (uint64_t) sc->fsb); 361 READ_PENDING_WAIT(status);
| 402 val = cfid - fid_delta; 403 rv = pn8_write_fidvid(val, cvid, 404 sc->pll * (uint64_t) sc->fsb, 405 &status); 406 if (rv) { 407 sc->errata |= PENDING_STUCK; 408 return (rv); 409 }
|
362 cfid = PN8_STA_CFID(status); 363 COUNT_OFF_IRT(sc->irt); 364 365 vco_cfid = FID_TO_VCO_FID(cfid); 366 } 367
| 410 cfid = PN8_STA_CFID(status); 411 COUNT_OFF_IRT(sc->irt); 412 413 vco_cfid = FID_TO_VCO_FID(cfid); 414 } 415
|
368 WRITE_FIDVID(fid, cvid, sc->pll * (uint64_t) sc->fsb); 369 READ_PENDING_WAIT(status);
| 416 rv = pn8_write_fidvid(fid, cvid, 417 sc->pll * (uint64_t) sc->fsb, 418 &status); 419 if (rv) { 420 sc->errata |= PENDING_STUCK; 421 return (rv); 422 }
|
370 cfid = PN8_STA_CFID(status); 371 COUNT_OFF_IRT(sc->irt); 372 } 373 374 /* Phase 3: change to requested voltage */ 375 if (cvid != vid) {
| 423 cfid = PN8_STA_CFID(status); 424 COUNT_OFF_IRT(sc->irt); 425 } 426 427 /* Phase 3: change to requested voltage */ 428 if (cvid != vid) {
|
376 WRITE_FIDVID(cfid, vid, 1ULL); 377 READ_PENDING_WAIT(status);
| 429 rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
|
378 cvid = PN8_STA_CVID(status); 379 COUNT_OFF_VST(sc->vst); 380 } 381 382 /* Check if transition failed. */ 383 if (cfid != fid || cvid != vid)
| 430 cvid = PN8_STA_CVID(status); 431 COUNT_OFF_VST(sc->vst); 432 } 433 434 /* Check if transition failed. */ 435 if (cfid != fid || cvid != vid)
|
384 return (ENXIO);
| 436 rv = ENXIO;
|
385
| 437
|
386 return (0);
| 438 return (rv);
|
387} 388 389static int 390pn_set(device_t dev, const struct cf_setting *cf) 391{ 392 struct pn_softc *sc; 393 int fid, vid; 394 int i; 395 int rv; 396 397 if (cf == NULL) 398 return (EINVAL); 399 sc = device_get_softc(dev); 400
| 439} 440 441static int 442pn_set(device_t dev, const struct cf_setting *cf) 443{ 444 struct pn_softc *sc; 445 int fid, vid; 446 int i; 447 int rv; 448 449 if (cf == NULL) 450 return (EINVAL); 451 sc = device_get_softc(dev); 452
|
| 453 if (sc->errata & PENDING_STUCK) 454 return (ENXIO); 455
|
401 for (i = 0; i < sc->powernow_max_states; ++i) 402 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq)) 403 break; 404 405 fid = sc->powernow_states[i].fid; 406 vid = sc->powernow_states[i].vid; 407 408 rv = ENODEV; 409 410 switch (sc->pn_type) { 411 case PN7_TYPE: 412 rv = pn7_setfidvid(sc, fid, vid); 413 break; 414 case PN8_TYPE: 415 rv = pn8_setfidvid(sc, fid, vid); 416 break; 417 } 418 419 return (rv); 420} 421 422static int 423pn_get(device_t dev, struct cf_setting *cf) 424{ 425 struct pn_softc *sc; 426 u_int cfid = 0, cvid = 0; 427 int i; 428 uint64_t status; 429 430 if (cf == NULL) 431 return (EINVAL); 432 sc = device_get_softc(dev);
| 456 for (i = 0; i < sc->powernow_max_states; ++i) 457 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq)) 458 break; 459 460 fid = sc->powernow_states[i].fid; 461 vid = sc->powernow_states[i].vid; 462 463 rv = ENODEV; 464 465 switch (sc->pn_type) { 466 case PN7_TYPE: 467 rv = pn7_setfidvid(sc, fid, vid); 468 break; 469 case PN8_TYPE: 470 rv = pn8_setfidvid(sc, fid, vid); 471 break; 472 } 473 474 return (rv); 475} 476 477static int 478pn_get(device_t dev, struct cf_setting *cf) 479{ 480 struct pn_softc *sc; 481 u_int cfid = 0, cvid = 0; 482 int i; 483 uint64_t status; 484 485 if (cf == NULL) 486 return (EINVAL); 487 sc = device_get_softc(dev);
|
| 488 if (sc->errata & PENDING_STUCK) 489 return (ENXIO);
|
433 434 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 435 436 switch (sc->pn_type) { 437 case PN7_TYPE: 438 cfid = PN7_STA_CFID(status); 439 cvid = PN7_STA_CVID(status); 440 break; 441 case PN8_TYPE: 442 cfid = PN8_STA_CFID(status); 443 cvid = PN8_STA_CVID(status); 444 break; 445 } 446 for (i = 0; i < sc->powernow_max_states; ++i) 447 if (cfid == sc->powernow_states[i].fid && 448 cvid == sc->powernow_states[i].vid) 449 break; 450 451 if (i < sc->powernow_max_states) { 452 cf->freq = sc->powernow_states[i].freq / 1000; 453 cf->power = sc->powernow_states[i].power; 454 cf->lat = 200; 455 cf->volts = sc->vid_to_volts[cvid]; 456 cf->dev = dev; 457 } else { 458 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 459 cf->dev = NULL; 460 } 461 462 return (0); 463} 464 465static int 466pn_settings(device_t dev, struct cf_setting *sets, int *count) 467{ 468 struct pn_softc *sc; 469 int i; 470 471 if (sets == NULL|| count == NULL) 472 return (EINVAL); 473 sc = device_get_softc(dev); 474 if (*count < sc->powernow_max_states) 475 return (E2BIG); 476 for (i = 0; i < sc->powernow_max_states; ++i) { 477 sets[i].freq = sc->powernow_states[i].freq / 1000; 478 sets[i].power = sc->powernow_states[i].power; 479 sets[i].lat = 200; 480 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid]; 481 sets[i].dev = dev; 482 } 483 *count = sc->powernow_max_states; 484 485 return (0); 486} 487 488static int 489pn_type(device_t dev, int *type) 490{ 491 if (type == NULL) 492 return (EINVAL); 493 494 *type = CPUFREQ_TYPE_ABSOLUTE; 495 496 return (0); 497} 498 499/* 500 * Given a set of pair of fid/vid, and number of performance states, 501 * compute powernow_states via an insertion sort. 502 */ 503static int 504decode_pst(struct pn_softc *sc, uint8_t *p, int npstates) 505{ 506 int i, j, n; 507 struct powernow_state state; 508 509 for (i = 0; i < POWERNOW_MAX_STATES; ++i) 510 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN; 511 512 for (n = 0, i = 0; i < npstates; ++i) { 513 state.fid = *p++; 514 state.vid = *p++; 515 state.power = CPUFREQ_VAL_UNKNOWN; 516 517 switch (sc->pn_type) { 518 case PN7_TYPE: 519 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
| 490 491 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 492 493 switch (sc->pn_type) { 494 case PN7_TYPE: 495 cfid = PN7_STA_CFID(status); 496 cvid = PN7_STA_CVID(status); 497 break; 498 case PN8_TYPE: 499 cfid = PN8_STA_CFID(status); 500 cvid = PN8_STA_CVID(status); 501 break; 502 } 503 for (i = 0; i < sc->powernow_max_states; ++i) 504 if (cfid == sc->powernow_states[i].fid && 505 cvid == sc->powernow_states[i].vid) 506 break; 507 508 if (i < sc->powernow_max_states) { 509 cf->freq = sc->powernow_states[i].freq / 1000; 510 cf->power = sc->powernow_states[i].power; 511 cf->lat = 200; 512 cf->volts = sc->vid_to_volts[cvid]; 513 cf->dev = dev; 514 } else { 515 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 516 cf->dev = NULL; 517 } 518 519 return (0); 520} 521 522static int 523pn_settings(device_t dev, struct cf_setting *sets, int *count) 524{ 525 struct pn_softc *sc; 526 int i; 527 528 if (sets == NULL|| count == NULL) 529 return (EINVAL); 530 sc = device_get_softc(dev); 531 if (*count < sc->powernow_max_states) 532 return (E2BIG); 533 for (i = 0; i < sc->powernow_max_states; ++i) { 534 sets[i].freq = sc->powernow_states[i].freq / 1000; 535 sets[i].power = sc->powernow_states[i].power; 536 sets[i].lat = 200; 537 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid]; 538 sets[i].dev = dev; 539 } 540 *count = sc->powernow_max_states; 541 542 return (0); 543} 544 545static int 546pn_type(device_t dev, int *type) 547{ 548 if (type == NULL) 549 return (EINVAL); 550 551 *type = CPUFREQ_TYPE_ABSOLUTE; 552 553 return (0); 554} 555 556/* 557 * Given a set of pair of fid/vid, and number of performance states, 558 * compute powernow_states via an insertion sort. 559 */ 560static int 561decode_pst(struct pn_softc *sc, uint8_t *p, int npstates) 562{ 563 int i, j, n; 564 struct powernow_state state; 565 566 for (i = 0; i < POWERNOW_MAX_STATES; ++i) 567 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN; 568 569 for (n = 0, i = 0; i < npstates; ++i) { 570 state.fid = *p++; 571 state.vid = *p++; 572 state.power = CPUFREQ_VAL_UNKNOWN; 573 574 switch (sc->pn_type) { 575 case PN7_TYPE: 576 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
|
520 if (sc->errata_a0 &&
| 577 if ((sc->errata & A0_ERRATA) &&
|
521 (pn7_fid_to_mult[state.fid] % 10) == 5) 522 continue; 523 break; 524 case PN8_TYPE:
| 578 (pn7_fid_to_mult[state.fid] % 10) == 5) 579 continue; 580 break; 581 case PN8_TYPE:
|
525 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] * 526 sc->fsb;
| 582 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
|
527 break; 528 } 529 530 j = n; 531 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 532 memcpy(&sc->powernow_states[j], 533 &sc->powernow_states[j - 1], 534 sizeof(struct powernow_state)); 535 --j; 536 } 537 memcpy(&sc->powernow_states[j], &state, 538 sizeof(struct powernow_state)); 539 ++n; 540 } 541 542 /*
| 583 break; 584 } 585 586 j = n; 587 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 588 memcpy(&sc->powernow_states[j], 589 &sc->powernow_states[j - 1], 590 sizeof(struct powernow_state)); 591 --j; 592 } 593 memcpy(&sc->powernow_states[j], &state, 594 sizeof(struct powernow_state)); 595 ++n; 596 } 597 598 /*
|
543 * Fix powernow_max_states, if errata_a0 give us less states
| 599 * Fix powernow_max_states, if errata a0 give us less states
|
544 * than expected. 545 */ 546 sc->powernow_max_states = n; 547 548 if (bootverbose) 549 for (i = 0; i < sc->powernow_max_states; ++i) { 550 int fid = sc->powernow_states[i].fid; 551 int vid = sc->powernow_states[i].vid; 552 553 printf("powernow: %2i %8dkHz FID %02x VID %02x\n", 554 i, 555 sc->powernow_states[i].freq, 556 fid, 557 vid); 558 } 559 560 return (0); 561} 562 563static int 564cpuid_is_k7(u_int cpuid) 565{ 566 567 switch (cpuid) { 568 case 0x760: 569 case 0x761: 570 case 0x762: 571 case 0x770: 572 case 0x771: 573 case 0x780: 574 case 0x781: 575 case 0x7a0: 576 return (TRUE); 577 } 578 return (FALSE); 579} 580 581static int 582pn_decode_pst(device_t dev) 583{ 584 int maxpst; 585 struct pn_softc *sc; 586 u_int cpuid, maxfid, startvid; 587 u_long sig; 588 struct psb_header *psb; 589 uint8_t *p; 590 u_int regs[4]; 591 uint64_t status; 592 593 sc = device_get_softc(dev); 594 595 do_cpuid(0x80000001, regs); 596 cpuid = regs[0]; 597 598 if ((cpuid & 0xfff) == 0x760)
| 600 * than expected. 601 */ 602 sc->powernow_max_states = n; 603 604 if (bootverbose) 605 for (i = 0; i < sc->powernow_max_states; ++i) { 606 int fid = sc->powernow_states[i].fid; 607 int vid = sc->powernow_states[i].vid; 608 609 printf("powernow: %2i %8dkHz FID %02x VID %02x\n", 610 i, 611 sc->powernow_states[i].freq, 612 fid, 613 vid); 614 } 615 616 return (0); 617} 618 619static int 620cpuid_is_k7(u_int cpuid) 621{ 622 623 switch (cpuid) { 624 case 0x760: 625 case 0x761: 626 case 0x762: 627 case 0x770: 628 case 0x771: 629 case 0x780: 630 case 0x781: 631 case 0x7a0: 632 return (TRUE); 633 } 634 return (FALSE); 635} 636 637static int 638pn_decode_pst(device_t dev) 639{ 640 int maxpst; 641 struct pn_softc *sc; 642 u_int cpuid, maxfid, startvid; 643 u_long sig; 644 struct psb_header *psb; 645 uint8_t *p; 646 u_int regs[4]; 647 uint64_t status; 648 649 sc = device_get_softc(dev); 650 651 do_cpuid(0x80000001, regs); 652 cpuid = regs[0]; 653 654 if ((cpuid & 0xfff) == 0x760)
|
599 sc->errata_a0 = TRUE;
| 655 sc->errata |= A0_ERRATA;
|
600 601 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 602 603 switch (sc->pn_type) { 604 case PN7_TYPE: 605 maxfid = PN7_STA_MFID(status); 606 startvid = PN7_STA_SVID(status); 607 break; 608 case PN8_TYPE: 609 maxfid = PN8_STA_MFID(status); 610 /* 611 * we should actually use a variable named 'maxvid' if K8, 612 * but why introducing a new variable for that? 613 */ 614 startvid = PN8_STA_MVID(status); 615 break; 616 default: 617 return (ENODEV); 618 } 619 620 if (bootverbose) { 621 device_printf(dev, "STATUS: 0x%jx\n", status); 622 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid); 623 device_printf(dev, "STATUS: %s: 0x%02x\n", 624 sc->pn_type == PN7_TYPE ? "startvid" : "maxvid", 625 startvid); 626 } 627 628 sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF); 629 if (sig) { 630 struct pst_header *pst; 631 632 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig); 633 634 switch (psb->version) { 635 default: 636 return (ENODEV); 637 case 0x14: 638 /* 639 * We can't be picky about numpst since at least 640 * some systems have a value of 1 and some have 2. 641 * We trust that cpuid_is_k7() will be better at 642 * catching that we're on a K8 anyway. 643 */ 644 if (sc->pn_type != PN8_TYPE) 645 return (EINVAL); 646 sc->vst = psb->settlingtime; 647 sc->rvo = PN8_PSB_TO_RVO(psb->res1), 648 sc->irt = PN8_PSB_TO_IRT(psb->res1), 649 sc->mvs = PN8_PSB_TO_MVS(psb->res1), 650 sc->low = PN8_PSB_TO_BATT(psb->res1); 651 if (bootverbose) { 652 device_printf(dev, "PSB: VST: %d\n", 653 psb->settlingtime); 654 device_printf(dev, "PSB: RVO %x IRT %d " 655 "MVS %d BATT %d\n", 656 sc->rvo, 657 sc->irt, 658 sc->mvs, 659 sc->low); 660 } 661 break; 662 case 0x12: 663 if (sc->pn_type != PN7_TYPE) 664 return (EINVAL); 665 sc->sgtc = psb->settlingtime * sc->fsb; 666 if (sc->sgtc < 100 * sc->fsb) 667 sc->sgtc = 100 * sc->fsb; 668 break; 669 } 670 671 p = ((uint8_t *) psb) + sizeof(struct psb_header); 672 pst = (struct pst_header*) p; 673 674 maxpst = 200; 675 676 do { 677 struct pst_header *pst = (struct pst_header*) p; 678 679 if (cpuid == pst->cpuid && 680 maxfid == pst->maxfid && 681 startvid == pst->startvid) { 682 sc->powernow_max_states = pst->numpstates; 683 switch (sc->pn_type) { 684 case PN7_TYPE: 685 if (abs(sc->fsb - pst->fsb) > 5) 686 continue; 687 break; 688 case PN8_TYPE: 689 break; 690 } 691 return (decode_pst(sc, 692 p + sizeof(struct pst_header), 693 sc->powernow_max_states)); 694 } 695 696 p += sizeof(struct pst_header) + (2 * pst->numpstates); 697 } while (cpuid_is_k7(pst->cpuid) && maxpst--); 698 699 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid); 700 } 701 702 return (ENODEV); 703} 704 705/* 706 * TODO: this should be done in sys/ARCH/ARCH/identcpu.c 707 */ 708static int 709cpu_is_powernow_capable(void) 710{ 711 u_int regs[4]; 712 713 if (strcmp(cpu_vendor, "AuthenticAMD") != 0 || 714 cpu_exthigh < 0x80000007) 715 return (FALSE); 716 717 do_cpuid(0x80000007, regs); 718 return (regs[3] & 0x6); 719} 720 721static int 722pn_decode_acpi(device_t dev, device_t perf_dev) 723{ 724 int i, j, n; 725 uint64_t status; 726 uint32_t ctrl; 727 u_int cpuid; 728 u_int regs[4]; 729 struct pn_softc *sc; 730 struct powernow_state state; 731 struct cf_setting sets[POWERNOW_MAX_STATES]; 732 int count = POWERNOW_MAX_STATES; 733 int type; 734 int rv; 735 736 if (perf_dev == NULL) 737 return (ENXIO); 738 739 rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count); 740 if (rv) 741 return (ENXIO); 742 rv = CPUFREQ_DRV_TYPE(perf_dev, &type); 743 if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0) 744 return (ENXIO); 745 746 sc = device_get_softc(dev); 747 748 do_cpuid(0x80000001, regs); 749 cpuid = regs[0]; 750 if ((cpuid & 0xfff) == 0x760)
| 656 657 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 658 659 switch (sc->pn_type) { 660 case PN7_TYPE: 661 maxfid = PN7_STA_MFID(status); 662 startvid = PN7_STA_SVID(status); 663 break; 664 case PN8_TYPE: 665 maxfid = PN8_STA_MFID(status); 666 /* 667 * we should actually use a variable named 'maxvid' if K8, 668 * but why introducing a new variable for that? 669 */ 670 startvid = PN8_STA_MVID(status); 671 break; 672 default: 673 return (ENODEV); 674 } 675 676 if (bootverbose) { 677 device_printf(dev, "STATUS: 0x%jx\n", status); 678 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid); 679 device_printf(dev, "STATUS: %s: 0x%02x\n", 680 sc->pn_type == PN7_TYPE ? "startvid" : "maxvid", 681 startvid); 682 } 683 684 sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF); 685 if (sig) { 686 struct pst_header *pst; 687 688 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig); 689 690 switch (psb->version) { 691 default: 692 return (ENODEV); 693 case 0x14: 694 /* 695 * We can't be picky about numpst since at least 696 * some systems have a value of 1 and some have 2. 697 * We trust that cpuid_is_k7() will be better at 698 * catching that we're on a K8 anyway. 699 */ 700 if (sc->pn_type != PN8_TYPE) 701 return (EINVAL); 702 sc->vst = psb->settlingtime; 703 sc->rvo = PN8_PSB_TO_RVO(psb->res1), 704 sc->irt = PN8_PSB_TO_IRT(psb->res1), 705 sc->mvs = PN8_PSB_TO_MVS(psb->res1), 706 sc->low = PN8_PSB_TO_BATT(psb->res1); 707 if (bootverbose) { 708 device_printf(dev, "PSB: VST: %d\n", 709 psb->settlingtime); 710 device_printf(dev, "PSB: RVO %x IRT %d " 711 "MVS %d BATT %d\n", 712 sc->rvo, 713 sc->irt, 714 sc->mvs, 715 sc->low); 716 } 717 break; 718 case 0x12: 719 if (sc->pn_type != PN7_TYPE) 720 return (EINVAL); 721 sc->sgtc = psb->settlingtime * sc->fsb; 722 if (sc->sgtc < 100 * sc->fsb) 723 sc->sgtc = 100 * sc->fsb; 724 break; 725 } 726 727 p = ((uint8_t *) psb) + sizeof(struct psb_header); 728 pst = (struct pst_header*) p; 729 730 maxpst = 200; 731 732 do { 733 struct pst_header *pst = (struct pst_header*) p; 734 735 if (cpuid == pst->cpuid && 736 maxfid == pst->maxfid && 737 startvid == pst->startvid) { 738 sc->powernow_max_states = pst->numpstates; 739 switch (sc->pn_type) { 740 case PN7_TYPE: 741 if (abs(sc->fsb - pst->fsb) > 5) 742 continue; 743 break; 744 case PN8_TYPE: 745 break; 746 } 747 return (decode_pst(sc, 748 p + sizeof(struct pst_header), 749 sc->powernow_max_states)); 750 } 751 752 p += sizeof(struct pst_header) + (2 * pst->numpstates); 753 } while (cpuid_is_k7(pst->cpuid) && maxpst--); 754 755 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid); 756 } 757 758 return (ENODEV); 759} 760 761/* 762 * TODO: this should be done in sys/ARCH/ARCH/identcpu.c 763 */ 764static int 765cpu_is_powernow_capable(void) 766{ 767 u_int regs[4]; 768 769 if (strcmp(cpu_vendor, "AuthenticAMD") != 0 || 770 cpu_exthigh < 0x80000007) 771 return (FALSE); 772 773 do_cpuid(0x80000007, regs); 774 return (regs[3] & 0x6); 775} 776 777static int 778pn_decode_acpi(device_t dev, device_t perf_dev) 779{ 780 int i, j, n; 781 uint64_t status; 782 uint32_t ctrl; 783 u_int cpuid; 784 u_int regs[4]; 785 struct pn_softc *sc; 786 struct powernow_state state; 787 struct cf_setting sets[POWERNOW_MAX_STATES]; 788 int count = POWERNOW_MAX_STATES; 789 int type; 790 int rv; 791 792 if (perf_dev == NULL) 793 return (ENXIO); 794 795 rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count); 796 if (rv) 797 return (ENXIO); 798 rv = CPUFREQ_DRV_TYPE(perf_dev, &type); 799 if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0) 800 return (ENXIO); 801 802 sc = device_get_softc(dev); 803 804 do_cpuid(0x80000001, regs); 805 cpuid = regs[0]; 806 if ((cpuid & 0xfff) == 0x760)
|
751 sc->errata_a0 = TRUE;
| 807 sc->errata |= A0_ERRATA;
|
752 753 ctrl = 0; 754 sc->sgtc = 0; 755 for (n = 0, i = 0; i < count; ++i) { 756 ctrl = sets[i].spec[PX_SPEC_CONTROL]; 757 switch (sc->pn_type) { 758 case PN7_TYPE: 759 state.fid = ACPI_PN7_CTRL_TO_FID(ctrl); 760 state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
| 808 809 ctrl = 0; 810 sc->sgtc = 0; 811 for (n = 0, i = 0; i < count; ++i) { 812 ctrl = sets[i].spec[PX_SPEC_CONTROL]; 813 switch (sc->pn_type) { 814 case PN7_TYPE: 815 state.fid = ACPI_PN7_CTRL_TO_FID(ctrl); 816 state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
|
761 if (sc->errata_a0 &&
| 817 if ((sc->errata & A0_ERRATA) &&
|
762 (pn7_fid_to_mult[state.fid] % 10) == 5) 763 continue; 764 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; 765 break; 766 case PN8_TYPE: 767 state.fid = ACPI_PN8_CTRL_TO_FID(ctrl); 768 state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
| 818 (pn7_fid_to_mult[state.fid] % 10) == 5) 819 continue; 820 state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; 821 break; 822 case PN8_TYPE: 823 state.fid = ACPI_PN8_CTRL_TO_FID(ctrl); 824 state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
|
769 state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] * 770 sc->fsb;
| 825 state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
|
771 break; 772 } 773 774 state.power = sets[i].power; 775 776 j = n; 777 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 778 memcpy(&sc->powernow_states[j], 779 &sc->powernow_states[j - 1], 780 sizeof(struct powernow_state)); 781 --j; 782 } 783 memcpy(&sc->powernow_states[j], &state, 784 sizeof(struct powernow_state)); 785 ++n; 786 } 787 788 sc->powernow_max_states = n; 789 state = sc->powernow_states[0]; 790 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 791 792 switch (sc->pn_type) { 793 case PN7_TYPE: 794 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl); 795 /* 796 * XXX Some bios forget the max frequency! 797 * This maybe indicates we have the wrong tables. Therefore, 798 * don't implement a quirk, but fallback to BIOS legacy 799 * tables instead. 800 */ 801 if (PN7_STA_MFID(status) != state.fid) { 802 device_printf(dev, "ACPI MAX frequency not found\n"); 803 return (EINVAL); 804 } 805 break; 806 case PN8_TYPE: 807 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl), 808 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl), 809 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl), 810 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl), 811 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl); 812 sc->low = 0; /* XXX */ 813 814 /* 815 * powernow k8 supports only one low frequency. 816 */ 817 if (sc->powernow_max_states >= 2 && 818 (sc->powernow_states[sc->powernow_max_states - 2].fid < 8)) 819 return (EINVAL); 820 break; 821 } 822 823 return (0); 824} 825 826static void 827pn_identify(driver_t *driver, device_t parent) 828{ 829 device_t child; 830 831 if (cpu_is_powernow_capable() == 0) 832 return; 833 switch (cpu_id & 0xf00) { 834 case 0x600: 835 case 0xf00: 836 break; 837 default: 838 return; 839 } 840 if (device_find_child(parent, "powernow", -1) != NULL) 841 return; 842 if ((child = BUS_ADD_CHILD(parent, 0, "powernow", -1)) == NULL) 843 device_printf(parent, "powernow: add child failed\n"); 844} 845 846static int 847pn_probe(device_t dev) 848{ 849 struct pn_softc *sc; 850 uint64_t status; 851 uint64_t rate; 852 struct pcpu *pc; 853 u_int sfid, mfid, cfid; 854 855 sc = device_get_softc(dev);
| 826 break; 827 } 828 829 state.power = sets[i].power; 830 831 j = n; 832 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) { 833 memcpy(&sc->powernow_states[j], 834 &sc->powernow_states[j - 1], 835 sizeof(struct powernow_state)); 836 --j; 837 } 838 memcpy(&sc->powernow_states[j], &state, 839 sizeof(struct powernow_state)); 840 ++n; 841 } 842 843 sc->powernow_max_states = n; 844 state = sc->powernow_states[0]; 845 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 846 847 switch (sc->pn_type) { 848 case PN7_TYPE: 849 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl); 850 /* 851 * XXX Some bios forget the max frequency! 852 * This maybe indicates we have the wrong tables. Therefore, 853 * don't implement a quirk, but fallback to BIOS legacy 854 * tables instead. 855 */ 856 if (PN7_STA_MFID(status) != state.fid) { 857 device_printf(dev, "ACPI MAX frequency not found\n"); 858 return (EINVAL); 859 } 860 break; 861 case PN8_TYPE: 862 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl), 863 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl), 864 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl), 865 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl), 866 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl); 867 sc->low = 0; /* XXX */ 868 869 /* 870 * powernow k8 supports only one low frequency. 871 */ 872 if (sc->powernow_max_states >= 2 && 873 (sc->powernow_states[sc->powernow_max_states - 2].fid < 8)) 874 return (EINVAL); 875 break; 876 } 877 878 return (0); 879} 880 881static void 882pn_identify(driver_t *driver, device_t parent) 883{ 884 device_t child; 885 886 if (cpu_is_powernow_capable() == 0) 887 return; 888 switch (cpu_id & 0xf00) { 889 case 0x600: 890 case 0xf00: 891 break; 892 default: 893 return; 894 } 895 if (device_find_child(parent, "powernow", -1) != NULL) 896 return; 897 if ((child = BUS_ADD_CHILD(parent, 0, "powernow", -1)) == NULL) 898 device_printf(parent, "powernow: add child failed\n"); 899} 900 901static int 902pn_probe(device_t dev) 903{ 904 struct pn_softc *sc; 905 uint64_t status; 906 uint64_t rate; 907 struct pcpu *pc; 908 u_int sfid, mfid, cfid; 909 910 sc = device_get_softc(dev);
|
856 sc->errata_a0 = FALSE;
| 911 sc->errata = 0;
|
857 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 858 859 pc = cpu_get_pcpu(dev); 860 if (pc == NULL) 861 return (ENODEV); 862 863 cpu_est_clockrate(pc->pc_cpuid, &rate); 864 865 switch (cpu_id & 0xf00) { 866 case 0x600: 867 sfid = PN7_STA_SFID(status); 868 mfid = PN7_STA_MFID(status); 869 cfid = PN7_STA_CFID(status); 870 sc->pn_type = PN7_TYPE; 871 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid]; 872 873 /* 874 * If start FID is different to max FID, then it is a 875 * mobile processor. If not, it is a low powered desktop 876 * processor. 877 */ 878 if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) { 879 sc->vid_to_volts = pn7_mobile_vid_to_volts; 880 device_set_desc(dev, "PowerNow! K7"); 881 } else { 882 sc->vid_to_volts = pn7_desktop_vid_to_volts; 883 device_set_desc(dev, "Cool`n'Quiet K7"); 884 } 885 break; 886 887 case 0xf00: 888 sfid = PN8_STA_SFID(status); 889 mfid = PN8_STA_MFID(status); 890 cfid = PN8_STA_CFID(status); 891 sc->pn_type = PN8_TYPE; 892 sc->vid_to_volts = pn8_vid_to_volts;
| 912 status = rdmsr(MSR_AMDK7_FIDVID_STATUS); 913 914 pc = cpu_get_pcpu(dev); 915 if (pc == NULL) 916 return (ENODEV); 917 918 cpu_est_clockrate(pc->pc_cpuid, &rate); 919 920 switch (cpu_id & 0xf00) { 921 case 0x600: 922 sfid = PN7_STA_SFID(status); 923 mfid = PN7_STA_MFID(status); 924 cfid = PN7_STA_CFID(status); 925 sc->pn_type = PN7_TYPE; 926 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid]; 927 928 /* 929 * If start FID is different to max FID, then it is a 930 * mobile processor. If not, it is a low powered desktop 931 * processor. 932 */ 933 if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) { 934 sc->vid_to_volts = pn7_mobile_vid_to_volts; 935 device_set_desc(dev, "PowerNow! K7"); 936 } else { 937 sc->vid_to_volts = pn7_desktop_vid_to_volts; 938 device_set_desc(dev, "Cool`n'Quiet K7"); 939 } 940 break; 941 942 case 0xf00: 943 sfid = PN8_STA_SFID(status); 944 mfid = PN8_STA_MFID(status); 945 cfid = PN8_STA_CFID(status); 946 sc->pn_type = PN8_TYPE; 947 sc->vid_to_volts = pn8_vid_to_volts;
|
893 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid >> 1];
| 948 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
|
894 895 if (PN8_STA_SFID(status) != PN8_STA_MFID(status)) 896 device_set_desc(dev, "PowerNow! K8"); 897 else 898 device_set_desc(dev, "Cool`n'Quiet K8"); 899 break; 900 default: 901 return (ENODEV); 902 } 903 904 return (0); 905} 906 907static int 908pn_attach(device_t dev) 909{ 910 int rv; 911 device_t child; 912 913 child = device_find_child(device_get_parent(dev), "acpi_perf", -1); 914 if (child) { 915 rv = pn_decode_acpi(dev, child); 916 if (rv) 917 rv = pn_decode_pst(dev); 918 } else 919 rv = pn_decode_pst(dev); 920 921 if (rv != 0) 922 return (ENXIO); 923 cpufreq_register(dev); 924 return (0); 925} 926 927static int 928pn_detach(device_t dev) 929{ 930 931 cpufreq_unregister(dev); 932 return (0); 933}
| 949 950 if (PN8_STA_SFID(status) != PN8_STA_MFID(status)) 951 device_set_desc(dev, "PowerNow! K8"); 952 else 953 device_set_desc(dev, "Cool`n'Quiet K8"); 954 break; 955 default: 956 return (ENODEV); 957 } 958 959 return (0); 960} 961 962static int 963pn_attach(device_t dev) 964{ 965 int rv; 966 device_t child; 967 968 child = device_find_child(device_get_parent(dev), "acpi_perf", -1); 969 if (child) { 970 rv = pn_decode_acpi(dev, child); 971 if (rv) 972 rv = pn_decode_pst(dev); 973 } else 974 rv = pn_decode_pst(dev); 975 976 if (rv != 0) 977 return (ENXIO); 978 cpufreq_register(dev); 979 return (0); 980} 981 982static int 983pn_detach(device_t dev) 984{ 985 986 cpufreq_unregister(dev); 987 return (0); 988}
|