longhaul.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 588 行 · 第 1/2 页

C
588
字号
	dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n",		 minmult/10, minmult%10, maxmult/10, maxmult%10);	if (fsb == -1) {		printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");		return -EINVAL;	}	highest_speed = calc_speed (maxmult, fsb);	lowest_speed = calc_speed (minmult,fsb);	dprintk (KERN_INFO PFX "FSB: %dMHz Lowestspeed=%dMHz Highestspeed=%dMHz\n",		 fsb, lowest_speed/1000, highest_speed/1000);	if (lowest_speed == highest_speed) {		printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");		return -EINVAL;	}	if (lowest_speed > highest_speed) {		printk (KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",			lowest_speed, highest_speed);		return -EINVAL;	}	longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);	if(!longhaul_table)		return -ENOMEM;	for (j=0; j < numscales; j++) {		unsigned int ratio;		ratio = clock_ratio[j];		if (ratio == -1)			continue;		if (ratio > maxmult || ratio < minmult)			continue;		longhaul_table[k].frequency = calc_speed (ratio, fsb);		longhaul_table[k].index	= j;		k++;	}	longhaul_table[k].frequency = CPUFREQ_TABLE_END;	if (!k) {		kfree (longhaul_table);		return -EINVAL;	}	return 0;}static void __init longhaul_setup_voltagescaling(void){	union msr_longhaul longhaul;	rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);	if (!(longhaul.bits.RevisionID & 1))		return;	minvid = longhaul.bits.MinimumVID;	maxvid = longhaul.bits.MaximumVID;	vrmrev = longhaul.bits.VRMRev;	if (minvid == 0 || maxvid == 0) {		printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "					"Voltage scaling disabled.\n",					minvid/1000, minvid%1000, maxvid/1000, maxvid%1000);		return;	}	if (minvid == maxvid) {		printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "				"both %d.%03d. Voltage scaling disabled\n",				maxvid/1000, maxvid%1000);		return;	}	if (vrmrev==0) {		dprintk (KERN_INFO PFX "VRM 8.5 : ");		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;	} else {		dprintk (KERN_INFO PFX "Mobile VRM : ");		memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;	}	/* Current voltage isn't readable at first, so we need to	   set it to a known value. The spec says to use maxvid */	longhaul.bits.RevisionKey = longhaul.bits.RevisionID;	/* FIXME: This is bad. */	longhaul.bits.EnableSoftVID = 1;	longhaul.bits.SoftVID = maxvid;	wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);	minvid = voltage_table[minvid];	maxvid = voltage_table[maxvid];	dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",		maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);	can_scale_voltage = 1;}static int longhaul_verify(struct cpufreq_policy *policy){	return cpufreq_frequency_table_verify(policy, longhaul_table);}static int longhaul_target(struct cpufreq_policy *policy,			    unsigned int target_freq,			    unsigned int relation){	unsigned int table_index = 0;	unsigned int new_clock_ratio = 0;	if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))		return -EINVAL;	new_clock_ratio = longhaul_table[table_index].index & 0xFF;	longhaul_setstate(new_clock_ratio);	return 0;}static unsigned int longhaul_get(unsigned int cpu){	if (cpu)		return 0;	return (calc_speed (longhaul_get_cpu_mult(), fsb));}static int __init longhaul_cpu_init(struct cpufreq_policy *policy){	struct cpuinfo_x86 *c = cpu_data;	char *cpuname=NULL;	int ret;	switch (c->x86_model) {	case 6:		cpuname = "C3 'Samuel' [C5A]";		longhaul_version=1;		memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));		break;	case 7:		/* C5B / C5C */		longhaul_version=1;		switch (c->x86_mask) {		case 0:			cpuname = "C3 'Samuel 2' [C5B]";			/* Note, this is not a typo, early Samuel2's had Samuel1 ratios. */			memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));			memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));			break;		case 1 ... 15:			if (c->x86_mask < 8)				cpuname = "C3 'Samuel 2' [C5B]";			else				cpuname = "C3 'Ezra' [C5C]";			memcpy (clock_ratio, ezra_clock_ratio, sizeof(ezra_clock_ratio));			memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));			break;		}		break;	case 8:		cpuname = "C3 'Ezra-T' [C5M]";		longhaul_version=2;		numscales=32;		memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));		memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));		break;	case 9:		longhaul_version=3;		numscales=32;		switch (c->x86_mask) {		case 0 ... 1:			cpuname = "C3 'Nehemiah A' [C5N]";			memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio));			memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr));			break;		case 2 ... 4:			cpuname = "C3 'Nehemiah B' [C5N]";			memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio));			memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr));			break;		case 5 ... 15:			cpuname = "C3 'Nehemiah C' [C5N]";			memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio));			memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr));			break;		}		break;	default:		cpuname = "Unknown";		break;	}	printk (KERN_INFO PFX "VIA %s CPU detected. Longhaul v%d supported.\n",					cpuname, longhaul_version);	ret = longhaul_get_ranges();	if (ret != 0)		return ret;	if ((longhaul_version==2) && (dont_scale_voltage==0))		longhaul_setup_voltagescaling();	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;	policy->cur = calc_speed (longhaul_get_cpu_mult(), fsb);	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);	if (ret)		return ret;	cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);	return 0;}static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy){	cpufreq_frequency_table_put_attr(policy->cpu);	return 0;}static struct freq_attr* longhaul_attr[] = {	&cpufreq_freq_attr_scaling_available_freqs,	NULL,};static struct cpufreq_driver longhaul_driver = {	.verify	= longhaul_verify,	.target	= longhaul_target,	.get	= longhaul_get,	.init	= longhaul_cpu_init,	.exit	= __devexit_p(longhaul_cpu_exit),	.name	= "longhaul",	.owner	= THIS_MODULE,	.attr	= longhaul_attr,};static int __init longhaul_init(void){	struct cpuinfo_x86 *c = cpu_data;	if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)		return -ENODEV;	switch (c->x86_model) {	case 6 ... 9:		return cpufreq_register_driver(&longhaul_driver);	default:		printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n");	}	return -ENODEV;}static void __exit longhaul_exit(void){	int i=0;	unsigned int new_clock_ratio;	while (clock_ratio[i] != maxmult)		i++;	new_clock_ratio = longhaul_table[i].index & 0xFF;	longhaul_setstate(new_clock_ratio);	cpufreq_unregister_driver(&longhaul_driver);	kfree(longhaul_table);}module_param (dont_scale_voltage, int, 0644);MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");module_param (debug, int, 0644);MODULE_PARM_DESC(debug, "Dump debugging information.");MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");MODULE_LICENSE ("GPL");module_init(longhaul_init);module_exit(longhaul_exit);

⌨️ 快捷键说明

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