⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 powernow-k7.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			 (u32) state->power,			 (u32) state->transition_latency,			 (u32) state->control,			 pc.bits.sgtc);		vid = pc.bits.vid;		fid = pc.bits.fid;		powernow_table[i].frequency = fsb * fid_codes[fid] / 10;		powernow_table[i].index = fid; /* lower 8 bits */		powernow_table[i].index |= (vid << 8); /* upper 8 bits */		speed = powernow_table[i].frequency;		speed_mhz = speed / 1000;		/* processor_perflib will multiply the MHz value by 1000 to		 * get a KHz value (e.g. 1266000). However, powernow-k7 works		 * with true KHz values (e.g. 1266768). To ensure that all		 * powernow frequencies are available, we must ensure that		 * ACPI doesn't restrict them, so we round up the MHz value		 * to ensure that perflib's computed KHz value is greater than		 * or equal to powernow's KHz value.		 */		if (speed % 1000 > 0)			speed_mhz++;		if ((fid_codes[fid] % 10)==5) {			if (have_a0 == 1)				powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;		}		dprintk ("   FID: 0x%x (%d.%dx [%dMHz])  "			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,			 fid_codes[fid] % 10, speed_mhz, vid,			 mobile_vid_table[vid]/1000,			 mobile_vid_table[vid]%1000);		if (state->core_frequency != speed_mhz) {			state->core_frequency = speed_mhz;			dprintk("   Corrected ACPI frequency to %d\n",				speed_mhz);		}		if (latency < pc.bits.sgtc)			latency = pc.bits.sgtc;		if (speed < minimum_speed)			minimum_speed = speed;		if (speed > maximum_speed)			maximum_speed = speed;	}	powernow_table[i].frequency = CPUFREQ_TABLE_END;	powernow_table[i].index = 0;	/* notify BIOS that we exist */	acpi_processor_notify_smm(THIS_MODULE);	return 0;err2:	acpi_processor_unregister_performance(acpi_processor_perf, 0);err1:	kfree(acpi_processor_perf);err0:	printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n");	acpi_processor_perf = NULL;	return retval;}#elsestatic int powernow_acpi_init(void){	printk(KERN_INFO PFX "no support for ACPI processor found."	       "  Please recompile your kernel with ACPI processor\n");	return -EINVAL;}#endifstatic int powernow_decode_bios (int maxfid, int startvid){	struct psb_s *psb;	struct pst_s *pst;	unsigned int i, j;	unsigned char *p;	unsigned int etuple;	unsigned int ret;	etuple = cpuid_eax(0x80000001);	for (i=0xC0000; i < 0xffff0 ; i+=16) {		p = phys_to_virt(i);		if (memcmp(p, "AMDK7PNOW!",  10) == 0){			dprintk ("Found PSB header at %p\n", p);			psb = (struct psb_s *) p;			dprintk ("Table version: 0x%x\n", psb->tableversion);			if (psb->tableversion != 0x12) {				printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n");				return -ENODEV;			}			dprintk ("Flags: 0x%x\n", psb->flags);			if ((psb->flags & 1)==0) {				dprintk ("Mobile voltage regulator\n");			} else {				dprintk ("Desktop voltage regulator\n");			}			latency = psb->settlingtime;			if (latency < 100) {				printk (KERN_INFO PFX "BIOS set settling time to %d microseconds."						"Should be at least 100. Correcting.\n", latency);				latency = 100;			}			dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);			dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);			p += sizeof (struct psb_s);			pst = (struct pst_s *) p;			for (j=0; j<psb->numpst; j++) {				pst = (struct pst_s *) p;				number_scales = pst->numpstates;				if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&				    (maxfid==pst->maxfid) && (startvid==pst->startvid))				{					dprintk ("PST:%d (@%p)\n", j, pst);					dprintk (" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",						 pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);					ret = get_ranges ((char *) pst + sizeof (struct pst_s));					return ret;				} else {					unsigned int k;					p = (char *) pst + sizeof (struct pst_s);					for (k=0; k<number_scales; k++)						p+=2;				}			}			printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);			printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");			return -EINVAL;		}		p++;	}	return -ENODEV;}static int powernow_target (struct cpufreq_policy *policy,			    unsigned int target_freq,			    unsigned int relation){	unsigned int newstate;	if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate))		return -EINVAL;	change_speed(newstate);	return 0;}static int powernow_verify (struct cpufreq_policy *policy){	return cpufreq_frequency_table_verify(policy, powernow_table);}/* * We use the fact that the bus frequency is somehow * a multiple of 100000/3 khz, then we compute sgtc according * to this multiple. * That way, we match more how AMD thinks all of that work. * We will then get the same kind of behaviour already tested under * the "well-known" other OS. */static int __init fixup_sgtc(void){	unsigned int sgtc;	unsigned int m;	m = fsb / 3333;	if ((m % 10) >= 5)		m += 5;	m /= 10;	sgtc = 100 * m * latency;	sgtc = sgtc / 3;	if (sgtc > 0xfffff) {		printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc);		sgtc = 0xfffff;	}	return sgtc;}static unsigned int powernow_get(unsigned int cpu){	union msr_fidvidstatus fidvidstatus;	unsigned int cfid;	if (cpu)		return 0;	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);	cfid = fidvidstatus.bits.CFID;	return (fsb * fid_codes[cfid] / 10);}static int __init acer_cpufreq_pst(const struct dmi_system_id *d){	printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);	printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");	printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");	return 0;}/* * Some Athlon laptops have really fucked PST tables. * A BIOS update is all that can save them. * Mention this, and disable cpufreq. */static struct dmi_system_id __initdata powernow_dmi_table[] = {	{		.callback = acer_cpufreq_pst,		.ident = "Acer Aspire",		.matches = {			DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),			DMI_MATCH(DMI_BIOS_VERSION, "3A71"),		},	},	{ }};static int __init powernow_cpu_init (struct cpufreq_policy *policy){	union msr_fidvidstatus fidvidstatus;	int result;	if (policy->cpu != 0)		return -ENODEV;	rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);	recalibrate_cpu_khz();	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];	if (!fsb) {		printk(KERN_WARNING PFX "can not determine bus frequency\n");		return -EINVAL;	}	dprintk("FSB: %3dMHz\n", fsb/1000);	if (dmi_check_system(powernow_dmi_table) || acpi_force) {		printk (KERN_INFO PFX "PSB/PST known to be broken.  Trying ACPI instead\n");		result = powernow_acpi_init();	} else {		result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);		if (result) {			printk (KERN_INFO PFX "Trying ACPI perflib\n");			maximum_speed = 0;			minimum_speed = -1;			latency = 0;			result = powernow_acpi_init();			if (result) {				printk (KERN_INFO PFX "ACPI and legacy methods failed\n");				printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n");			}		} else {			/* SGTC use the bus clock as timer */			latency = fixup_sgtc();			printk(KERN_INFO PFX "SGTC: %d\n", latency);		}	}	if (result)		return result;	printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",				minimum_speed/1000, maximum_speed/1000);	policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);	policy->cur = powernow_get(0);	cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);	return cpufreq_frequency_table_cpuinfo(policy, powernow_table);}static int powernow_cpu_exit (struct cpufreq_policy *policy) {	cpufreq_frequency_table_put_attr(policy->cpu);#ifdef CONFIG_X86_POWERNOW_K7_ACPI	if (acpi_processor_perf) {		acpi_processor_unregister_performance(acpi_processor_perf, 0);		kfree(acpi_processor_perf);	}#endif	kfree(powernow_table);	return 0;}static struct freq_attr* powernow_table_attr[] = {	&cpufreq_freq_attr_scaling_available_freqs,	NULL,};static struct cpufreq_driver powernow_driver = {	.verify	= powernow_verify,	.target	= powernow_target,	.get	= powernow_get,	.init	= powernow_cpu_init,	.exit	= powernow_cpu_exit,	.name	= "powernow-k7",	.owner	= THIS_MODULE,	.attr	= powernow_table_attr,};static int __init powernow_init (void){	if (check_powernow()==0)		return -ENODEV;	return cpufreq_register_driver(&powernow_driver);}static void __exit powernow_exit (void){	cpufreq_unregister_driver(&powernow_driver);}module_param(acpi_force,  int, 0444);MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");MODULE_LICENSE ("GPL");late_initcall(powernow_init);module_exit(powernow_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -