^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Pentium 4/Xeon CPU on demand clock modulation/speed scaling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * (C) 2002 Arjan van de Ven <arjanv@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * (C) 2002 Tora T. Engstad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * The author(s) of this software shall not be held liable for damages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * of any nature resulting due to the use of this software. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * software is provided AS-IS with no warranties.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Date Errata Description
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * 20020525 N44, O17 12.5% or 25% DC causes lockup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/timex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/msr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/cpu_device_id.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "speedstep-lib.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Duty Cycle (3bits), note DC_DISABLE is not specified in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * intel docs i just use it to mean disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) DC_64PT, DC_75PT, DC_88PT, DC_DISABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define DC_ENTRIES 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int has_N44_O17_errata[NR_CPUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static unsigned int stock_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static struct cpufreq_driver p4clockmod_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static unsigned int cpufreq_p4_get(unsigned int cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u32 l, h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if ((newstate > DC_DISABLE) || (newstate == DC_RESV))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (l & 0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) pr_debug("CPU#%d currently thermal throttled\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (has_N44_O17_errata[cpu] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) (newstate == DC_25PT || newstate == DC_DFLT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) newstate = DC_38PT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (newstate == DC_DISABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) pr_debug("CPU#%d disabling modulation\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pr_debug("CPU#%d setting duty cycle to %d%%\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) cpu, ((125 * newstate) / 10));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* bits 63 - 5 : reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * bit 4 : enable/disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * bits 3-1 : duty cycle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * bit 0 : reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) l = (l & ~14);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) l = l | (1<<4) | ((newstate & 0x7)<<1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static struct cpufreq_frequency_table p4clockmod_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {0, DC_RESV, CPUFREQ_ENTRY_INVALID},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {0, DC_DFLT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {0, DC_25PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {0, DC_38PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {0, DC_50PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {0, DC_64PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {0, DC_75PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {0, DC_88PT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {0, DC_DISABLE, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {0, DC_RESV, CPUFREQ_TABLE_END},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* run on each logical CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * see section 13.15.3 of IA32 Intel Architecture Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Developer's Manual, Volume 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) for_each_cpu(i, policy->cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (c->x86 == 0x06) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (cpu_has(c, X86_FEATURE_EST))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pr_warn_once("Warning: EST-capable CPU detected. The acpi-cpufreq module offers voltage scaling in addition to frequency scaling. You should use that instead of p4-clockmod, if possible.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) switch (c->x86_model) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case 0x0E: /* Core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case 0x0F: /* Core Duo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case 0x16: /* Celeron Core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) case 0x1C: /* Atom */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case 0x0D: /* Pentium M (Dothan) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) case 0x09: /* Pentium M (Banias) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return speedstep_get_frequency(SPEEDSTEP_CPU_PM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (c->x86 != 0xF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* on P-4s, the TSC runs with constant frequency independent whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * throttling is active or not. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) pr_warn("Warning: Pentium 4-M detected. The speedstep-ich or acpi cpufreq modules offer voltage scaling in addition of frequency scaling. You should use either one instead of p4-clockmod, if possible.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return speedstep_get_frequency(SPEEDSTEP_CPU_P4M);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return speedstep_get_frequency(SPEEDSTEP_CPU_P4D);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct cpuinfo_x86 *c = &cpu_data(policy->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) int cpuid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) cpumask_copy(policy->cpus, topology_sibling_cpumask(policy->cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Errata workaround */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_stepping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) switch (cpuid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case 0x0f07:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case 0x0f0a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case 0x0f11:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) case 0x0f12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) has_N44_O17_errata[policy->cpu] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) pr_debug("has errata -- disabling low frequencies\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) c->x86_model < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* switch to maximum frequency and measure result */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) cpufreq_p4_setdc(policy->cpu, DC_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) recalibrate_cpu_khz();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* get max frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) stock_freq = cpufreq_p4_get_frequency(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (!stock_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* table init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if ((i < 2) && (has_N44_O17_errata[policy->cpu]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) p4clockmod_table[i].frequency = (stock_freq * i)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* cpuinfo and default policy values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* the transition latency is set to be 1 higher than the maximum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * transition latency of the ondemand governor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) policy->cpuinfo.transition_latency = 10000001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) policy->freq_table = &p4clockmod_table[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static unsigned int cpufreq_p4_get(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) u32 l, h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (l & 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) l = l >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) l &= 0x7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) l = DC_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (l != DC_DISABLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return stock_freq * l / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return stock_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static struct cpufreq_driver p4clockmod_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .verify = cpufreq_generic_frequency_table_verify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .target_index = cpufreq_p4_target,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .init = cpufreq_p4_cpu_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .get = cpufreq_p4_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .name = "p4-clockmod",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .attr = cpufreq_generic_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static const struct x86_cpu_id cpufreq_p4_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_ACC, NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Intentionally no MODULE_DEVICE_TABLE here: this driver should not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * be auto loaded. Please don't add one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) static int __init cpufreq_p4_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * THERM_CONTROL is architectural for IA32 now, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * we can rely on the capability checks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (!x86_match_cpu(cpufreq_p4_id) || !boot_cpu_has(X86_FEATURE_ACPI))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ret = cpufreq_register_driver(&p4clockmod_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pr_info("P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static void __exit cpufreq_p4_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) cpufreq_unregister_driver(&p4clockmod_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) late_initcall(cpufreq_p4_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) module_exit(cpufreq_p4_exit);