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

📄 longhaul.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			longhaul_table[j].index = longhaul_table[min_i].index;			longhaul_table[min_i].index = temp;		}	}	longhaul_table[k].frequency = CPUFREQ_TABLE_END;	/* Find index we are running on */	for (j = 0; j < k; j++) {		if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) {			longhaul_index = j;			break;		}	}	return 0;}static void __init longhaul_setup_voltagescaling(void){	union msr_longhaul longhaul;	struct mV_pos minvid, maxvid, vid;	unsigned int j, speed, pos, kHz_step, numvscales;	int min_vid_speed;	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);	if (!(longhaul.bits.RevisionID & 1)) {		printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");		return;	}	if (!longhaul.bits.VRMRev) {		printk(KERN_INFO PFX "VRM 8.5\n");		vrm_mV_table = &vrm85_mV[0];		mV_vrm_table = &mV_vrm85[0];	} else {		printk(KERN_INFO PFX "Mobile VRM\n");		if (cpu_model < CPU_NEHEMIAH)			return;		vrm_mV_table = &mobilevrm_mV[0];		mV_vrm_table = &mV_mobilevrm[0];	}	minvid = vrm_mV_table[longhaul.bits.MinimumVID];	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {		printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "					"Voltage scaling disabled.\n",					minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);		return;	}	if (minvid.mV == maxvid.mV) {		printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "				"both %d.%03d. Voltage scaling disabled\n",				maxvid.mV/1000, maxvid.mV%1000);		return;	}	/* How many voltage steps */	numvscales = maxvid.pos - minvid.pos + 1;	printk(KERN_INFO PFX		"Max VID=%d.%03d  "		"Min VID=%d.%03d, "		"%d possible voltage scales\n",		maxvid.mV/1000, maxvid.mV%1000,		minvid.mV/1000, minvid.mV%1000,		numvscales);	/* Calculate max frequency at min voltage */	j = longhaul.bits.MinMHzBR;	if (longhaul.bits.MinMHzBR4)		j += 16;	min_vid_speed = eblcr_table[j];	if (min_vid_speed == -1)		return;	switch (longhaul.bits.MinMHzFSB) {	case 0:		min_vid_speed *= 13333;		break;	case 1:		min_vid_speed *= 10000;		break;	case 3:		min_vid_speed *= 6666;		break;	default:		return;		break;	}	if (min_vid_speed >= highest_speed)		return;	/* Calculate kHz for one voltage step */	kHz_step = (highest_speed - min_vid_speed) / numvscales;	j = 0;	while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {		speed = longhaul_table[j].frequency;		if (speed > min_vid_speed)			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;		else			pos = minvid.pos;		longhaul_table[j].index |= mV_vrm_table[pos] << 8;		vid = vrm_mV_table[mV_vrm_table[pos]];		printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV);		j++;	}	can_scale_voltage = 1;	printk(KERN_INFO PFX "Voltage scaling enabled.\n");}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 i;	unsigned int dir = 0;	u8 vid, current_vid;	if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))		return -EINVAL;	/* Don't set same frequency again */	if (longhaul_index == table_index)		return 0;	if (!can_scale_voltage)		longhaul_setstate(table_index);	else {		/* On test system voltage transitions exceeding single		 * step up or down were turning motherboard off. Both		 * "ondemand" and "userspace" are unsafe. C7 is doing		 * this in hardware, C3 is old and we need to do this		 * in software. */		i = longhaul_index;		current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f;		if (table_index > longhaul_index)			dir = 1;		while (i != table_index) {			vid = (longhaul_table[i].index >> 8) & 0x1f;			if (vid != current_vid) {				longhaul_setstate(i);				current_vid = vid;				msleep(200);			}			if (dir)				i++;			else				i--;		}		longhaul_setstate(table_index);	}	longhaul_index = table_index;	return 0;}static unsigned int longhaul_get(unsigned int cpu){	if (cpu)		return 0;	return calc_speed(longhaul_get_cpu_mult());}static acpi_status longhaul_walk_callback(acpi_handle obj_handle,					  u32 nesting_level,					  void *context, void **return_value){	struct acpi_device *d;	if ( acpi_bus_get_device(obj_handle, &d) ) {		return 0;	}	*return_value = (void *)acpi_driver_data(d);	return 1;}/* VIA don't support PM2 reg, but have something similar */static int enable_arbiter_disable(void){	struct pci_dev *dev;	int status = 1;	int reg;	u8 pci_cmd;	/* Find PLE133 host bridge */	reg = 0x78;	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,			     NULL);	/* Find PM133/VT8605 host bridge */	if (dev == NULL)		dev = pci_get_device(PCI_VENDOR_ID_VIA,				     PCI_DEVICE_ID_VIA_8605_0, NULL);	/* Find CLE266 host bridge */	if (dev == NULL) {		reg = 0x76;		dev = pci_get_device(PCI_VENDOR_ID_VIA,				     PCI_DEVICE_ID_VIA_862X_0, NULL);		/* Find CN400 V-Link host bridge */		if (dev == NULL)			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);	}	if (dev != NULL) {		/* Enable access to port 0x22 */		pci_read_config_byte(dev, reg, &pci_cmd);		if (!(pci_cmd & 1<<7)) {			pci_cmd |= 1<<7;			pci_write_config_byte(dev, reg, pci_cmd);			pci_read_config_byte(dev, reg, &pci_cmd);			if (!(pci_cmd & 1<<7)) {				printk(KERN_ERR PFX					"Can't enable access to port 0x22.\n");				status = 0;			}		}		pci_dev_put(dev);		return status;	}	return 0;}static int longhaul_setup_southbridge(void){	struct pci_dev *dev;	u8 pci_cmd;	/* Find VT8235 southbridge */	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);	if (dev == NULL)	/* Find VT8237 southbridge */		dev = pci_get_device(PCI_VENDOR_ID_VIA,				     PCI_DEVICE_ID_VIA_8237, NULL);	if (dev != NULL) {		/* Set transition time to max */		pci_read_config_byte(dev, 0xec, &pci_cmd);		pci_cmd &= ~(1 << 2);		pci_write_config_byte(dev, 0xec, pci_cmd);		pci_read_config_byte(dev, 0xe4, &pci_cmd);		pci_cmd &= ~(1 << 7);		pci_write_config_byte(dev, 0xe4, pci_cmd);		pci_read_config_byte(dev, 0xe5, &pci_cmd);		pci_cmd |= 1 << 7;		pci_write_config_byte(dev, 0xe5, pci_cmd);		/* Get address of ACPI registers block*/		pci_read_config_byte(dev, 0x81, &pci_cmd);		if (pci_cmd & 1 << 7) {			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);			acpi_regs_addr &= 0xff00;			printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", acpi_regs_addr);		}		pci_dev_put(dev);		return 1;	}	return 0;}static int __init longhaul_cpu_init(struct cpufreq_policy *policy){	struct cpuinfo_x86 *c = &cpu_data(0);	char *cpuname=NULL;	int ret;	u32 lo, hi;	/* Check what we have on this motherboard */	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:		switch (c->x86_mask) {		case 0:			longhaul_version = TYPE_LONGHAUL_V1;			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:			longhaul_version = TYPE_LONGHAUL_V1;			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:		longhaul_version = TYPE_POWERSAVER;		numscales = 32;		memcpy(clock_ratio,		       nehemiah_clock_ratio,		       sizeof(nehemiah_clock_ratio));		memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));		switch (c->x86_mask) {		case 0 ... 1:			cpu_model = CPU_NEHEMIAH;			cpuname = "C3 'Nehemiah A' [C5XLOE]";			break;		case 2 ... 4:			cpu_model = CPU_NEHEMIAH;			cpuname = "C3 'Nehemiah B' [C5XLOH]";			break;		case 5 ... 15:			cpu_model = CPU_NEHEMIAH_C;			cpuname = "C3 'Nehemiah C' [C5P]";			break;		}		break;	default:		cpuname = "Unknown";		break;	}	/* Check Longhaul ver. 2 */	if (longhaul_version == TYPE_LONGHAUL_V2) {		rdmsr(MSR_VIA_LONGHAUL, lo, hi);		if (lo == 0 && hi == 0)			/* Looks like MSR isn't present */			longhaul_version = TYPE_LONGHAUL_V1;	}	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;	};	/* Doesn't hurt */	longhaul_setup_southbridge();	/* Find ACPI data for processor */	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,				ACPI_UINT32_MAX, &longhaul_walk_callback,				NULL, (void *)&pr);	/* Check ACPI support for C3 state */	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {		cx = &pr->power.states[ACPI_STATE_C3];		if (cx->address > 0 && cx->latency <= 1000)			longhaul_flags |= USE_ACPI_C3;	}	/* Disable if it isn't working */	if (disable_acpi_c3)		longhaul_flags &= ~USE_ACPI_C3;	/* Check if northbridge is friendly */	if (enable_arbiter_disable())		longhaul_flags |= USE_NORTHBRIDGE;	/* Check ACPI support for bus master arbiter disable */	if (!(longhaul_flags & USE_ACPI_C3	     || longhaul_flags & USE_NORTHBRIDGE)	    && ((pr == NULL) || !(pr->flags.bm_control))) {		printk(KERN_ERR PFX			"No ACPI support. Unsupported northbridge.\n");		return -ENODEV;	}	if (longhaul_flags & USE_NORTHBRIDGE)		printk(KERN_INFO PFX "Using northbridge support.\n");	if (longhaul_flags & USE_ACPI_C3)		printk(KERN_INFO PFX "Using ACPI support.\n");	ret = longhaul_get_ranges();	if (ret != 0)		return ret;	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))		longhaul_setup_voltagescaling();	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(0);	if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)		return -ENODEV;#ifdef CONFIG_SMP	if (num_online_cpus() > 1) {		printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");		return -ENODEV;	}#endif#ifdef CONFIG_X86_IO_APIC	if (cpu_has_apic) {		printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n");		return -ENODEV;	}#endif	switch (c->x86_model) {	case 6 ... 9:		return cpufreq_register_driver(&longhaul_driver);	case 10:		printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n");	default:		;;	}	return -ENODEV;}static void __exit longhaul_exit(void){	int i;	for (i=0; i < numscales; i++) {		if (clock_ratio[i] == maxmult) {			longhaul_setstate(i);			break;		}	}	cpufreq_unregister_driver(&longhaul_driver);	kfree(longhaul_table);}/* Even if BIOS is exporting ACPI C3 state, and it is used * with success when CPU is idle, this state doesn't * trigger frequency transition in some cases. */module_param (disable_acpi_c3, int, 0644);MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");/* Change CPU voltage with frequency. Very usefull to save * power, but most VIA C3 processors aren't supporting it. */module_param (scale_voltage, int, 0644);MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");/* Force revision key to 0 for processors which doesn't * support voltage scaling, but are introducing itself as * such. */module_param(revid_errata, int, 0644);MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");MODULE_LICENSE ("GPL");late_initcall(longhaul_init);module_exit(longhaul_exit);

⌨️ 快捷键说明

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