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

📄 longhaul.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 2 页
字号:
			lo &= ~(1<<28|1<<29);			switch (newfsb) {				case 66:	lo |= (1<<28|1<<29); /* 11 */							break;				case 100:	lo |= 1<<28;	/* 01 */							break;				case 133:	break;	/* 00*/			}		}		wrmsr (MSR_VIA_LONGHAUL, lo, hi);		__hlt();		rdmsr (MSR_VIA_LONGHAUL, lo, hi);		lo &= ~(1<<8);		lo |= revkey;		wrmsr (MSR_VIA_LONGHAUL, lo, hi);		break;	}	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);}static void __init longhaul_get_ranges (void){	unsigned long lo, hi, invalue;	unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0;	unsigned int multipliers[32]= {		50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,		-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };	unsigned int fsb_table[4] = { 133, 100, -1, 66 };	switch (longhaul) {	case 1:		/* Ugh, Longhaul v1 didn't have the min/max MSRs.		   Assume min=3.0x & max = whatever we booted at. */		minmult = 30;		maxmult = longhaul_get_cpu_mult();		minfsb = maxfsb = current_fsb;		break;	case 2 ... 3:		rdmsr (MSR_VIA_LONGHAUL, lo, hi);		invalue = (hi & (1<<0|1<<1|1<<2|1<<3));		if (hi & (1<<11))			invalue += 16;		maxmult=multipliers[invalue];#if 0	/* This is MaxMhz @ Min Voltage. Ignore for now */		invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16;		if (hi & (1<<27))		invalue += 16;		minmult = multipliers[invalue];#else		minmult = 30; /* as per spec */#endif		if (can_scale_fsb==1) {			invalue = (hi & (1<<9|1<<10)) >> 9;			maxfsb = fsb_table[invalue];			invalue = (hi & (1<<25|1<<26)) >> 25;			minfsb = fsb_table[invalue];			dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n",				minfsb, maxfsb);		} else {			minfsb = maxfsb = current_fsb;		}		break;	}	highest_speed = maxmult * maxfsb * 100;	lowest_speed = minmult * minfsb * 100;	dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n",		minmult, maxmult);	dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n",		lowest_speed, highest_speed);}static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi){	int revkey;	can_scale_voltage = 1;	minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */	maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4;       /* 40:36 */	vrmrev = (lo & (1<<15))>>15;	if (vrmrev==0) {		dprintk (KERN_INFO "longhaul: VRM 8.5 : ");		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;	} else {		dprintk (KERN_INFO "longhaul: 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 */	revkey = (lo & 0xf)<<4;	/* Rev key. */	lo &= 0xfe0fff0f;	/* Mask unneeded bits */	lo |= (1<<9);		/* EnableSoftVID */	lo |= revkey;		/* Reinsert key */	lo |= maxvid << 20;	wrmsr (MSR_VIA_LONGHAUL, lo, hi);	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);}static inline unsigned int longhaul_statecount_fsb(struct cpufreq_policy *policy, unsigned int fsb) {	unsigned int i, count = 0;	for(i=0; i<numscales; i++) {		if ((clock_ratio[i] != -1) &&		    ((clock_ratio[i] * fsb * 100) <= policy->max) &&		    ((clock_ratio[i] * fsb * 100) >= policy->min))			count++;	}	return count;}static int longhaul_verify(struct cpufreq_policy *policy){	unsigned int    number_states = 0;	unsigned int    i;	unsigned int    fsb_index = 0;	unsigned int    tmpfreq = 0;	unsigned int    newmax = -1;	if (!policy || !longhaul_driver)		return -EINVAL;	policy->cpu = 0;	cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);	if (can_scale_fsb==1) {		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)			number_states += longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);	} else		number_states = longhaul_statecount_fsb(policy, current_fsb);	if (number_states)		return 0;	/* get frequency closest above current policy->max */	if (can_scale_fsb==1) {		for (fsb_index=0; fsb_search_table[fsb_index] != -1; fsb_index++)			for(i=0; i<numscales; i++) {				if (clock_ratio[i] == -1)					continue;				tmpfreq = clock_ratio[i] * fsb_search_table[fsb_index];				if ((tmpfreq > policy->max) &&				    (tmpfreq < newmax))					newmax = tmpfreq;			}	} else {		for(i=0; i<numscales; i++) {			if (clock_ratio[i] == -1)				continue;			tmpfreq = clock_ratio[i] * current_fsb;			if ((tmpfreq > policy->max) &&			    (tmpfreq < newmax))				newmax = tmpfreq;			}	}	policy->max = newmax;	cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);	return 0;}static int longhaul_get_best_freq_for_fsb(struct cpufreq_policy *policy, 					  unsigned int min_mult, 					  unsigned int max_mult, 					  unsigned int fsb, 					  unsigned int *new_mult){	unsigned int optimal = 0;	unsigned int found_optimal = 0;	unsigned int i;	switch(policy->policy) {	case CPUFREQ_POLICY_POWERSAVE:		optimal = max_mult;		break;	case CPUFREQ_POLICY_PERFORMANCE:		optimal = min_mult;	}	for(i=0; i<numscales; i++) {		unsigned int freq = fsb * clock_ratio[i] * 100;		if ((freq > policy->max) ||		    (freq < policy->min))			continue;		switch(policy->policy) {		case CPUFREQ_POLICY_POWERSAVE:			if (clock_ratio[i] < clock_ratio[optimal]) {				found_optimal = 1;				optimal = i;			}			break;		case CPUFREQ_POLICY_PERFORMANCE:			if (clock_ratio[i] > clock_ratio[optimal]) {				found_optimal = 1;				optimal = i;			}			break;		}	}			if (found_optimal) {		*new_mult = optimal;		return 1;	}	return 0;}static int longhaul_setpolicy (struct cpufreq_policy *policy){	unsigned int    i;	unsigned int    fsb_index = 0;	unsigned int    new_fsb = 0;	unsigned int    new_clock_ratio = 0;	unsigned int    min_mult = 0;	unsigned int    max_mult = 0;	if (!longhaul_driver)		return -EINVAL;	if (policy->policy==CPUFREQ_POLICY_PERFORMANCE)		fsb_search_table = perf_fsb_table;	else		fsb_search_table = power_fsb_table;	for(i=0;i<numscales;i++) {		if (clock_ratio[max_mult] < clock_ratio[i])				max_mult = i;		else if (clock_ratio[min_mult] > clock_ratio[i])				min_mult = i;	}	if (can_scale_fsb==1) {		unsigned int found = 0;		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)		{			if (longhaul_get_best_freq_for_fsb(policy, 			              min_mult, max_mult, 				      fsb_search_table[fsb_index], 				      &new_clock_ratio)) {				new_fsb = fsb_search_table[fsb_index];				break;			}		}		if (!found)			return -EINVAL;	} else {		new_fsb = current_fsb;		if (!longhaul_get_best_freq_for_fsb(policy, min_mult, 			     max_mult, new_fsb, &new_clock_ratio))			return -EINVAL;	}	longhaul_setstate(new_clock_ratio, new_fsb);	return 0;}static int __init longhaul_init (void){	struct cpuinfo_x86 *c = cpu_data;	unsigned int currentspeed;	static int currentmult;	unsigned long lo, hi;	int ret;	struct cpufreq_driver *driver;	if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )		return -ENODEV;	switch (c->x86_model) {	case 6:		/* VIA C3 Samuel C5A */		longhaul=1;		memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));		break;	case 7:		/* C5B / C5C */		switch (c->x86_mask) {		case 0:			longhaul=1;			memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));			memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));			break;		case 1 ... 15:			longhaul=2;			memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio));			memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));			break;		}		break;	case 8:		/* C5M/C5N */		return -ENODEV; // Waiting on updated docs from VIA before this is usable		longhaul=3;		numscales=32;		memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio));		memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr));		break;	default:		printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n");		return -ENODEV;	}	printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul);	current_fsb = longhaul_get_cpu_fsb();	currentmult = longhaul_get_cpu_mult();	currentspeed = currentmult * current_fsb * 100;	dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n",		(currentspeed/1000), current_fsb, currentmult/10, currentmult%10);	if (longhaul==2 || longhaul==3) {		rdmsr (MSR_VIA_LONGHAUL, lo, hi);		if ((lo & (1<<0)) && (dont_scale_voltage==0))			longhaul_setup_voltagescaling (lo, hi);		if ((lo & (1<<1)) && (dont_scale_fsb==0) && (current_fsb==0))			can_scale_fsb = 1;	}	longhaul_get_ranges();	driver = kmalloc(sizeof(struct cpufreq_driver) + 			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);	if (!driver)		return -ENOMEM;	driver->policy = (struct cpufreq_policy *) (driver + 1);#ifdef CONFIG_CPU_FREQ_24_API	driver->cpu_cur_freq[0] = currentspeed;#endif	driver->verify    = &longhaul_verify;	driver->setpolicy = &longhaul_setpolicy;	driver->policy[0].cpu = 0;	driver->policy[0].min = (unsigned int) lowest_speed;	driver->policy[0].max = (unsigned int) highest_speed;	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;	driver->policy[0].cpuinfo.min_freq = (unsigned int) lowest_speed;	driver->policy[0].cpuinfo.max_freq = (unsigned int) highest_speed;	driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;	longhaul_driver = driver;	ret = cpufreq_register(driver);	if (ret) {		longhaul_driver = NULL;		kfree(driver);	}	return ret;}static void __exit longhaul_exit (void){	if (longhaul_driver) {		cpufreq_unregister();		kfree(longhaul_driver);	}}MODULE_PARM (dont_scale_fsb, "i");MODULE_PARM (dont_scale_voltage, "i");MODULE_PARM (current_fsb, "i");MODULE_AUTHOR ("Dave Jones <davej@suse.de>");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 + -