* 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
+ * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
* for extensive testing.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*********************************************************************/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
/* 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
+ * 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.
*/
-static struct pci_dev *speedstep_chipset_dev;
+static struct pci_dev *speedstep_chipset_dev;
/* speedstep_processor
*/
-static unsigned int speedstep_processor = 0;
+static unsigned int speedstep_processor = 0;
-/*
+/*
* There are only two frequency states for each processor. Values
* are in kHz for the time being.
*/
static struct cpufreq_frequency_table speedstep_freqs[] = {
- {SPEEDSTEP_HIGH, 0},
+ {SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_LOW, 0},
{0, CPUFREQ_TABLE_END},
};
-/* DEBUG
- * Define it if you want verbose debug output, e.g. for bug reporting
- */
-//#define SPEEDSTEP_DEBUG
-
-#ifdef SPEEDSTEP_DEBUG
-#define dprintk(msg...) printk(msg)
-#else
-#define dprintk(msg...) do { } while(0)
-#endif
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg)
/**
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
*
- * Tries to change the SpeedStep state.
+ * Tries to change the SpeedStep state.
*/
static void speedstep_set_state (unsigned int state)
{
- u32 pmbase;
- u8 pm2_blk;
- u8 value;
- unsigned long flags;
+ u32 pmbase;
+ u8 pm2_blk;
+ u8 value;
+ unsigned long flags;
if (!speedstep_chipset_dev || (state > 0x1))
return;
/* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
- if (!(pmbase & 0x01))
- {
- printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+ if (!(pmbase & 0x01)) {
+ printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
return;
}
pmbase &= 0xFFFFFFFE;
if (!pmbase) {
- printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+ printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
return;
}
/* read state */
value = inb(pmbase + 0x50);
- dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+ dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
/* write new state */
value &= 0xFE;
value |= state;
- dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
+ dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
/* Disable bus master arbitration */
pm2_blk = inb(pmbase + 0x20);
/* Enable IRQs */
local_irq_restore(flags);
- dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+ dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
if (state == (value & 0x1)) {
- dprintk (KERN_INFO "cpufreq: change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
+ dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
} else {
printk (KERN_ERR "cpufreq: change failed - I/O error\n");
}
*/
static int speedstep_activate (void)
{
- u16 value = 0;
+ u16 value = 0;
if (!speedstep_chipset_dev)
return -EINVAL;
- pci_read_config_word(speedstep_chipset_dev,
- 0x00A0, &value);
+ pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
if (!(value & 0x08)) {
value |= 0x08;
- dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n");
- pci_write_config_word(speedstep_chipset_dev,
- 0x00A0, value);
+ dprintk("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
+ * 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.
*/
static unsigned int speedstep_detect_chipset (void)
{
- speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82801DB_12,
+ 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_find_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82801CA_12,
+ speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82801CA_12,
PCI_ANY_ID,
PCI_ANY_ID,
NULL);
return 3; /* 3-M */
- speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+ 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
+ * 8100 which use a pretty old revision of the 82815
* host brige. Abort on these systems.
*/
- static struct pci_dev *hostbridge;
- u8 rev = 0;
+ static struct pci_dev *hostbridge;
+ u8 rev = 0;
- hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+ hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_MC,
PCI_ANY_ID,
PCI_ANY_ID,
if (!hostbridge)
return 2; /* 2-M */
-
+
pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
if (rev < 5) {
- dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n");
+ dprintk("hostbridge does not support speedstep\n");
speedstep_chipset_dev = NULL;
+ pci_dev_put(hostbridge);
return 0;
}
+ pci_dev_put(hostbridge);
return 2; /* 2-M */
}
return 0;
}
+static unsigned int _speedstep_get(cpumask_t cpus)
+{
+ unsigned int speed;
+ cpumask_t cpus_allowed;
+
+ cpus_allowed = current->cpus_allowed;
+ set_cpus_allowed(current, cpus);
+ speed = speedstep_get_processor_frequency(speedstep_processor);
+ set_cpus_allowed(current, cpus_allowed);
+ dprintk("detected %u kHz as current frequency\n", speed);
+ return speed;
+}
+
+static unsigned int speedstep_get(unsigned int cpu)
+{
+ return _speedstep_get(cpumask_of_cpu(cpu));
+}
/**
* speedstep_target - set a new CPUFreq policy
unsigned int target_freq,
unsigned int relation)
{
- unsigned int newstate = 0;
+ unsigned int newstate = 0;
struct cpufreq_freqs freqs;
- cpumask_t cpus_allowed, affected_cpu_map;
+ cpumask_t cpus_allowed;
int i;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
return -EINVAL;
+ freqs.old = _speedstep_get(policy->cpus);
+ freqs.new = speedstep_freqs[newstate].frequency;
+ freqs.cpu = policy->cpu;
+
+ dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new);
+
/* no transition necessary */
if (freqs.old == freqs.new)
return 0;
- freqs.old = speedstep_get_processor_frequency(speedstep_processor);
- freqs.new = speedstep_freqs[newstate].frequency;
- freqs.cpu = policy->cpu;
-
cpus_allowed = current->cpus_allowed;
- /* only run on CPU to be set, or on its sibling */
-#ifdef CONFIG_SMP
- affected_cpu_map = cpu_sibling_map[policy->cpu];
-#else
- affected_cpu_map = cpumask_of_cpu(policy->cpu);
-#endif
-
- for_each_cpu_mask(i, affected_cpu_map) {
+ for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
/* switch to physical CPU where state is to be changed */
- set_cpus_allowed(current, affected_cpu_map);
+ set_cpus_allowed(current, policy->cpus);
speedstep_set_state(newstate);
/* allow to be run on all CPUs */
set_cpus_allowed(current, cpus_allowed);
- for_each_cpu_mask(i, affected_cpu_map) {
+ for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
- int result = 0;
- unsigned int speed;
- cpumask_t cpus_allowed,affected_cpu_map;
-
-
- /* capability check */
- if (policy->cpu != 0) /* FIXME: better support for SMT in cpufreq core. Up until then, it's better to register only one CPU */
- return -ENODEV;
+ int result = 0;
+ unsigned int speed;
+ cpumask_t cpus_allowed;
/* only run on CPU to be set, or on its sibling */
- cpus_allowed = current->cpus_allowed;
#ifdef CONFIG_SMP
- affected_cpu_map = cpu_sibling_map[policy->cpu];
-#else
- affected_cpu_map = cpumask_of_cpu(policy->cpu);
+ policy->cpus = cpu_sibling_map[policy->cpu];
#endif
- set_cpus_allowed(current, affected_cpu_map);
+
+ cpus_allowed = current->cpus_allowed;
+ set_cpus_allowed(current, policy->cpus);
/* detect low and high frequency */
result = speedstep_get_freqs(speedstep_processor,
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
&speedstep_set_state);
- if (result) {
- set_cpus_allowed(current, cpus_allowed);
+ set_cpus_allowed(current, cpus_allowed);
+ if (result)
return result;
- }
/* get current speed setting */
- speed = speedstep_get_processor_frequency(speedstep_processor);
- set_cpus_allowed(current, cpus_allowed);
+ speed = _speedstep_get(policy->cpus);
if (!speed)
return -EIO;
- dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n",
+ dprintk("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
(speed / 1000));
return 0;
}
-static unsigned int speedstep_get(unsigned int cpu)
-{
- return speedstep_get_processor_frequency(speedstep_processor);
-}
-
static struct freq_attr* speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
static struct cpufreq_driver speedstep_driver = {
- .name = "speedstep-ich",
- .verify = speedstep_verify,
- .target = speedstep_target,
- .init = speedstep_cpu_init,
- .exit = speedstep_cpu_exit,
- .get = speedstep_get,
- .owner = THIS_MODULE,
- .attr = speedstep_attr,
+ .name = "speedstep-ich",
+ .verify = speedstep_verify,
+ .target = speedstep_target,
+ .init = speedstep_cpu_init,
+ .exit = speedstep_cpu_exit,
+ .get = speedstep_get,
+ .owner = THIS_MODULE,
+ .attr = speedstep_attr,
};
{
/* detect processor */
speedstep_processor = speedstep_detect_processor();
- if (!speedstep_processor)
+ if (!speedstep_processor) {
+ dprintk("Intel(R) SpeedStep(TM) capable processor not found\n");
return -ENODEV;
+ }
/* detect chipset */
if (!speedstep_detect_chipset()) {
- printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n");
+ dprintk("Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n");
return -ENODEV;
}
/* activate speedstep support */
- if (speedstep_activate())
+ if (speedstep_activate()) {
+ pci_dev_put(speedstep_chipset_dev);
return -EINVAL;
+ }
return cpufreq_register_driver(&speedstep_driver);
}
*/
static void __exit speedstep_exit(void)
{
+ pci_dev_put(speedstep_chipset_dev);
cpufreq_unregister_driver(&speedstep_driver);
}