vserver 1.9.5.x5
[linux-2.6.git] / arch / i386 / kernel / cpu / cpufreq / speedstep-ich.c
index 93b70f0..5b7d18a 100644 (file)
@@ -7,7 +7,7 @@
  *  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*
@@ -19,7 +19,7 @@
  *********************************************************************/
 
 #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;
        }
 
@@ -100,13 +90,13 @@ static void speedstep_set_state (unsigned int state)
        /* 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);
@@ -126,10 +116,10 @@ static void speedstep_set_state (unsigned int state)
        /* 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");
        }
@@ -146,18 +136,16 @@ static void speedstep_set_state (unsigned int state)
  */
 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;
@@ -167,23 +155,23 @@ static int speedstep_activate (void)
 /**
  * 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);
@@ -191,20 +179,20 @@ static unsigned int speedstep_detect_chipset (void)
                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,
@@ -212,20 +200,39 @@ static unsigned int speedstep_detect_chipset (void)
 
                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
@@ -239,45 +246,40 @@ static int speedstep_target (struct cpufreq_policy *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);
        }
@@ -301,41 +303,33 @@ static int speedstep_verify (struct cpufreq_policy *policy)
 
 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));
 
@@ -360,11 +354,6 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
        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,
@@ -372,14 +361,14 @@ static struct freq_attr* speedstep_attr[] = {
 
 
 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,
 };
 
 
@@ -394,18 +383,22 @@ static int __init speedstep_init(void)
 {
        /* 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);
 }
@@ -418,6 +411,7 @@ static int __init speedstep_init(void)
  */
 static void __exit speedstep_exit(void)
 {
+       pci_dev_put(speedstep_chipset_dev);
        cpufreq_unregister_driver(&speedstep_driver);
 }