// SPDX-License-Identifier: GPL-2.0-only /* * (C) 2001 Dave Jones, Arjan van de ven. * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> * * Based upon reverse engineered information, and on Intel documentation * for chipsets ICH2-M and ICH3-M. * * Many thanks to Ducrot Bruno for finding and fixing the last * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler * for extensive testing. * * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/
/* speedstep_chipset: * It is necessary to know which chipset is used. As accesses to * this device occur at various places in this module, we need a * static struct pci_dev * pointing to that device.
*/ staticstruct pci_dev *speedstep_chipset_dev;
/* * There are only two frequency states for each processor. Values * are in kHz for the time being.
*/ staticstruct cpufreq_frequency_table speedstep_freqs[] = {
{0, SPEEDSTEP_HIGH, 0},
{0, SPEEDSTEP_LOW, 0},
{0, 0, CPUFREQ_TABLE_END},
};
/** * speedstep_find_register - read the PMBASE address * * Returns: -ENODEV if no register could be found
*/ staticint speedstep_find_register(void)
{ if (!speedstep_chipset_dev) return -ENODEV;
/* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); if (!(pmbase & 0x01)) {
pr_err("could not find speedstep register\n"); return -ENODEV;
}
pmbase &= 0xFFFFFFFE; if (!pmbase) {
pr_err("could not find speedstep register\n"); return -ENODEV;
}
pr_debug("pmbase is 0x%x\n", pmbase); return 0;
}
/** * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * * Tries to change the SpeedStep state. Can be called from * smp_call_function_single.
*/ staticvoid speedstep_set_state(unsignedint state)
{
u8 pm2_blk;
u8 value; unsignedlong flags;
if (state > 0x1) return;
/* Disable IRQs */
local_irq_save(flags);
/* read state */
value = inb(pmbase + 0x50);
pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
/* write new state */
value &= 0xFE;
value |= state;
pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
/** * speedstep_activate - activate SpeedStep control in the chipset * * Tries to activate the SpeedStep status and control registers. * Returns -EINVAL on an unsupported chipset, and zero on success.
*/ staticint speedstep_activate(void)
{
u16 value = 0;
if (!speedstep_chipset_dev) return -EINVAL;
pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) {
value |= 0x08;
pr_debug("activating SpeedStep (TM) registers\n");
pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
}
return 0;
}
/** * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic * * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to * the LPC bridge / PM module which contains all power-management * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected * chipset, or zero on failure.
*/ staticunsignedint speedstep_detect_chipset(void)
{
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801DB_12,
PCI_ANY_ID, PCI_ANY_ID,
NULL); if (speedstep_chipset_dev) return 4; /* 4-M */
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801BA_10,
PCI_ANY_ID, PCI_ANY_ID,
NULL); if (speedstep_chipset_dev) { /* speedstep.c causes lockups on Dell Inspirons 8000 and * 8100 which use a pretty old revision of the 82815 * host bridge. Abort on these systems.
*/ struct pci_dev *hostbridge;
if (hostbridge->revision < 5) {
pr_debug("hostbridge does not support speedstep\n");
speedstep_chipset_dev = NULL;
pci_dev_put(hostbridge); return 0;
}
/* You're supposed to ensure CPU is online. */
BUG_ON(smp_call_function_single(cpu, get_freq_data, &speed, 1));
pr_debug("detected %u kHz as current frequency\n", speed); return speed;
}
/** * speedstep_target - set a new CPUFreq policy * @policy: new policy * @index: index of target frequency * * Sets a new CPUFreq policy.
*/ staticint speedstep_target(struct cpufreq_policy *policy, unsignedint index)
{ unsignedint policy_cpu;
/* only run on CPU to be set, or on its sibling */ #ifdef CONFIG_SMP
cpumask_copy(policy->cpus, topology_sibling_cpumask(policy->cpu)); #endif
policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask);
/* detect low and high frequency and transition latency */
gf.policy = policy;
smp_call_function_single(policy_cpu, get_freqs_on_cpu, &gf, 1); if (gf.ret) return gf.ret;
/** * speedstep_init - initializes the SpeedStep CPUFreq driver * * Initializes the SpeedStep support. Returns -ENODEV on unsupported * devices, -EINVAL on problems during initiatization, and zero on * success.
*/ staticint __init speedstep_init(void)
{ if (!x86_match_cpu(ss_smi_ids)) return -ENODEV;
/* detect chipset */ if (!speedstep_detect_chipset()) {
pr_debug("Intel(R) SpeedStep(TM) for this chipset not " "(yet) available.\n"); return -ENODEV;
}
/* activate speedstep support */ if (speedstep_activate()) {
pci_dev_put(speedstep_chipset_dev); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.