X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fcpu%2Fcpufreq%2Fspeedstep-ich.c;h=b425cd3d1838377aee89ad50411b2f51b6d40306;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=5f94c4fa24e77f32ea982207f9b7bdb33693f97b;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c index 5f94c4fa2..b425cd3d1 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c @@ -40,6 +40,7 @@ static struct pci_dev *speedstep_chipset_dev; */ static unsigned int speedstep_processor = 0; +static u32 pmbase; /* * There are only two frequency states for each processor. Values @@ -52,17 +53,35 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { }; -/* DEBUG - * Define it if you want verbose debug output, e.g. for bug reporting +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg) + + +/** + * speedstep_find_register - read the PMBASE address + * + * Returns: -ENODEV if no register could be found */ -//#define SPEEDSTEP_DEBUG +static int speedstep_find_register (void) +{ + if (!speedstep_chipset_dev) + return -ENODEV; -#ifdef SPEEDSTEP_DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) { + printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); + return -ENODEV; + } + pmbase &= 0xFFFFFFFE; + if (!pmbase) { + printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); + return -ENODEV; + } + + dprintk("pmbase is 0x%x\n", pmbase); + return 0; +} /** * speedstep_set_state - set the SpeedStep state @@ -72,26 +91,12 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { */ static void speedstep_set_state (unsigned int state) { - 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"); - return; - } - - pmbase &= 0xFFFFFFFE; - if (!pmbase) { - printk(KERN_ERR "cpufreq: could not find speedstep register\n"); + if (state > 0x1) return; - } /* Disable IRQs */ local_irq_save(flags); @@ -99,13 +104,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); @@ -125,10 +130,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"); } @@ -153,7 +158,7 @@ static int speedstep_activate (void) pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) { value |= 0x08; - dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); + dprintk("activating SpeedStep (TM) registers\n"); pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); } @@ -171,7 +176,7 @@ static int speedstep_activate (void) */ static unsigned int speedstep_detect_chipset (void) { - speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, @@ -179,7 +184,7 @@ static unsigned int speedstep_detect_chipset (void) if (speedstep_chipset_dev) return 4; /* 4-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_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, @@ -188,7 +193,7 @@ 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, @@ -201,7 +206,7 @@ static unsigned int speedstep_detect_chipset (void) 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,35 +217,37 @@ static unsigned int speedstep_detect_chipset (void) 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(unsigned int cpu) +static unsigned int _speedstep_get(cpumask_t cpus) { unsigned int speed; - cpumask_t cpus_allowed,affected_cpu_map; + 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[cpu]; -#else - affected_cpu_map = cpumask_of_cpu(cpu); -#endif - set_cpus_allowed(current, affected_cpu_map); - speed=speedstep_get_processor_frequency(speedstep_processor); + 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 * @policy: new policy @@ -255,43 +262,38 @@ static int speedstep_target (struct cpufreq_policy *policy, { 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->cpu); + 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; 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); } @@ -317,43 +319,37 @@ 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; + 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); - /* detect low and high frequency */ + cpus_allowed = current->cpus_allowed; + set_cpus_allowed(current, policy->cpus); + + /* detect low and high frequency and transition latency */ result = speedstep_get_freqs(speedstep_processor, &speedstep_freqs[SPEEDSTEP_LOW].frequency, &speedstep_freqs[SPEEDSTEP_HIGH].frequency, + &policy->cpuinfo.transition_latency, &speedstep_set_state); set_cpus_allowed(current, cpus_allowed); if (result) return result; /* get current speed setting */ - speed = speedstep_get(policy->cpu); + 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)); /* cpuinfo and default policy values */ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = speed; result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); @@ -401,18 +397,25 @@ 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; + } + + if (speedstep_find_register()) + return -ENODEV; return cpufreq_register_driver(&speedstep_driver); } @@ -425,6 +428,7 @@ static int __init speedstep_init(void) */ static void __exit speedstep_exit(void) { + pci_dev_put(speedstep_chipset_dev); cpufreq_unregister_driver(&speedstep_driver); }