GIT e925e85aecaebd467cbec1662a6a7f2832e2b4a0 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq.git commit Author: RafaƂ Bilski Date: Fri Mar 2 20:12:27 2007 +0100 [CPUFREQ] Longhaul - Correct PCI code Replace obsolete pci_find_device with pci_get_device. Signed-off-by: Rafal Bilski Signed-off-by: Dave Jones commit c3de34888e78f0fd6b043dfc5df0f4e8b742b443 Author: Alexey Dobriyan Date: Mon Mar 19 19:17:00 2007 +0300 [CPUFREQ] p4-clockmod: switch to rdmsr_on_cpu/wrmsr_on_cpu Dances with cpumasks go away. Signed-off-by: Alexey Dobriyan Signed-off-by: Dave Jones commit 38bcdd030a142f989b3d616efc5dd08d33898f79 Author: Mattia Dongili Date: Thu Mar 22 18:02:01 2007 +0100 [CPUFREQ] fix cpufreq_stats attrs removal There are other symptoms to this same bug: 1. unload p4-clockmod: /sys/.../cpu0/cpufreq is removed all together 2. load p4-clockmod: /sys/.../cpu0/cpufreq appears but no 'stats' subdir (yes, cpufreq_stats is loaded) 3. rmmod cpufreq_stats: Ooops! Call Trace: [] remove_dir+0x33/0xc4 [] remove_files+0x1a/0x28 [] sysfs_remove_group+0x63/0x71 [] cpufreq_stat_cpu_callback+0x51/0x8a [cpufreq_stats] [] cpufreq_stats_exit+0x47/0x4b [cpufreq_stats] [] sys_delete_module+0x190/0x1b7 [] do_wp_page+0x231/0x3e7 [] syscall_call+0x7/0xb The problem is cpufreq_stats doesn't know when a cpufreq driver is removed and doesn't cleanup. I guess this affects any setup with cpufreq_stats. The attached patch seems to solve both symptoms and yes... it's quite invasive as it introduce one more cpufreq policy notification (REMOVED). Signed-off-by: Mattia Dongili Signed-off-by: Dave Jones arch/i386/kernel/cpu/cpufreq/longhaul.c | 19 +++++++++++------ arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 31 +++++----------------------- drivers/cpufreq/cpufreq.c | 4 ++++ drivers/cpufreq/cpufreq_stats.c | 26 ++++++++++++++--------- include/linux/cpufreq.h | 1 + 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index a1f1b71..3d37f8d 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -590,20 +590,23 @@ static acpi_status longhaul_walk_callbac static int enable_arbiter_disable(void) { struct pci_dev *dev; + int status; int reg; u8 pci_cmd; + status = 1; /* Find PLE133 host bridge */ reg = 0x78; - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, + NULL); /* Find CLE266 host bridge */ if (dev == NULL) { reg = 0x76; - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_862X_0, NULL); /* Find CN400 V-Link host bridge */ if (dev == NULL) - dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); - + dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); } if (dev != NULL) { /* Enable access to port 0x22 */ @@ -615,10 +618,11 @@ static int enable_arbiter_disable(void) if (!(pci_cmd & 1<<7)) { printk(KERN_ERR PFX "Can't enable access to port 0x22.\n"); - return 0; + status = 0; } } - return 1; + pci_dev_put(dev); + return status; } return 0; } @@ -629,7 +633,7 @@ static int longhaul_setup_vt8235(void) u8 pci_cmd; /* Find VT8235 southbridge */ - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); if (dev != NULL) { /* Set transition time to max */ pci_read_config_byte(dev, 0xec, &pci_cmd); @@ -641,6 +645,7 @@ static int longhaul_setup_vt8235(void) pci_read_config_byte(dev, 0xe5, &pci_cmd); pci_cmd |= 1 << 7; pci_write_config_byte(dev, 0xe5, pci_cmd); + pci_dev_put(dev); return 1; } return 0; diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 4786fed..4c76b51 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -27,7 +27,6 @@ #include #include #include #include -#include /* current / set_cpus_allowed() */ #include #include @@ -62,7 +61,7 @@ static int cpufreq_p4_setdc(unsigned int if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; - rdmsr(MSR_IA32_THERM_STATUS, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); if (l & 0x01) dprintk("CPU#%d currently thermal throttled\n", cpu); @@ -70,10 +69,10 @@ static int cpufreq_p4_setdc(unsigned int if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) newstate = DC_38PT; - rdmsr(MSR_IA32_THERM_CONTROL, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (newstate == DC_DISABLE) { dprintk("CPU#%d disabling modulation\n", cpu); - wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { dprintk("CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); @@ -84,7 +83,7 @@ static int cpufreq_p4_setdc(unsigned int */ l = (l & ~14); l = l | (1<<4) | ((newstate & 0x7)<<1); - wrmsr(MSR_IA32_THERM_CONTROL, l, h); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); } return 0; @@ -111,7 +110,6 @@ static int cpufreq_p4_target(struct cpuf { unsigned int newstate = DC_RESV; struct cpufreq_freqs freqs; - cpumask_t cpus_allowed; int i; if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) @@ -132,17 +130,8 @@ static int cpufreq_p4_target(struct cpuf /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ - cpus_allowed = current->cpus_allowed; - - for_each_cpu_mask(i, policy->cpus) { - cpumask_t this_cpu = cpumask_of_cpu(i); - - set_cpus_allowed(current, this_cpu); - BUG_ON(smp_processor_id() != i); - + for_each_cpu_mask(i, policy->cpus) cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); - } - set_cpus_allowed(current, cpus_allowed); /* notifiers */ for_each_cpu_mask(i, policy->cpus) { @@ -256,17 +245,9 @@ static int cpufreq_p4_cpu_exit(struct cp static unsigned int cpufreq_p4_get(unsigned int cpu) { - cpumask_t cpus_allowed; u32 l, h; - cpus_allowed = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - BUG_ON(smp_processor_id() != cpu); - - rdmsr(MSR_IA32_THERM_CONTROL, l, h); - - set_cpus_allowed(current, cpus_allowed); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (l & 0x10) { l = l >> 1; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3162010..ef6fb0e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -989,6 +989,10 @@ #endif unlock_policy_rwsem_write(cpu); + /* notify of policy cancellation */ + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_REMOVE, data); + kobject_unregister(&data->kobj); kobject_put(&data->kobj); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index d1c7cac..c3c03de 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -257,18 +257,23 @@ static int cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val, void *data) { - int ret; + int ret = 0; struct cpufreq_policy *policy = data; struct cpufreq_frequency_table *table; unsigned int cpu = policy->cpu; - if (val != CPUFREQ_NOTIFY) - return 0; - table = cpufreq_frequency_get_table(cpu); - if (!table) - return 0; - if ((ret = cpufreq_stats_create_table(policy, table))) - return ret; - return 0; + switch (val) { + case CPUFREQ_NOTIFY: + table = cpufreq_frequency_get_table(cpu); + if (!table) + break; + ret = cpufreq_stats_create_table(policy, table); + break; + + case CPUFREQ_REMOVE: + cpufreq_stats_free_table(cpu); + break; + } + return ret; } static int @@ -371,8 +376,7 @@ __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_DEAD, (void *)(long)cpu); + cpufreq_stats_free_table(cpu); } } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0899e2c..2cb19c5 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -96,6 +96,7 @@ struct cpufreq_policy { #define CPUFREQ_ADJUST (0) #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) +#define CPUFREQ_REMOVE (3) #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */