as the per-CPU initialization can fail, we need to deal with this situation in cpufreq_remove_dev as the sysdev core doesn't (yet) do this for us. The solution: add a "struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]" array, which has a NULL pointer for each CPU not managed by cpufreq (yet) and a pointer to the per-CPU data for each CPU managed by cpufreq. It is locked by cpufreq_driver_lock. diff -ruN linux-original/kernel/cpufreq.c linux/kernel/cpufreq.c --- linux-original/kernel/cpufreq.c 2003-07-12 22:01:26.000000000 +0200 +++ linux/kernel/cpufreq.c 2003-07-12 22:11:50.000000000 +0200 @@ -27,10 +27,11 @@ /** * The "cpufreq driver" - the arch- or hardware-dependend low - * level driver of CPUFreq support, and its spinlock. - * cpu_max_freq is in kHz. + * level driver of CPUFreq support, and its spinlock. This lock + * also protects the cpufreq_cpu_data array. */ static struct cpufreq_driver *cpufreq_driver; +static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; /* will go away once the locking mess is cleaned up */ @@ -71,7 +72,10 @@ /* get the CPU */ - data = &cpufreq_driver->policy[cpu]; + data = cpufreq_cpu_data[cpu]; + + if (!data) + goto err_out_put_module; if (!kobject_get(&data->kobj)) goto err_out_put_module; @@ -352,11 +356,12 @@ if (!try_module_get(cpufreq_driver->owner)) return -EINVAL; + policy = &cpufreq_driver->policy[cpu]; + policy->cpu = cpu; + /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ - policy = &cpufreq_driver->policy[cpu]; - policy->cpu = cpu; ret = cpufreq_driver->init(policy); if (ret) goto out; @@ -386,10 +391,17 @@ sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); drv_attr++; } + + spin_lock(&cpufreq_driver_lock); + cpufreq_cpu_data[cpu] = policy; + spin_unlock(&cpufreq_driver_lock); /* set default policy */ ret = cpufreq_set_policy(&new_policy); if (ret) { + spin_lock(&cpufreq_driver_lock); + cpufreq_cpu_data[cpu] = NULL; + spin_unlock(&cpufreq_driver_lock); kobject_unregister(&policy->kobj); wait_for_completion(&policy->kobj_unregister); } @@ -409,6 +421,14 @@ { unsigned int cpu = sys_dev->id; + spin_lock(&cpufreq_driver_lock); + if (!cpufreq_cpu_data[cpu]) { + spin_unlock(&cpufreq_driver_lock); + return -EINVAL; + } + cpufreq_cpu_data[cpu] = NULL; + spin_unlock(&cpufreq_driver_lock); + if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) return -EFAULT;