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

📄 longhaul.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (longhaul.bits.MaxMHzBR4)				invalue += 16;			maxmult=multipliers[invalue];			invalue = longhaul.bits.MinMHzBR;			if (longhaul.bits.MinMHzBR4 == 1)				minmult = 30;			else				minmult = multipliers[invalue];			fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];			break;		}		/* Nehemiah */		if (cpu_model==CPU_NEHEMIAH) {			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);			/*			 * TODO: This code works, but raises a lot of questions.			 * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.			 *   We get around this by using a hardcoded multiplier of 4.0x			 *   for the minimimum speed, and the speed we booted up at for the max.			 *   This is done in longhaul_get_cpu_mult() by reading the EBLCR register.			 * - According to some VIA documentation EBLCR is only			 *   in pre-Nehemiah C3s. How this still works is a mystery.			 *   We're possibly using something undocumented and unsupported,			 *   But it works, so we don't grumble.			 */			minmult=40;			maxmult=longhaul_get_cpu_mult();			/* Starting with the 1.2GHz parts, theres a 200MHz bus. */			if ((cpu_khz/1000) > 1200)				fsb = 200;			else				fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];			break;		}	}	dprintk ("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);	lowest_speed = calc_speed(minmult);	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,		 print_speed(lowest_speed/1000), 		 print_speed(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);		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 ("VRM 8.5\n");		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;	} else {		dprintk ("Mobile VRM\n");		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());}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:		cpu_model = CPU_SAMUEL;		cpuname = "C3 'Samuel' [C5A]";		longhaul_version = TYPE_LONGHAUL_V1;		memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));		break;	case 7:		longhaul_version = TYPE_LONGHAUL_V1;		switch (c->x86_mask) {		case 0:			cpu_model = CPU_SAMUEL2;			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) {				cpu_model = CPU_SAMUEL2;				cpuname = "C3 'Samuel 2' [C5B]";			} else {				cpu_model = CPU_EZRA;				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:		cpu_model = CPU_EZRA_T;		cpuname = "C3 'Ezra-T' [C5M]";		longhaul_version = TYPE_POWERSAVER;		numscales=32;		memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));		memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));		break;	case 9:		cpu_model = CPU_NEHEMIAH;		longhaul_version = TYPE_POWERSAVER;		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.  ", cpuname);	switch (longhaul_version) {	case TYPE_LONGHAUL_V1:	case TYPE_LONGHAUL_V2:		printk ("Longhaul v%d supported.\n", longhaul_version);		break;	case TYPE_POWERSAVER:		printk ("Powersaver supported.\n");		break;	};	ret = longhaul_get_ranges();	if (ret != 0)		return ret;	if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&		 (dont_scale_voltage==0))		longhaul_setup_voltagescaling();	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;	policy->cpuinfo.transition_latency = 200000;	/* nsec */	policy->cur = calc_speed(longhaul_get_cpu_mult());	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;	for (i=0; i < numscales; i++) {		if (clock_ratio[i] == maxmult) {			longhaul_setstate(i);			break;		}	}	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_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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -