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$"); 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 56 struct 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 }; 64 65 #define THR_GET_REG(reg) \ 66 (bus_space_read_4(rman_get_bustag((reg)), \ 67 rman_get_bushandle((reg)), 0)) 68 #define THR_SET_REG(reg, val) \ 69 (bus_space_write_4(rman_get_bustag((reg)), \ 70 rman_get_bushandle((reg)), 0, (val))) 71 72 /* 73 * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and 74 * reported to the user in hundredths of a percent. 75 */ 76 #define CPU_MAX_SPEED (1 << cpu_duty_width) 77 #define CPU_SPEED_PERCENT(x) ((10000 * (x)) / CPU_MAX_SPEED) 78 #define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10), \ 79 (CPU_SPEED_PERCENT(x) % 10) 80 #define CPU_P_CNT_THT_EN (1<<4) 81 #define CPU_QUIRK_NO_THROTTLE (1<<1) /* Throttling is not usable. */ 82 83 #define PCI_VENDOR_INTEL 0x8086 84 #define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */ 85 #define PCI_REVISION_A_STEP 0 86 #define PCI_REVISION_B_STEP 1 87 88 static uint32_t cpu_duty_offset; /* Offset in P_CNT of throttle val. */ 89 static uint32_t cpu_duty_width; /* Bit width of throttle value. */ 90 static uint32_t cpu_throttle_state; /* Current throttle setting. */ 91 static int thr_rid; /* Driver-wide resource id. */ 92 static int thr_quirks; /* Indicate any hardware bugs. */ 93 94 static void acpi_throttle_identify(driver_t *driver, device_t parent); 95 static int acpi_throttle_probe(device_t dev); 96 static int acpi_throttle_attach(device_t dev); 97 static int acpi_throttle_evaluate(struct acpi_throttle_softc *sc); 98 static int acpi_throttle_quirks(struct acpi_throttle_softc *sc); 99 static int acpi_thr_settings(device_t dev, struct cf_setting *sets, 100 int *count, int *type); 101 static int acpi_thr_set(device_t dev, const struct cf_setting *set); 102 static int acpi_thr_get(device_t dev, struct cf_setting *set); 103 104 static device_method_t acpi_throttle_methods[] = { 105 /* Device interface */ 106 DEVMETHOD(device_identify, acpi_throttle_identify), 107 DEVMETHOD(device_probe, acpi_throttle_probe), 108 DEVMETHOD(device_attach, acpi_throttle_attach), 109 110 /* cpufreq interface */ 111 DEVMETHOD(cpufreq_drv_set, acpi_thr_set), 112 DEVMETHOD(cpufreq_drv_get, acpi_thr_get), 113 DEVMETHOD(cpufreq_drv_settings, acpi_thr_settings), 114 {0, 0} 115 }; 116 117 static driver_t acpi_throttle_driver = { 118 "acpi_throttle", 119 acpi_throttle_methods, 120 sizeof(struct acpi_throttle_softc), 121 }; 122 123 static devclass_t acpi_throttle_devclass; 124 DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass, 125 0, 0); 126 127 static void 128 acpi_throttle_identify(driver_t *driver, device_t parent) 129 { 130 131 /* Make sure we're not being doubly invoked. */ 132 if (device_find_child(parent, "acpi_throttle", 0) != NULL) 133 return; 134 135 /* Check for a valid duty width and parent CPU type. */ 136 if (acpi_get_handle(parent) == NULL) 137 return; 138 if (AcpiGbl_FADT->DutyWidth == 0 || 139 acpi_get_type(parent) != ACPI_TYPE_PROCESSOR) 140 return; 141 if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", 0) == NULL) 142 device_printf(parent, "acpi_throttle: add child failed\n"); 143 } 144 145 static int 146 acpi_throttle_probe(device_t dev) 147 { 148 149 device_set_desc(dev, "ACPI CPU Throttling"); 150 return (0); 151 } 152 153 static int 154 acpi_throttle_attach(device_t dev) 155 { 156 struct acpi_throttle_softc *sc; 157 ACPI_BUFFER buf; 158 ACPI_OBJECT*obj; 159 ACPI_STATUS status; 160 161 sc = device_get_softc(dev); 162 sc->cpu_dev = dev; 163 sc->cpu_handle = acpi_get_handle(dev); 164 165 buf.Pointer = NULL; 166 buf.Length = ACPI_ALLOCATE_BUFFER; 167 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); 168 if (ACPI_FAILURE(status)) { 169 device_printf(dev, "attach failed to get Processor obj - %s\n", 170 AcpiFormatException(status)); 171 return (ENXIO); 172 } 173 obj = (ACPI_OBJECT *)buf.Pointer; 174 sc->cpu_p_blk = obj->Processor.PblkAddress; 175 sc->cpu_p_blk_len = obj->Processor.PblkLength; 176 AcpiOsFree(obj); 177 178 /* If this is the first device probed, check for quirks. */ 179 if (device_get_unit(dev) == 0) 180 acpi_throttle_quirks(sc); 181 182 return (acpi_throttle_evaluate(sc)); 183 } 184 185 static int 186 acpi_throttle_evaluate(struct acpi_throttle_softc *sc) 187 { 188 uint32_t duty_end; 189 ACPI_BUFFER buf; 190 ACPI_OBJECT obj; 191 ACPI_GENERIC_ADDRESS gas; 192 ACPI_STATUS status; 193 194 /* Get throttling parameters from the FADT. 0 means not supported. */ 195 if (device_get_unit(sc->cpu_dev) == 0) { 196 cpu_duty_offset = AcpiGbl_FADT->DutyOffset; 197 cpu_duty_width = AcpiGbl_FADT->DutyWidth; 198 } 199 if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0) 200 return (ENXIO); 201 202 /* Validate the duty offset/width. */ 203 duty_end = cpu_duty_offset + cpu_duty_width - 1; 204 if (duty_end > 31) { 205 device_printf(sc->cpu_dev, 206 "CLK_VAL field overflows P_CNT register\n"); 207 return (ENXIO); 208 } 209 if (cpu_duty_offset <= 4 && duty_end >= 4) { 210 device_printf(sc->cpu_dev, 211 "CLK_VAL field overlaps THT_EN bit\n"); 212 return (ENXIO); 213 } 214 215 /* 216 * If not present, fall back to using the processor's P_BLK to find 217 * the P_CNT register. 218 * 219 * Note that some systems seem to duplicate the P_BLK pointer 220 * across multiple CPUs, so not getting the resource is not fatal. 221 */ 222 buf.Pointer = &obj; 223 buf.Length = sizeof(obj); 224 status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf); 225 if (ACPI_SUCCESS(status)) { 226 if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) { 227 device_printf(sc->cpu_dev, "_PTC buffer too small\n"); 228 return (ENXIO); 229 } 230 memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas)); 231 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 232 &gas, &sc->cpu_p_cnt); 233 if (sc->cpu_p_cnt != NULL && bootverbose) { 234 device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n", 235 gas.Address); 236 } 237 } 238 239 /* If _PTC not present or other failure, try the P_BLK. */ 240 if (sc->cpu_p_cnt == NULL) { 241 /* 242 * The spec says P_BLK must be 6 bytes long. However, some 243 * systems use it to indicate a fractional set of features 244 * present so we take anything >= 4. 245 */ 246 if (sc->cpu_p_blk_len < 4) 247 return (ENXIO); 248 gas.Address = sc->cpu_p_blk; 249 gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO; 250 gas.RegisterBitWidth = 32; 251 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid, 252 &gas, &sc->cpu_p_cnt); 253 if (sc->cpu_p_cnt != NULL) { 254 if (bootverbose) 255 device_printf(sc->cpu_dev, 256 "P_CNT from P_BLK %#x\n", sc->cpu_p_blk); 257 } else { 258 device_printf(sc->cpu_dev, "failed to attach P_CNT\n"); 259 return (ENXIO); 260 } 261 } 262 thr_rid++; 263 264 return (0); 265 } 266 267 static int 268 acpi_throttle_quirks(struct acpi_throttle_softc *sc) 269 { 270 device_t acpi_dev; 271 272 /* Look for various quirks of the PIIX4 part. */ 273 acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3); 274 if (acpi_dev) { 275 switch (pci_get_revid(acpi_dev)) { 276 /* 277 * Disable throttling control on PIIX4 A and B-step. 278 * See specification changes #13 ("Manual Throttle Duty Cycle") 279 * and #14 ("Enabling and Disabling Manual Throttle"), plus 280 * erratum #5 ("STPCLK# Deassertion Time") from the January 281 * 2002 PIIX4 specification update. Note that few (if any) 282 * mobile systems ever used this part. 283 */ 284 case PCI_REVISION_A_STEP: 285 case PCI_REVISION_B_STEP: 286 thr_quirks |= CPU_QUIRK_NO_THROTTLE; 287 break; 288 default: 289 break; 290 } 291 } 292 293 return (0); 294 } 295 296 static int 297 acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count, int *type) 298 { 299 struct acpi_throttle_softc *sc; 300 int i, speed; 301 302 sc = device_get_softc(dev); 303 if (sets == NULL || count == NULL) 304 return (EINVAL); 305 if (*count < CPU_MAX_SPEED) 306 return (ENOMEM); 307 308 /* Return a list of valid settings for this driver. */ 309 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED); 310 for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) { 311 sets[i].freq = CPU_SPEED_PERCENT(speed); 312 sets[i].dev = dev; 313 } 314 *count = CPU_MAX_SPEED; 315 *type = CPUFREQ_TYPE_RELATIVE; 316 317 return (0); 318 } 319 320 static int 321 acpi_thr_set(device_t dev, const struct cf_setting *set) 322 { 323 struct acpi_throttle_softc *sc; 324 uint32_t clk_val, p_cnt, speed; 325 326 if (set == NULL) 327 return (EINVAL); 328 sc = device_get_softc(dev); 329 330 /* 331 * Validate requested state converts to a duty cycle that is an 332 * integer from [1 .. CPU_MAX_SPEED]. 333 */ 334 speed = set->freq * CPU_MAX_SPEED / 10000; 335 if (speed * 10000 != set->freq * CPU_MAX_SPEED || 336 speed < 1 || speed > CPU_MAX_SPEED) 337 return (EINVAL); 338 339 /* If we're at this setting, don't bother applying it again. */ 340 if (speed == cpu_throttle_state) 341 return (0); 342 343 /* Get the current P_CNT value and disable throttling */ 344 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 345 p_cnt &= ~CPU_P_CNT_THT_EN; 346 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 347 348 /* If we're at maximum speed, that's all */ 349 if (speed < CPU_MAX_SPEED) { 350 /* Mask the old CLK_VAL off and OR in the new value */ 351 clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset; 352 p_cnt &= ~clk_val; 353 p_cnt |= (speed << cpu_duty_offset); 354 355 /* Write the new P_CNT value and then enable throttling */ 356 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 357 p_cnt |= CPU_P_CNT_THT_EN; 358 THR_SET_REG(sc->cpu_p_cnt, p_cnt); 359 } 360 cpu_throttle_state = speed; 361 362 return (0); 363 } 364 365 static int 366 acpi_thr_get(device_t dev, struct cf_setting *set) 367 { 368 struct acpi_throttle_softc *sc; 369 uint32_t p_cnt, clk_val; 370 371 if (set == NULL) 372 return (EINVAL); 373 sc = device_get_softc(dev); 374 375 /* Get the current throttling setting from P_CNT. */ 376 p_cnt = THR_GET_REG(sc->cpu_p_cnt); 377 clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1); 378 379 memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set)); 380 set->freq = CPU_SPEED_PERCENT(clk_val); 381 set->dev = dev; 382 383 return (0); 384 } 385