1/*- 2 * Copyright (c) 2003-2005 Nate Lawson (SDG) 3 * Copyright (c) 2001 Michael Smith 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2003-2005 Nate Lawson (SDG) 3 * Copyright (c) 2001 Michael Smith 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h>
|
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_throttle.c 142032 2005-02-18 00:23:36Z njl $");
| 29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_throttle.c 142203 2005-02-22 06:31:45Z njl $");
|
30 31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/cpu.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/rman.h> 39 40#include <machine/bus.h> 41 42#include "acpi.h" 43#include <dev/acpica/acpivar.h> 44#include <dev/pci/pcivar.h> 45 46#include "cpufreq_if.h" 47 48/* 49 * Throttling provides relative frequency control. It involves modulating 50 * the clock so that the CPU is active for only a fraction of the normal 51 * clock cycle. It does not change voltage and so is less efficient than 52 * other mechanisms. Since it is relative, it can be used in addition to 53 * absolute cpufreq drivers. We support the ACPI 2.0 specification. 54 */ 55 56struct acpi_throttle_softc { 57 device_t cpu_dev; 58 ACPI_HANDLE cpu_handle; 59 uint32_t cpu_p_blk; /* ACPI P_BLK location */ 60 uint32_t cpu_p_blk_len; /* P_BLK length (must be 6). */ 61 struct resource *cpu_p_cnt; /* Throttling control register */ 62 int cpu_p_type; /* Resource type for cpu_p_cnt. */ 63 uint32_t cpu_thr_state; /* Current throttle setting. */ 64}; 65 66#define THR_GET_REG(reg) \ 67 (bus_space_read_4(rman_get_bustag((reg)), \ 68 rman_get_bushandle((reg)), 0)) 69#define THR_SET_REG(reg, val) \ 70 (bus_space_write_4(rman_get_bustag((reg)), \ 71 rman_get_bushandle((reg)), 0, (val))) 72 73/* 74 * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and 75 * reported to the user in hundredths of a percent. 76 */ 77#define CPU_MAX_SPEED (1 << cpu_duty_width) 78#define CPU_SPEED_PERCENT(x) ((10000 * (x)) / CPU_MAX_SPEED) 79#define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10), \ 80 (CPU_SPEED_PERCENT(x) % 10) 81#define CPU_P_CNT_THT_EN (1<<4) 82#define CPU_QUIRK_NO_THROTTLE (1<<1) /* Throttling is not usable. */ 83 84#define PCI_VENDOR_INTEL 0x8086 85#define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */ 86#define PCI_REVISION_A_STEP 0 87#define PCI_REVISION_B_STEP 1 88 89static uint32_t cpu_duty_offset; /* Offset in P_CNT of throttle val. */ 90static uint32_t cpu_duty_width; /* Bit width of throttle value. */ 91static int thr_rid; /* Driver-wide resource id. */ 92static int thr_quirks; /* Indicate any hardware bugs. */ 93 94static void acpi_throttle_identify(driver_t *driver, device_t parent); 95static int acpi_throttle_probe(device_t dev); 96static int acpi_throttle_attach(device_t dev); 97static int acpi_throttle_evaluate(struct acpi_throttle_softc *sc); 98static int acpi_throttle_quirks(struct acpi_throttle_softc *sc); 99static int acpi_thr_settings(device_t dev, struct cf_setting *sets, 100 int *count); 101static int acpi_thr_set(device_t dev, const struct cf_setting *set); 102static int acpi_thr_get(device_t dev, struct cf_setting *set); 103static int acpi_thr_type(device_t dev, int *type); 104 105static device_method_t acpi_throttle_methods[] = { 106 /* Device interface */ 107 DEVMETHOD(device_identify, acpi_throttle_identify), 108 DEVMETHOD(device_probe, acpi_throttle_probe), 109 DEVMETHOD(device_attach, acpi_throttle_attach), 110 111 /* cpufreq interface */ 112 DEVMETHOD(cpufreq_drv_set, acpi_thr_set), 113 DEVMETHOD(cpufreq_drv_get, acpi_thr_get), 114 DEVMETHOD(cpufreq_drv_type, acpi_thr_type), 115 DEVMETHOD(cpufreq_drv_settings, acpi_thr_settings), 116 {0, 0} 117}; 118 119static driver_t acpi_throttle_driver = { 120 "acpi_throttle", 121 acpi_throttle_methods, 122 sizeof(struct acpi_throttle_softc), 123}; 124 125static devclass_t acpi_throttle_devclass; 126DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass, 127 0, 0); 128 129static void 130acpi_throttle_identify(driver_t *driver, device_t parent) 131{ 132 ACPI_BUFFER buf; 133 ACPI_HANDLE handle; 134 ACPI_OBJECT *obj; 135 136 /* Make sure we're not being doubly invoked. */ 137 if (device_find_child(parent, "acpi_throttle", -1) != NULL) 138 return; 139 140 /* Check for a valid duty width and parent CPU type. */ 141 handle = acpi_get_handle(parent); 142 if (handle == NULL) 143 return; 144 if (AcpiGbl_FADT->DutyWidth == 0 || 145 acpi_get_type(parent) != ACPI_TYPE_PROCESSOR) 146 return; 147 148 /* 149 * Add a child if there's a non-NULL P_BLK and correct length, or 150 * if the _PTC method is present. 151 */ 152 buf.Pointer = NULL; 153 buf.Length = ACPI_ALLOCATE_BUFFER; 154 if (ACPI_FAILURE(AcpiEvaluateObject(handle, NULL, NULL, &buf))) 155 return; 156 obj = (ACPI_OBJECT *)buf.Pointer; 157 if ((obj->Processor.PblkAddress && obj->Processor.PblkLength >= 4) || 158 ACPI_SUCCESS(AcpiEvaluateObject(handle, "_PTC", NULL, NULL))) { 159 if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", -1) == NULL) 160 device_printf(parent, "add throttle child failed\n"); 161 } 162 AcpiOsFree(obj); 163} 164 165static int 166acpi_throttle_probe(device_t dev) 167{ 168
| 30 31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/cpu.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/rman.h> 39 40#include <machine/bus.h> 41 42#include "acpi.h" 43#include <dev/acpica/acpivar.h> 44#include <dev/pci/pcivar.h> 45 46#include "cpufreq_if.h" 47 48/* 49 * Throttling provides relative frequency control. It involves modulating 50 * the clock so that the CPU is active for only a fraction of the normal 51 * clock cycle. It does not change voltage and so is less efficient than 52 * other mechanisms. Since it is relative, it can be used in addition to 53 * absolute cpufreq drivers. We support the ACPI 2.0 specification. 54 */ 55 56struct acpi_throttle_softc { 57 device_t cpu_dev; 58 ACPI_HANDLE cpu_handle; 59 uint32_t cpu_p_blk; /* ACPI P_BLK location */ 60 uint32_t cpu_p_blk_len; /* P_BLK length (must be 6). */ 61 struct resource *cpu_p_cnt; /* Throttling control register */ 62 int cpu_p_type; /* Resource type for cpu_p_cnt. */ 63 uint32_t cpu_thr_state; /* Current throttle setting. */ 64}; 65 66#define THR_GET_REG(reg) \ 67 (bus_space_read_4(rman_get_bustag((reg)), \ 68 rman_get_bushandle((reg)), 0)) 69#define THR_SET_REG(reg, val) \ 70 (bus_space_write_4(rman_get_bustag((reg)), \ 71 rman_get_bushandle((reg)), 0, (val))) 72 73/* 74 * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and 75 * reported to the user in hundredths of a percent. 76 */ 77#define CPU_MAX_SPEED (1 << cpu_duty_width) 78#define CPU_SPEED_PERCENT(x) ((10000 * (x)) / CPU_MAX_SPEED) 79#define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10), \ 80 (CPU_SPEED_PERCENT(x) % 10) 81#define CPU_P_CNT_THT_EN (1<<4) 82#define CPU_QUIRK_NO_THROTTLE (1<<1) /* Throttling is not usable. */ 83 84#define PCI_VENDOR_INTEL 0x8086 85#define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */ 86#define PCI_REVISION_A_STEP 0 87#define PCI_REVISION_B_STEP 1 88 89static uint32_t cpu_duty_offset; /* Offset in P_CNT of throttle val. */ 90static uint32_t cpu_duty_width; /* Bit width of throttle value. */ 91static int thr_rid; /* Driver-wide resource id. */ 92static int thr_quirks; /* Indicate any hardware bugs. */ 93 94static void acpi_throttle_identify(driver_t *driver, device_t parent); 95static int acpi_throttle_probe(device_t dev); 96static int acpi_throttle_attach(device_t dev); 97static int acpi_throttle_evaluate(struct acpi_throttle_softc *sc); 98static int acpi_throttle_quirks(struct acpi_throttle_softc *sc); 99static int acpi_thr_settings(device_t dev, struct cf_setting *sets, 100 int *count); 101static int acpi_thr_set(device_t dev, const struct cf_setting *set); 102static int acpi_thr_get(device_t dev, struct cf_setting *set); 103static int acpi_thr_type(device_t dev, int *type); 104 105static device_method_t acpi_throttle_methods[] = { 106 /* Device interface */ 107 DEVMETHOD(device_identify, acpi_throttle_identify), 108 DEVMETHOD(device_probe, acpi_throttle_probe), 109 DEVMETHOD(device_attach, acpi_throttle_attach), 110 111 /* cpufreq interface */ 112 DEVMETHOD(cpufreq_drv_set, acpi_thr_set), 113 DEVMETHOD(cpufreq_drv_get, acpi_thr_get), 114 DEVMETHOD(cpufreq_drv_type, acpi_thr_type), 115 DEVMETHOD(cpufreq_drv_settings, acpi_thr_settings), 116 {0, 0} 117}; 118 119static driver_t acpi_throttle_driver = { 120 "acpi_throttle", 121 acpi_throttle_methods, 122 sizeof(struct acpi_throttle_softc), 123}; 124 125static devclass_t acpi_throttle_devclass; 126DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass, 127 0, 0); 128 129static void 130acpi_throttle_identify(driver_t *driver, device_t parent) 131{ 132 ACPI_BUFFER buf; 133 ACPI_HANDLE handle; 134 ACPI_OBJECT *obj; 135 136 /* Make sure we're not being doubly invoked. */ 137 if (device_find_child(parent, "acpi_throttle", -1) != NULL) 138 return; 139 140 /* Check for a valid duty width and parent CPU type. */ 141 handle = acpi_get_handle(parent); 142 if (handle == NULL) 143 return; 144 if (AcpiGbl_FADT->DutyWidth == 0 || 145 acpi_get_type(parent) != ACPI_TYPE_PROCESSOR) 146 return; 147 148 /* 149 * Add a child if there's a non-NULL P_BLK and correct length, or 150 * if the _PTC method is present. 151 */ 152 buf.Pointer = NULL; 153 buf.Length = ACPI_ALLOCATE_BUFFER; 154 if (ACPI_FAILURE(AcpiEvaluateObject(handle, NULL, NULL, &buf))) 155 return; 156 obj = (ACPI_OBJECT *)buf.Pointer; 157 if ((obj->Processor.PblkAddress && obj->Processor.PblkLength >= 4) || 158 ACPI_SUCCESS(AcpiEvaluateObject(handle, "_PTC", NULL, NULL))) { 159 if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", -1) == NULL) 160 device_printf(parent, "add throttle child failed\n"); 161 } 162 AcpiOsFree(obj); 163} 164 165static int 166acpi_throttle_probe(device_t dev) 167{ 168
|
| 169 if (resource_disabled("acpi_throttle", 0)) 170 return (ENXIO); 171
|
169 device_set_desc(dev, "ACPI CPU Throttling"); 170 return (0); 171} 172 173static int 174acpi_throttle_attach(device_t dev) 175{ 176 struct acpi_throttle_softc *sc; 177 ACPI_BUFFER buf; 178 ACPI_OBJECT *obj; 179 ACPI_STATUS status; 180 int error; 181 182 sc = device_get_softc(dev); 183 sc->cpu_dev = dev; 184 sc->cpu_handle = acpi_get_handle(dev); 185 186 buf.Pointer = NULL; 187 buf.Length = ACPI_ALLOCATE_BUFFER; 188 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); 189 if (ACPI_FAILURE(status)) { 190 device_printf(dev, "attach failed to get Processor obj - %s\n", 191 AcpiFormatException(status)); 192 return (ENXIO); 193 } 194 obj = (ACPI_OBJECT *)buf.Pointer; 195 sc->cpu_p_blk = obj->Processor.PblkAddress; 196 sc->cpu_p_blk_len = obj->Processor.PblkLength; 197 AcpiOsFree(obj); 198 199 /* If this is the first device probed, check for quirks. */ 200 if (device_get_unit(dev) == 0) 201 acpi_throttle_quirks(sc); 202 203 /* Attempt to attach the actual throttling register. */ 204 error = acpi_throttle_evaluate(sc); 205 if (error) 206 return (error); 207 208 /* Everything went ok, register with cpufreq(4). */ 209 cpufreq_register(dev); 210 return (0); 211} 212 213static int 214acpi_throttle_evaluate(struct acpi_throttle_softc *sc) 215{ 216 uint32_t duty_end; 217 ACPI_BUFFER buf; 218 ACPI_OBJECT obj; 219 ACPI_GENERIC_ADDRESS gas; 220 ACPI_STATUS status; 221 222 /* Get throttling parameters from the FADT. 0 means not supported. */ 223 if (device_get_unit(sc->cpu_dev) == 0) { 224 cpu_duty_offset = AcpiGbl_FADT->DutyOffset; 225 cpu_duty_width = AcpiGbl_FADT->DutyWidth; 226 } 227 if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0) 228 return (ENXIO); 229 230 /* Validate the duty offset/width. */ 231 duty_end = cpu_duty_offset + cpu_duty_width - 1; 232 if (duty_end > 31) { 233 device_printf(sc->cpu_dev, 234 "CLK_VAL field overflows P_CNT register\n"); 235 return (ENXIO); 236 } 237 if (cpu_duty_offset <= 4 && duty_end >= 4) { 238 device_printf(sc->cpu_dev, 239 "CLK_VAL field overlaps THT_EN bit\n"); 240 return (ENXIO); 241 } 242 243 /* 244 * If not present, fall back to using the processor's P_BLK to find 245 * the P_CNT register. 246 * 247 * Note that some systems seem to duplicate the P_BLK pointer 248 * across multiple CPUs, so not getting the resource is not fatal. 249 */ 250 buf.Pointer = &obj; 251 buf.Length = sizeof(obj); 252 status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf); 253 if (ACPI_SUCCESS(status)) { 254 if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) { 255 device_printf(sc->cpu_dev, "_PTC buffer too small\n"); 256 return (ENXIO); 257 } 258 memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas)); 259 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 260 &gas, &sc->cpu_p_cnt); 261 if (sc->cpu_p_cnt != NULL && bootverbose) { 262 device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n", 263 gas.Address); 264 } 265 } 266 267 /* If _PTC not present or other failure, try the P_BLK. */ 268 if (sc->cpu_p_cnt == NULL) { 269 /* 270 * The spec says P_BLK must be 6 bytes long. However, some 271 * systems use it to indicate a fractional set of features 272 * present so we take anything >= 4. 273 */ 274 if (sc->cpu_p_blk_len < 4) 275 return (ENXIO); 276 gas.Address = sc->cpu_p_blk; 277 gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO; 278 gas.RegisterBitWidth = 32; 279 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 280 &gas, &sc->cpu_p_cnt); 281 if (sc->cpu_p_cnt != NULL) { 282 if (bootverbose) 283 device_printf(sc->cpu_dev, 284 "P_CNT from P_BLK %#x\n", sc->cpu_p_blk); 285 } else { 286 device_printf(sc->cpu_dev, "failed to attach P_CNT\n"); 287 return (ENXIO); 288 } 289 } 290 thr_rid++; 291 292 return (0); 293} 294 295static int 296acpi_throttle_quirks(struct acpi_throttle_softc *sc) 297{ 298 device_t acpi_dev; 299 300 /* Look for various quirks of the PIIX4 part. */ 301 acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3); 302 if (acpi_dev) { 303 switch (pci_get_revid(acpi_dev)) { 304 /* 305 * Disable throttling control on PIIX4 A and B-step. 306 * See specification changes #13 ("Manual Throttle Duty Cycle") 307 * and #14 ("Enabling and Disabling Manual Throttle"), plus 308 * erratum #5 ("STPCLK# Deassertion Time") from the January 309 * 2002 PIIX4 specification update. Note that few (if any) 310 * mobile systems ever used this part. 311 */ 312 case PCI_REVISION_A_STEP: 313 case PCI_REVISION_B_STEP: 314 thr_quirks |= CPU_QUIRK_NO_THROTTLE; 315 break; 316 default: 317 break; 318 } 319 } 320 321 return (0); 322} 323 324static int 325acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count) 326{ 327 struct acpi_throttle_softc *sc; 328 int i, speed; 329 330 sc = device_get_softc(dev); 331 if (sets == NULL || count == NULL) 332 return (EINVAL); 333 if (*count < CPU_MAX_SPEED) 334 return (E2BIG); 335 336 /* Return a list of valid settings for this driver. */ 337 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED); 338 for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) { 339 sets[i].freq = CPU_SPEED_PERCENT(speed); 340 sets[i].dev = dev; 341 } 342 *count = CPU_MAX_SPEED; 343 344 return (0); 345} 346 347static int 348acpi_thr_set(device_t dev, const struct cf_setting *set) 349{ 350 struct acpi_throttle_softc *sc; 351 uint32_t clk_val, p_cnt, speed; 352 353 if (set == NULL) 354 return (EINVAL); 355 sc = device_get_softc(dev); 356 357 /* 358 * Validate requested state converts to a duty cycle that is an 359 * integer from [1 .. CPU_MAX_SPEED]. 360 */ 361 speed = set->freq * CPU_MAX_SPEED / 10000; 362 if (speed * 10000 != set->freq * CPU_MAX_SPEED || 363 speed < 1 || speed > CPU_MAX_SPEED) 364 return (EINVAL); 365 366 /* If we're at this setting, don't bother applying it again. */ 367 if (speed == sc->cpu_thr_state) 368 return (0); 369 370 /* Get the current P_CNT value and disable throttling */ 371 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 372 p_cnt &= ~CPU_P_CNT_THT_EN; 373 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 374 375 /* If we're at maximum speed, that's all */ 376 if (speed < CPU_MAX_SPEED) { 377 /* Mask the old CLK_VAL off and OR in the new value */ 378 clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset; 379 p_cnt &= ~clk_val; 380 p_cnt |= (speed << cpu_duty_offset); 381 382 /* Write the new P_CNT value and then enable throttling */ 383 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 384 p_cnt |= CPU_P_CNT_THT_EN; 385 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 386 } 387 sc->cpu_thr_state = speed; 388 389 return (0); 390} 391 392static int 393acpi_thr_get(device_t dev, struct cf_setting *set) 394{ 395 struct acpi_throttle_softc *sc; 396 uint32_t p_cnt, clk_val; 397 398 if (set == NULL) 399 return (EINVAL); 400 sc = device_get_softc(dev); 401 402 /* Get the current throttling setting from P_CNT. */ 403 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 404 clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1); 405 sc->cpu_thr_state = clk_val; 406 407 memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set)); 408 set->freq = CPU_SPEED_PERCENT(clk_val); 409 set->dev = dev; 410 411 return (0); 412} 413 414static int 415acpi_thr_type(device_t dev, int *type) 416{ 417 418 if (type == NULL) 419 return (EINVAL); 420 421 *type = CPUFREQ_TYPE_RELATIVE; 422 return (0); 423}
| 172 device_set_desc(dev, "ACPI CPU Throttling"); 173 return (0); 174} 175 176static int 177acpi_throttle_attach(device_t dev) 178{ 179 struct acpi_throttle_softc *sc; 180 ACPI_BUFFER buf; 181 ACPI_OBJECT *obj; 182 ACPI_STATUS status; 183 int error; 184 185 sc = device_get_softc(dev); 186 sc->cpu_dev = dev; 187 sc->cpu_handle = acpi_get_handle(dev); 188 189 buf.Pointer = NULL; 190 buf.Length = ACPI_ALLOCATE_BUFFER; 191 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); 192 if (ACPI_FAILURE(status)) { 193 device_printf(dev, "attach failed to get Processor obj - %s\n", 194 AcpiFormatException(status)); 195 return (ENXIO); 196 } 197 obj = (ACPI_OBJECT *)buf.Pointer; 198 sc->cpu_p_blk = obj->Processor.PblkAddress; 199 sc->cpu_p_blk_len = obj->Processor.PblkLength; 200 AcpiOsFree(obj); 201 202 /* If this is the first device probed, check for quirks. */ 203 if (device_get_unit(dev) == 0) 204 acpi_throttle_quirks(sc); 205 206 /* Attempt to attach the actual throttling register. */ 207 error = acpi_throttle_evaluate(sc); 208 if (error) 209 return (error); 210 211 /* Everything went ok, register with cpufreq(4). */ 212 cpufreq_register(dev); 213 return (0); 214} 215 216static int 217acpi_throttle_evaluate(struct acpi_throttle_softc *sc) 218{ 219 uint32_t duty_end; 220 ACPI_BUFFER buf; 221 ACPI_OBJECT obj; 222 ACPI_GENERIC_ADDRESS gas; 223 ACPI_STATUS status; 224 225 /* Get throttling parameters from the FADT. 0 means not supported. */ 226 if (device_get_unit(sc->cpu_dev) == 0) { 227 cpu_duty_offset = AcpiGbl_FADT->DutyOffset; 228 cpu_duty_width = AcpiGbl_FADT->DutyWidth; 229 } 230 if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0) 231 return (ENXIO); 232 233 /* Validate the duty offset/width. */ 234 duty_end = cpu_duty_offset + cpu_duty_width - 1; 235 if (duty_end > 31) { 236 device_printf(sc->cpu_dev, 237 "CLK_VAL field overflows P_CNT register\n"); 238 return (ENXIO); 239 } 240 if (cpu_duty_offset <= 4 && duty_end >= 4) { 241 device_printf(sc->cpu_dev, 242 "CLK_VAL field overlaps THT_EN bit\n"); 243 return (ENXIO); 244 } 245 246 /* 247 * If not present, fall back to using the processor's P_BLK to find 248 * the P_CNT register. 249 * 250 * Note that some systems seem to duplicate the P_BLK pointer 251 * across multiple CPUs, so not getting the resource is not fatal. 252 */ 253 buf.Pointer = &obj; 254 buf.Length = sizeof(obj); 255 status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf); 256 if (ACPI_SUCCESS(status)) { 257 if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) { 258 device_printf(sc->cpu_dev, "_PTC buffer too small\n"); 259 return (ENXIO); 260 } 261 memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas)); 262 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 263 &gas, &sc->cpu_p_cnt); 264 if (sc->cpu_p_cnt != NULL && bootverbose) { 265 device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n", 266 gas.Address); 267 } 268 } 269 270 /* If _PTC not present or other failure, try the P_BLK. */ 271 if (sc->cpu_p_cnt == NULL) { 272 /* 273 * The spec says P_BLK must be 6 bytes long. However, some 274 * systems use it to indicate a fractional set of features 275 * present so we take anything >= 4. 276 */ 277 if (sc->cpu_p_blk_len < 4) 278 return (ENXIO); 279 gas.Address = sc->cpu_p_blk; 280 gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO; 281 gas.RegisterBitWidth = 32; 282 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 283 &gas, &sc->cpu_p_cnt); 284 if (sc->cpu_p_cnt != NULL) { 285 if (bootverbose) 286 device_printf(sc->cpu_dev, 287 "P_CNT from P_BLK %#x\n", sc->cpu_p_blk); 288 } else { 289 device_printf(sc->cpu_dev, "failed to attach P_CNT\n"); 290 return (ENXIO); 291 } 292 } 293 thr_rid++; 294 295 return (0); 296} 297 298static int 299acpi_throttle_quirks(struct acpi_throttle_softc *sc) 300{ 301 device_t acpi_dev; 302 303 /* Look for various quirks of the PIIX4 part. */ 304 acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3); 305 if (acpi_dev) { 306 switch (pci_get_revid(acpi_dev)) { 307 /* 308 * Disable throttling control on PIIX4 A and B-step. 309 * See specification changes #13 ("Manual Throttle Duty Cycle") 310 * and #14 ("Enabling and Disabling Manual Throttle"), plus 311 * erratum #5 ("STPCLK# Deassertion Time") from the January 312 * 2002 PIIX4 specification update. Note that few (if any) 313 * mobile systems ever used this part. 314 */ 315 case PCI_REVISION_A_STEP: 316 case PCI_REVISION_B_STEP: 317 thr_quirks |= CPU_QUIRK_NO_THROTTLE; 318 break; 319 default: 320 break; 321 } 322 } 323 324 return (0); 325} 326 327static int 328acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count) 329{ 330 struct acpi_throttle_softc *sc; 331 int i, speed; 332 333 sc = device_get_softc(dev); 334 if (sets == NULL || count == NULL) 335 return (EINVAL); 336 if (*count < CPU_MAX_SPEED) 337 return (E2BIG); 338 339 /* Return a list of valid settings for this driver. */ 340 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED); 341 for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) { 342 sets[i].freq = CPU_SPEED_PERCENT(speed); 343 sets[i].dev = dev; 344 } 345 *count = CPU_MAX_SPEED; 346 347 return (0); 348} 349 350static int 351acpi_thr_set(device_t dev, const struct cf_setting *set) 352{ 353 struct acpi_throttle_softc *sc; 354 uint32_t clk_val, p_cnt, speed; 355 356 if (set == NULL) 357 return (EINVAL); 358 sc = device_get_softc(dev); 359 360 /* 361 * Validate requested state converts to a duty cycle that is an 362 * integer from [1 .. CPU_MAX_SPEED]. 363 */ 364 speed = set->freq * CPU_MAX_SPEED / 10000; 365 if (speed * 10000 != set->freq * CPU_MAX_SPEED || 366 speed < 1 || speed > CPU_MAX_SPEED) 367 return (EINVAL); 368 369 /* If we're at this setting, don't bother applying it again. */ 370 if (speed == sc->cpu_thr_state) 371 return (0); 372 373 /* Get the current P_CNT value and disable throttling */ 374 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 375 p_cnt &= ~CPU_P_CNT_THT_EN; 376 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 377 378 /* If we're at maximum speed, that's all */ 379 if (speed < CPU_MAX_SPEED) { 380 /* Mask the old CLK_VAL off and OR in the new value */ 381 clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset; 382 p_cnt &= ~clk_val; 383 p_cnt |= (speed << cpu_duty_offset); 384 385 /* Write the new P_CNT value and then enable throttling */ 386 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 387 p_cnt |= CPU_P_CNT_THT_EN; 388 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 389 } 390 sc->cpu_thr_state = speed; 391 392 return (0); 393} 394 395static int 396acpi_thr_get(device_t dev, struct cf_setting *set) 397{ 398 struct acpi_throttle_softc *sc; 399 uint32_t p_cnt, clk_val; 400 401 if (set == NULL) 402 return (EINVAL); 403 sc = device_get_softc(dev); 404 405 /* Get the current throttling setting from P_CNT. */ 406 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 407 clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1); 408 sc->cpu_thr_state = clk_val; 409 410 memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set)); 411 set->freq = CPU_SPEED_PERCENT(clk_val); 412 set->dev = dev; 413 414 return (0); 415} 416 417static int 418acpi_thr_type(device_t dev, int *type) 419{ 420 421 if (type == NULL) 422 return (EINVAL); 423 424 *type = CPUFREQ_TYPE_RELATIVE; 425 return (0); 426}
|