X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fcpu%2Fcpufreq%2Fpowernow-k8.c;h=a65ff7e32e5d09417279a06de1db0f003c77671a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=862bcf5dd997a8c950a0f1d2c731fa4204b745f6;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 862bcf5dd..a65ff7e32 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -18,6 +18,9 @@ * Processor information obtained from Chapter 9 (Power and Thermal Management) * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * Opteron Processors" available for download from www.amd.com + * + * Tables for specific CPUs can be infrerred from + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf */ #include @@ -32,14 +35,14 @@ #include #include -#ifdef CONFIG_ACPI_PROCESSOR +#ifdef CONFIG_X86_POWERNOW_K8_ACPI #include #include #endif #define PFX "powernow-k8: " #define BFX PFX "BIOS error: " -#define VERSION "version 1.00.08b" +#define VERSION "version 1.00.09e" #include "powernow-k8.h" /* serialize freq changes */ @@ -65,7 +68,12 @@ static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid) return 1550-vid*25; } -/* Return the vco fid for an input fid */ +/* Return the vco fid for an input fid + * + * Each "low" fid has corresponding "high" fid, and you can get to "low" fids + * only from corresponding high fids. This returns "high" fid corresponding to + * "low" one. + */ static u32 convert_fid_to_vco_fid(u32 fid) { if (fid < HI_FID_TABLE_BOTTOM) { @@ -136,7 +144,7 @@ static void fidvid_msr_init(void) fid = lo & MSR_S_LO_CURRENT_FID; lo = fid | (vid << MSR_C_LO_VID_SHIFT); hi = MSR_C_HI_STP_GNT_BENIGN; - dprintk(PFX "cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); + dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); wrmsr(MSR_FIDVID_CTL, lo, hi); } @@ -154,7 +162,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) lo = fid | (data->currvid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID; - dprintk(KERN_DEBUG PFX "writing fid 0x%x, lo 0x%x, hi 0x%x\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); @@ -192,7 +200,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) lo = data->currfid | (vid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID; - dprintk(KERN_DEBUG PFX "writing vid 0x%x, lo 0x%x, hi 0x%x\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); @@ -255,7 +263,7 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req return 1; } - dprintk(KERN_INFO PFX "transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", + dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); return 0; @@ -267,24 +275,22 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid u32 rvosteps = data->rvo; u32 savefid = data->currfid; - dprintk(KERN_DEBUG PFX - "ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", + dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); while (data->currvid > reqvid) { - dprintk(KERN_DEBUG PFX "ph1: curr 0x%x, req vid 0x%x\n", + dprintk("ph1: curr 0x%x, req vid 0x%x\n", data->currvid, reqvid); if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) return 1; } - while (rvosteps > 0) { + while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) { if (data->currvid == 0) { rvosteps = 0; } else { - dprintk(KERN_DEBUG PFX - "ph1: changing vid for rvo, req 0x%x\n", + dprintk("ph1: changing vid for rvo, req 0x%x\n", data->currvid - 1); if (decrease_vid_code_by_step(data, data->currvid - 1, 1)) return 1; @@ -300,7 +306,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid return 1; } - dprintk(KERN_DEBUG PFX "ph1 complete, currfid 0x%x, currvid 0x%x\n", + dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -309,10 +315,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid /* Phase 2 - core frequency transition */ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) { - u32 vcoreqfid; - u32 vcocurrfid; - u32 vcofiddiff; - u32 savevid = data->currvid; + u32 vcoreqfid, vcocurrfid, vcofiddiff, savevid = data->currvid; if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n", @@ -325,8 +328,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 0; } - dprintk(KERN_DEBUG PFX - "ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n", + dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqfid); @@ -376,7 +378,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 1; } - dprintk(KERN_DEBUG PFX "ph2 complete, currfid 0x%x, currvid 0x%x\n", + dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -388,7 +390,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi u32 savefid = data->currfid; u32 savereqvid = reqvid; - dprintk(KERN_DEBUG PFX "ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", + dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); @@ -415,17 +417,17 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi return 1; if (savereqvid != data->currvid) { - dprintk(KERN_ERR PFX "ph3 failed, currvid 0x%x\n", data->currvid); + dprintk("ph3 failed, currvid 0x%x\n", data->currvid); return 1; } if (savefid != data->currfid) { - dprintk(KERN_ERR PFX "ph3 failed, currfid changed 0x%x\n", + dprintk("ph3 failed, currfid changed 0x%x\n", data->currfid); return 1; } - dprintk(KERN_DEBUG PFX "ph3 complete, currfid 0x%x, currvid 0x%x\n", + dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -450,13 +452,10 @@ static int check_supported_cpu(unsigned int cpu) goto out; eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); - if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) { - dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n"); - } else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) { - dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n"); - } else { - printk(KERN_INFO PFX - "AMD Athlon 64 or AMD Opteron processor required\n"); + if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || + ((eax & CPUID_XFAM) != CPUID_XFAM_K8) || + ((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) { + printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax); goto out; } @@ -504,7 +503,7 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 || (pst[j].fid & 1) || (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) { /* Only first fid is allowed to be in "low" range */ - printk(KERN_ERR PFX "fid %d invalid : 0x%x\n", j, pst[j].fid); + printk(KERN_ERR PFX "two low fids - %d : 0x%x\n", j, pst[j].fid); return -EINVAL; } if (pst[j].fid < lastfid) @@ -524,11 +523,12 @@ static void print_basics(struct powernow_k8_data *data) { int j; for (j = 0; j < data->numps; j++) { - printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j, - data->powernow_table[j].index & 0xff, - data->powernow_table[j].frequency/1000, - data->powernow_table[j].index >> 8, - find_millivolts_from_vid(data, data->powernow_table[j].index >> 8)); + if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) + printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j, + data->powernow_table[j].index & 0xff, + data->powernow_table[j].frequency/1000, + data->powernow_table[j].index >> 8, + find_millivolts_from_vid(data, data->powernow_table[j].index >> 8)); } if (data->batps) printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps); @@ -555,7 +555,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, printk(KERN_ERR PFX "no p states to transition\n"); return -ENODEV; } - + if (check_pst_table(data, pst, maxvid)) return -EINVAL; @@ -579,7 +579,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, return -EIO; } - dprintk(KERN_INFO PFX "cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); + dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); data->powernow_table = powernow_table; print_basics(data); @@ -587,7 +587,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid)) return 0; - dprintk(KERN_ERR PFX "currfid/vid do not match PST, ignoring\n"); + dprintk("currfid/vid do not match PST, ignoring\n"); return 0; } @@ -598,6 +598,8 @@ static int find_psb_table(struct powernow_k8_data *data) unsigned int i; u32 mvs; u8 maxvid; + u32 cpst = 0; + u32 thiscpuid; for (i = 0xc0000; i < 0xffff0; i += 0x10) { /* Scan BIOS looking for the signature. */ @@ -607,48 +609,55 @@ static int find_psb_table(struct powernow_k8_data *data) if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0) continue; - dprintk(KERN_DEBUG PFX "found PSB header at 0x%p\n", psb); + dprintk("found PSB header at 0x%p\n", psb); - dprintk(KERN_DEBUG PFX "table vers: 0x%x\n", psb->tableversion); + dprintk("table vers: 0x%x\n", psb->tableversion); if (psb->tableversion != PSB_VERSION_1_4) { printk(KERN_INFO BFX "PSB table is not v1.4\n"); return -ENODEV; } - dprintk(KERN_DEBUG PFX "flags: 0x%x\n", psb->flags1); + dprintk("flags: 0x%x\n", psb->flags1); if (psb->flags1) { printk(KERN_ERR BFX "unknown flags\n"); return -ENODEV; } - data->vstable = psb->voltagestabilizationtime; - dprintk(KERN_INFO PFX "voltage stabilization time: %d(*20us)\n", data->vstable); + data->vstable = psb->vstable; + dprintk("voltage stabilization time: %d(*20us)\n", data->vstable); - dprintk(KERN_DEBUG PFX "flags2: 0x%x\n", psb->flags2); + dprintk("flags2: 0x%x\n", psb->flags2); data->rvo = psb->flags2 & 3; data->irt = ((psb->flags2) >> 2) & 3; mvs = ((psb->flags2) >> 4) & 3; data->vidmvs = 1 << mvs; data->batps = ((psb->flags2) >> 6) & 3; - dprintk(KERN_INFO PFX "ramp voltage offset: %d\n", data->rvo); - dprintk(KERN_INFO PFX "isochronous relief time: %d\n", data->irt); - dprintk(KERN_INFO PFX "maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); + dprintk("ramp voltage offset: %d\n", data->rvo); + dprintk("isochronous relief time: %d\n", data->irt); + dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); - dprintk(KERN_DEBUG PFX "numpst: 0x%x\n", psb->numpst); - if (psb->numpst != 1) { + dprintk("numpst: 0x%x\n", psb->num_tables); + cpst = psb->num_tables; + if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){ + thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); + if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) { + cpst = 1; + } + } + if (cpst != 1) { printk(KERN_ERR BFX "numpst must be 1\n"); return -ENODEV; } data->plllock = psb->plllocktime; - dprintk(KERN_INFO PFX "plllocktime: 0x%x (units 1us)\n", psb->plllocktime); - dprintk(KERN_INFO PFX "maxfid: 0x%x\n", psb->maxfid); - dprintk(KERN_INFO PFX "maxvid: 0x%x\n", psb->maxvid); + dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); + dprintk("maxfid: 0x%x\n", psb->maxfid); + dprintk("maxvid: 0x%x\n", psb->maxvid); maxvid = psb->maxvid; - data->numps = psb->numpstates; - dprintk(KERN_INFO PFX "numpstates: 0x%x\n", data->numps); + data->numps = psb->numps; + dprintk("numpstates: 0x%x\n", data->numps); return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); } /* @@ -666,7 +675,7 @@ static int find_psb_table(struct powernow_k8_data *data) return -ENODEV; } -#ifdef CONFIG_ACPI_PROCESSOR +#ifdef CONFIG_X86_POWERNOW_K8_ACPI static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) @@ -686,19 +695,21 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) struct cpufreq_frequency_table *powernow_table; if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { - dprintk(KERN_DEBUG PFX "register performance failed\n"); + dprintk("register performance failed\n"); return -EIO; } /* verify the data contained in the ACPI structures */ if (data->acpi_data.state_count <= 1) { - dprintk(KERN_DEBUG PFX "No ACPI P-States\n"); + dprintk("No ACPI P-States\n"); goto err_out; } if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - dprintk(KERN_DEBUG PFX "Invalid control/status registers\n"); + dprintk("Invalid control/status registers (%x - %x)\n", + data->acpi_data.control_register.space_id, + data->acpi_data.status_register.space_id); goto err_out; } @@ -706,7 +717,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1)), GFP_KERNEL); if (!powernow_table) { - dprintk(KERN_ERR PFX "powernow_table memory alloc failure\n"); + dprintk("powernow_table memory alloc failure\n"); goto err_out; } @@ -714,7 +725,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) u32 fid = data->acpi_data.states[i].control & FID_MASK; u32 vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK; - dprintk(KERN_INFO PFX " %d : fid 0x%x, vid 0x%x\n", i, fid, vid); + dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); powernow_table[i].index = fid; /* lower 8 bits */ powernow_table[i].index |= (vid << 8); /* upper 8 bits */ @@ -723,17 +734,36 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) /* verify frequency is OK */ if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) || (powernow_table[i].frequency < (MIN_FREQ * 1000))) { - dprintk(KERN_INFO PFX "invalid freq %u kHz\n", powernow_table[i].frequency); + dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency); + powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; + continue; + } + + /* verify voltage is OK - BIOSs are using "off" to indicate invalid */ + if (vid == 0x1f) { + dprintk("invalid vid %u, ignoring\n", vid); powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; continue; } - /* verify only 1 entry from the lo frequency table */ - if ((fid < HI_FID_TABLE_BOTTOM) && (cntlofreq++)) { - printk(KERN_ERR PFX "Too many lo freq table entries\n"); - goto err_out; + if (fid < HI_FID_TABLE_BOTTOM) { + if (cntlofreq) { + /* if both entries are the same, ignore this + * one... + */ + if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || + (powernow_table[i].index != powernow_table[cntlofreq].index)) { + printk(KERN_ERR PFX "Too many lo freq table entries\n"); + goto err_out_mem; + } + + dprintk("double low frequency table entry, ignoring it.\n"); + powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; + continue; + } else + cntlofreq = i; } - + if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) { printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n", powernow_table[i].frequency, @@ -751,13 +781,21 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) data->numps = data->acpi_data.state_count; print_basics(data); powernow_k8_acpi_pst_values(data, 0); + + /* notify BIOS that we exist */ + acpi_processor_notify_smm(THIS_MODULE); + return 0; + +err_out_mem: + kfree(powernow_table); + err_out: acpi_processor_unregister_performance(&data->acpi_data, data->cpu); /* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */ data->acpi_data.state_count = 0; - + return -ENODEV; } @@ -781,8 +819,7 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde int res; struct cpufreq_freqs freqs; - dprintk(KERN_DEBUG PFX "cpu %d transition to index %u\n", - smp_processor_id(), index ); + dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); /* fid are the lower 8 bits of the index we stored into * the cpufreq frequency table in find_psb_table, vid are @@ -792,28 +829,25 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde fid = data->powernow_table[index].index & 0xFF; vid = (data->powernow_table[index].index & 0xFF00) >> 8; - dprintk(KERN_DEBUG PFX "table matched fid 0x%x, giving vid 0x%x\n", - fid, vid); + dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); if (query_current_values_with_pending_wait(data)) return 1; if ((data->currvid == vid) && (data->currfid == fid)) { - dprintk(KERN_DEBUG PFX - "target matches current values (fid 0x%x, vid 0x%x)\n", + dprintk("target matches current values (fid 0x%x, vid 0x%x)\n", fid, vid); return 0; } if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { - printk(KERN_ERR PFX - "ignoring illegal change in lo freq table-%x to 0x%x\n", + printk("ignoring illegal change in lo freq table-%x to 0x%x\n", data->currfid, fid); return 1; } - dprintk(KERN_DEBUG PFX "cpu %d, changing to fid 0x%x, vid 0x%x\n", - smp_processor_id(), fid, vid); + dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n", + smp_processor_id(), fid, vid); freqs.cpu = data->cpu; @@ -848,18 +882,15 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi if (smp_processor_id() != pol->cpu) { printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu); - goto sched_out; + goto err_out; } - /* from this point, do not exit without restoring preempt and cpu */ - preempt_disable(); - if (pending_bit_stuck()) { printk(KERN_ERR PFX "failing targ, change pending bit set\n"); goto err_out; } - dprintk(KERN_DEBUG PFX "targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", + dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); if (query_current_values_with_pending_wait(data)) { @@ -867,7 +898,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi goto err_out; } - dprintk(KERN_DEBUG PFX "targ: curr fid 0x%x, vid 0x%x\n", + dprintk("targ: curr fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); if ((checkvid != data->currvid) || (checkfid != data->currfid)) { @@ -891,8 +922,6 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ret = 0; err_out: - preempt_enable_no_resched(); -sched_out: set_cpus_allowed(current, oldmask); schedule(); @@ -932,15 +961,15 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) * an UP version, and is deprecated by AMD. */ - if (pol->cpu != 0) { - printk(KERN_ERR PFX "init not cpu 0\n"); + if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { + printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); kfree(data); return -ENODEV; } - if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { - printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); + if (pol->cpu != 0) { + printk(KERN_ERR PFX "init not cpu 0\n"); kfree(data); - return 0; + return -ENODEV; } rc = find_psb_table(data); if (rc) { @@ -981,11 +1010,12 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) + (3 * (1 << data->irt) * 10)) * 1000; pol->cur = find_khz_freq_from_fid(data->currfid); - dprintk(KERN_DEBUG PFX "policy current frequency %d kHz\n", pol->cur); + dprintk("policy current frequency %d kHz\n", pol->cur); /* min/max the cpu is capable of */ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { printk(KERN_ERR PFX "invalid powernow_table\n"); + powernow_k8_cpu_exit_acpi(data); kfree(data->powernow_table); kfree(data); return -EINVAL; @@ -993,7 +1023,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); - printk(KERN_INFO PFX "cpu_init done, current fid 0x%x, vid 0x%x\n", + printk("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); powernow_data[pol->cpu] = data; @@ -1003,12 +1033,13 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) err_out: set_cpus_allowed(current, oldmask); schedule(); + powernow_k8_cpu_exit_acpi(data); kfree(data); return -ENODEV; } -static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) +static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) { struct powernow_k8_data *data = powernow_data[pol->cpu]; @@ -1025,6 +1056,32 @@ static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) return 0; } +static unsigned int powernowk8_get (unsigned int cpu) +{ + struct powernow_k8_data *data = powernow_data[cpu]; + cpumask_t oldmask = current->cpus_allowed; + unsigned int khz = 0; + + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (smp_processor_id() != cpu) { + printk(KERN_ERR PFX "limiting to CPU %d failed in powernowk8_get\n", cpu); + 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(); + set_cpus_allowed(current, oldmask); + + return khz; +} + static struct freq_attr* powernow_k8_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, @@ -1034,7 +1091,8 @@ static struct cpufreq_driver cpufreq_amd64_driver = { .verify = powernowk8_verify, .target = powernowk8_target, .init = powernowk8_cpu_init, - .exit = powernowk8_cpu_exit, + .exit = __devexit_p(powernowk8_cpu_exit), + .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, .attr = powernow_k8_attr, @@ -1064,7 +1122,7 @@ static int __init powernowk8_init(void) /* driver entry point for term */ static void __exit powernowk8_exit(void) { - dprintk(KERN_INFO PFX "exit\n"); + dprintk("exit\n"); cpufreq_unregister_driver(&cpufreq_amd64_driver); }