Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 21:28:20 +0000 (13:28 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 21:28:20 +0000 (13:28 -0800)
1  2 
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/i386/kernel/cpu/cpufreq/powernow-k8.c
arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c

index caa9f77113439c3aa4fb0276c1c21961151baf64,22b5622897f098cc3872bee81f0c726f7cc37b8f..871366b83b3f40cbc38ee91ec099e6cf3e5e15d0
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/compiler.h>
 +#include <linux/sched.h>      /* current */
  #include <asm/io.h>
  #include <asm/delay.h>
  #include <asm/uaccess.h>
@@@ -377,10 -376,9 +377,9 @@@ acpi_cpufreq_cpu_init 
          arg0.buffer.length = 12;
          arg0.buffer.pointer = (u8 *) arg0_buf;
  
-       data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+       data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
        if (!data)
                return (-ENOMEM);
-       memset(data, 0, sizeof(struct cpufreq_acpi_io));
  
        acpi_io_data[cpu] = data;
  
index 2d5c9adba0cdc9a183743993dd3f2a794ccc6e47,beb101157bd915005e0c1f9c6db4f497a62012fd..68a1fc87f4cabb6cb63b71a9c84bc0132494365a
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <linux/cpumask.h>
 +#include <linux/sched.h>      /* for current / set_cpus_allowed() */
  
  #include <asm/msr.h>
  #include <asm/io.h>
@@@ -45,7 -44,7 +45,7 @@@
  
  #define PFX "powernow-k8: "
  #define BFX PFX "BIOS error: "
 -#define VERSION "version 1.50.3"
 +#define VERSION "version 1.50.4"
  #include "powernow-k8.h"
  
  /* serialize freq changes  */
@@@ -112,8 -111,8 +112,8 @@@ static int query_current_values_with_pe
        u32 i = 0;
  
        do {
 -              if (i++ > 0x1000000) {
 -                      printk(KERN_ERR PFX "detected change pending stuck\n");
 +              if (i++ > 10000) {
 +                      dprintk("detected change pending stuck\n");
                        return 1;
                }
                rdmsr(MSR_FIDVID_STATUS, lo, hi);
@@@ -160,7 -159,6 +160,7 @@@ static int write_new_fid(struct powerno
  {
        u32 lo;
        u32 savevid = data->currvid;
 +      u32 i = 0;
  
        if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
                printk(KERN_ERR PFX "internal error - overflow on fid write\n");
        dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
                fid, lo, data->plllock * PLL_LOCK_CONVERSION);
  
 -      wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
 -
 -      if (query_current_values_with_pending_wait(data))
 -              return 1;
 +      do {
 +              wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
 +              if (i++ > 100) {
 +                      printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n");
 +                      return 1;
 +              }                       
 +      } while (query_current_values_with_pending_wait(data));
  
        count_off_irt(data);
  
@@@ -202,7 -197,6 +202,7 @@@ static int write_new_vid(struct powerno
  {
        u32 lo;
        u32 savefid = data->currfid;
 +      int i = 0;
  
        if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
                printk(KERN_ERR PFX "internal error - overflow on vid write\n");
        dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
                vid, lo, STOP_GRANT_5NS);
  
 -      wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
 -
 -      if (query_current_values_with_pending_wait(data))
 -              return 1;
 +      do {
 +              wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
 +                if (i++ > 100) {
 +                        printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n");
 +                        return 1;
 +                }
 +      } while (query_current_values_with_pending_wait(data));
  
        if (savefid != data->currfid) {
                printk(KERN_ERR PFX "fid changed on vid trans, old 0x%x new 0x%x\n",
@@@ -462,7 -453,6 +462,6 @@@ static int check_supported_cpu(unsigne
  
        oldmask = current->cpus_allowed;
        set_cpus_allowed(current, cpumask_of_cpu(cpu));
-       schedule();
  
        if (smp_processor_id() != cpu) {
                printk(KERN_ERR "limiting to cpu %u failed\n", cpu);
  
  out:
        set_cpus_allowed(current, oldmask);
-       schedule();
        return rc;
  }
  
  static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
@@@ -913,7 -901,6 +910,6 @@@ static int powernowk8_target(struct cpu
        /* only run on specific CPU from here on */
        oldmask = current->cpus_allowed;
        set_cpus_allowed(current, cpumask_of_cpu(pol->cpu));
-       schedule();
  
        if (smp_processor_id() != pol->cpu) {
                printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu);
  
  err_out:
        set_cpus_allowed(current, oldmask);
-       schedule();
        return ret;
  }
  
@@@ -991,12 -976,11 +985,11 @@@ static int __init powernowk8_cpu_init(s
        if (!check_supported_cpu(pol->cpu))
                return -ENODEV;
  
-       data = kmalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
+       data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
        if (!data) {
                printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
                return -ENOMEM;
        }
-       memset(data,0,sizeof(struct powernow_k8_data));
  
        data->cpu = pol->cpu;
  
        /* only run on specific CPU from here on */
        oldmask = current->cpus_allowed;
        set_cpus_allowed(current, cpumask_of_cpu(pol->cpu));
-       schedule();
  
        if (smp_processor_id() != pol->cpu) {
                printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu);
  
        /* run on any CPU again */
        set_cpus_allowed(current, oldmask);
-       schedule();
  
        pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
        pol->cpus = cpu_core_map[pol->cpu];
  
  err_out:
        set_cpus_allowed(current, oldmask);
-       schedule();
        powernow_k8_cpu_exit_acpi(data);
  
        kfree(data);
@@@ -1116,17 -1097,14 +1106,14 @@@ static unsigned int powernowk8_get (uns
                set_cpus_allowed(current, oldmask);
                return 0;
        }
-       preempt_disable();
-       
        if (query_current_values_with_pending_wait(data))
                goto out;
  
        khz = find_khz_freq_from_fid(data->currfid);
  
-  out:
-       preempt_enable_no_resched();
+ out:
        set_cpus_allowed(current, oldmask);
        return khz;
  }
  
index 0ea010a7afb15bb8d95d0c62afeb77bed13aaaf5,92936c1e173b96dbddbc4235e40ca4ad4a898b42..edb9873e27e37fbb7ee1f66c89c5e87436bec3bd
@@@ -22,7 -22,6 +22,7 @@@
  #include <linux/init.h>
  #include <linux/cpufreq.h>
  #include <linux/config.h>
 +#include <linux/sched.h>      /* current */
  #include <linux/delay.h>
  #include <linux/compiler.h>
  
@@@ -67,7 -66,7 +67,7 @@@ static const struct cpu_id cpu_ids[] = 
        [CPU_MP4HT_D0]  = {15,  3, 4 },
        [CPU_MP4HT_E0]  = {15,  4, 1 },
  };
 -#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0]))
 +#define N_IDS ARRAY_SIZE(cpu_ids)
  
  struct cpu_model
  {
@@@ -423,12 -422,11 +423,11 @@@ static int centrino_cpu_init_acpi(struc
                }
        }
  
-       centrino_model[cpu] = kmalloc(sizeof(struct cpu_model), GFP_KERNEL);
+       centrino_model[cpu] = kzalloc(sizeof(struct cpu_model), GFP_KERNEL);
        if (!centrino_model[cpu]) {
                result = -ENOMEM;
                goto err_unreg;
        }
-       memset(centrino_model[cpu], 0, sizeof(struct cpu_model));
  
        centrino_model[cpu]->model_name=NULL;
        centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000;
index 6c6121b85a54ba36168a73a737a0163e179f79a7,cfe1d0a2262de60cae563813448022f2a1076f37..25acf478c9e82c5f2d40cd6c89e9c8fcdb2862be
@@@ -4,9 -4,6 +4,9 @@@
   *  Copyright (C) 2001 Russell King
   *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
   *
 + *  Oct 2005 - Ashok Raj <ashok.raj@intel.com>
 + *                    Added handling for CPU hotplug
 + *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
@@@ -39,6 -36,13 +39,6 @@@ static struct cpufreq_policy *cpufreq_c
  static DEFINE_SPINLOCK(cpufreq_driver_lock);
  
  
 -/* we keep a copy of all ->add'ed CPU's struct sys_device here;
 - * as it is only accessed in ->add and ->remove, no lock or reference
 - * count is necessary.
 - */
 -static struct sys_device      *cpu_sys_devices[NR_CPUS];
 -
 -
  /* internal prototypes */
  static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
  static void handle_update(void *data);
@@@ -570,9 -574,6 +570,9 @@@ static int cpufreq_add_dev (struct sys_
        unsigned long flags;
        unsigned int j;
  
 +      if (cpu_is_offline(cpu))
 +              return 0;
 +
        cpufreq_debug_disable_ratelimit();
        dprintk("adding CPU %u\n", cpu);
  
         * CPU because it is in the same boat. */
        policy = cpufreq_cpu_get(cpu);
        if (unlikely(policy)) {
 -              cpu_sys_devices[cpu] = sys_dev;
                dprintk("CPU already managed, adding link\n");
                sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq");
                cpufreq_debug_enable_ratelimit();
                goto module_out;
        }
  
-       policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+       policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
        if (!policy) {
                ret = -ENOMEM;
                goto nomem_out;
        }
-       memset(policy, 0, sizeof(struct cpufreq_policy));
  
        policy->cpu = cpu;
        policy->cpus = cpumask_of_cpu(cpu);
        }
  
        module_put(cpufreq_driver->owner);
 -      cpu_sys_devices[cpu] = sys_dev;
        dprintk("initialization complete\n");
        cpufreq_debug_enable_ratelimit();
        
@@@ -679,7 -681,7 +678,7 @@@ err_out
  
  nomem_out:
        module_put(cpufreq_driver->owner);
 - module_out:
 +module_out:
        cpufreq_debug_enable_ratelimit();
        return ret;
  }
@@@ -695,7 -697,6 +694,7 @@@ static int cpufreq_remove_dev (struct s
        unsigned int cpu = sys_dev->id;
        unsigned long flags;
        struct cpufreq_policy *data;
 +      struct sys_device *cpu_sys_dev;
  #ifdef CONFIG_SMP
        unsigned int j;
  #endif
  
        if (!data) {
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 -              cpu_sys_devices[cpu] = NULL;
                cpufreq_debug_enable_ratelimit();
                return -EINVAL;
        }
                dprintk("removing link\n");
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
                sysfs_remove_link(&sys_dev->kobj, "cpufreq");
 -              cpu_sys_devices[cpu] = NULL;
                cpufreq_cpu_put(data);
                cpufreq_debug_enable_ratelimit();
                return 0;
        }
  #endif
  
 -      cpu_sys_devices[cpu] = NULL;
  
        if (!kobject_get(&data->kobj)) {
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
                        if (j == cpu)
                                continue;
                        dprintk("removing link for cpu %u\n", j);
 -                      sysfs_remove_link(&cpu_sys_devices[j]->kobj, "cpufreq");
 +                      cpu_sys_dev = get_cpu_sysdev(j);
 +                      sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
                        cpufreq_cpu_put(data);
                }
        }
        down(&data->lock);
        if (cpufreq_driver->target)
                __cpufreq_governor(data, CPUFREQ_GOV_STOP);
 -      cpufreq_driver->target = NULL;
        up(&data->lock);
  
        kobject_unregister(&data->kobj);
@@@ -1114,30 -1118,17 +1113,30 @@@ int __cpufreq_driver_target(struct cpuf
                            unsigned int relation)
  {
        int retval = -EINVAL;
 -      lock_cpu_hotplug();
 +
 +      /*
 +       * Converted the lock_cpu_hotplug to preempt_disable()
 +       * and preempt_enable(). This is a bit kludgy and relies on how cpu
 +       * hotplug works. All we need is a guarantee that cpu hotplug won't make
 +       * progress on any cpu. Once we do preempt_disable(), this would ensure
 +       * that hotplug threads don't get onto this cpu, thereby delaying
 +       * the cpu remove process.
 +       *
 +       * We removed the lock_cpu_hotplug since we need to call this function
 +       * via cpu hotplug callbacks, which result in locking the cpu hotplug
 +       * thread itself. Agree this is not very clean, cpufreq community
 +       * could improve this if required. - Ashok Raj <ashok.raj@intel.com>
 +       */
 +      preempt_disable();
        dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
                target_freq, relation);
        if (cpu_online(policy->cpu) && cpufreq_driver->target)
                retval = cpufreq_driver->target(policy, target_freq, relation);
 -      unlock_cpu_hotplug();
 +      preempt_enable();
        return retval;
  }
  EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
  
 -
  int cpufreq_driver_target(struct cpufreq_policy *policy,
                          unsigned int target_freq,
                          unsigned int relation)
@@@ -1424,45 -1415,6 +1423,45 @@@ int cpufreq_update_policy(unsigned int 
  }
  EXPORT_SYMBOL(cpufreq_update_policy);
  
 +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
 +                                      unsigned long action, void *hcpu)
 +{
 +      unsigned int cpu = (unsigned long)hcpu;
 +      struct cpufreq_policy *policy;
 +      struct sys_device *sys_dev;
 +
 +      sys_dev = get_cpu_sysdev(cpu);
 +
 +      if (sys_dev) {
 +              switch (action) {
 +              case CPU_ONLINE:
 +                      cpufreq_add_dev(sys_dev);
 +                      break;
 +              case CPU_DOWN_PREPARE:
 +                      /*
 +                       * We attempt to put this cpu in lowest frequency
 +                       * possible before going down. This will permit
 +                       * hardware-managed P-State to switch other related
 +                       * threads to min or higher speeds if possible.
 +                       */
 +                      policy = cpufreq_cpu_data[cpu];
 +                      if (policy) {
 +                              cpufreq_driver_target(policy, policy->min,
 +                                              CPUFREQ_RELATION_H);
 +                      }
 +                      break;
 +              case CPU_DEAD:
 +                      cpufreq_remove_dev(sys_dev);
 +                      break;
 +              }
 +      }
 +      return NOTIFY_OK;
 +}
 +
 +static struct notifier_block cpufreq_cpu_notifier =
 +{
 +    .notifier_call = cpufreq_cpu_callback,
 +};
  
  /*********************************************************************
   *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
@@@ -1523,7 -1475,6 +1522,7 @@@ int cpufreq_register_driver(struct cpuf
        }
  
        if (!ret) {
 +              register_cpu_notifier(&cpufreq_cpu_notifier);
                dprintk("driver %s up and running\n", driver_data->name);
                cpufreq_debug_enable_ratelimit();
        }
@@@ -1555,7 -1506,6 +1554,7 @@@ int cpufreq_unregister_driver(struct cp
        dprintk("unregistering driver %s\n", driver->name);
  
        sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
 +      unregister_cpu_notifier(&cpufreq_cpu_notifier);
  
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
        cpufreq_driver = NULL;
index 3597f25d5efa8957a0ee1ed8389131a71675f91d,7ddf714c4d437477156eb1da5173d347a78bed5f..0bddb8e694d9bbde6acd604c540383e65524e2f9
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/percpu.h>
  #include <linux/kobject.h>
  #include <linux/spinlock.h>
 +#include <linux/notifier.h>
  #include <asm/cputime.h>
  
  static spinlock_t cpufreq_stats_lock;
@@@ -193,11 -192,15 +193,15 @@@ cpufreq_stats_create_table (struct cpuf
        unsigned int cpu = policy->cpu;
        if (cpufreq_stats_table[cpu])
                return -EBUSY;
-       if ((stat = kmalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL)
+       if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL)
                return -ENOMEM;
-       memset(stat, 0, sizeof (struct cpufreq_stats));
  
        data = cpufreq_cpu_get(cpu);
+       if (data == NULL) {
+               ret = -EINVAL;
+               goto error_get_fail;
+       }
        if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group)))
                goto error_out;
  
        alloc_size += count * count * sizeof(int);
  #endif
        stat->max_state = count;
-       stat->time_in_state = kmalloc(alloc_size, GFP_KERNEL);
+       stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
        if (!stat->time_in_state) {
                ret = -ENOMEM;
                goto error_out;
        }
-       memset(stat->time_in_state, 0, alloc_size);
        stat->freq_table = (unsigned int *)(stat->time_in_state + count);
  
  #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        return 0;
  error_out:
        cpufreq_cpu_put(data);
+ error_get_fail:
        kfree(stat);
        cpufreq_stats_table[cpu] = NULL;
        return ret;
@@@ -299,27 -302,6 +303,27 @@@ cpufreq_stat_notifier_trans (struct not
        return 0;
  }
  
 +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
 +                                      unsigned long action, void *hcpu)
 +{
 +      unsigned int cpu = (unsigned long)hcpu;
 +
 +      switch (action) {
 +      case CPU_ONLINE:
 +              cpufreq_update_policy(cpu);
 +              break;
 +      case CPU_DEAD:
 +              cpufreq_stats_free_table(cpu);
 +              break;
 +      }
 +      return NOTIFY_OK;
 +}
 +
 +static struct notifier_block cpufreq_stat_cpu_notifier =
 +{
 +      .notifier_call = cpufreq_stat_cpu_callback,
 +};
 +
  static struct notifier_block notifier_policy_block = {
        .notifier_call = cpufreq_stat_notifier_policy
  };
@@@ -333,7 -315,6 +337,7 @@@ __init cpufreq_stats_init(void
  {
        int ret;
        unsigned int cpu;
 +
        spin_lock_init(&cpufreq_stats_lock);
        if ((ret = cpufreq_register_notifier(&notifier_policy_block,
                                CPUFREQ_POLICY_NOTIFIER)))
                return ret;
        }
  
 -      for_each_cpu(cpu)
 -              cpufreq_update_policy(cpu);
 +      register_cpu_notifier(&cpufreq_stat_cpu_notifier);
 +      lock_cpu_hotplug();
 +      for_each_online_cpu(cpu) {
 +              cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
 +                      (void *)(long)cpu);
 +      }
 +      unlock_cpu_hotplug();
        return 0;
  }
  static void
  __exit cpufreq_stats_exit(void)
  {
        unsigned int cpu;
 +
        cpufreq_unregister_notifier(&notifier_policy_block,
                        CPUFREQ_POLICY_NOTIFIER);
        cpufreq_unregister_notifier(&notifier_trans_block,
                        CPUFREQ_TRANSITION_NOTIFIER);
 -      for_each_cpu(cpu)
 -              cpufreq_stats_free_table(cpu);
 +      unregister_cpu_notifier(&cpufreq_stat_cpu_notifier);
 +      lock_cpu_hotplug();
 +      for_each_online_cpu(cpu) {
 +              cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
 +                      (void *)(long)cpu);
 +      }
 +      unlock_cpu_hotplug();
  }
  
  MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");