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

📄 powernow-k8.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
			data->currfid, reqfid);		return 1;	}	if (savevid != data->currvid) {		printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n",			savevid, data->currvid);		return 1;	}	dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n",		data->currfid, data->currvid);	return 0;}/* Phase 3 - core voltage transition flow ... jump to the final vid. */static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid){	u32 savefid = data->currfid;	u32 savereqvid = reqvid;	dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",		smp_processor_id(),		data->currfid, data->currvid);	if (reqvid != data->currvid) {		if (write_new_vid(data, reqvid))			return 1;		if (savefid != data->currfid) {			printk(KERN_ERR PFX			       "ph3: bad fid change, save 0x%x, curr 0x%x\n",			       savefid, data->currfid);			return 1;		}		if (data->currvid != reqvid) {			printk(KERN_ERR PFX			       "ph3: failed vid transition\n, req 0x%x, curr 0x%x",			       reqvid, data->currvid);			return 1;		}	}	if (query_current_values_with_pending_wait(data))		return 1;	if (savereqvid != data->currvid) {		dprintk("ph3 failed, currvid 0x%x\n", data->currvid);		return 1;	}	if (savefid != data->currfid) {		dprintk("ph3 failed, currfid changed 0x%x\n",			data->currfid);		return 1;	}	dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n",		data->currfid, data->currvid);	return 0;}static int check_supported_cpu(unsigned int cpu){	cpumask_t oldmask = CPU_MASK_ALL;	u32 eax, ebx, ecx, edx;	unsigned int rc = 0;	oldmask = current->cpus_allowed;	set_cpus_allowed(current, cpumask_of_cpu(cpu));	if (smp_processor_id() != cpu) {		printk(KERN_ERR "limiting to cpu %u failed\n", cpu);		goto out;	}	if (current_cpu_data.x86_vendor != X86_VENDOR_AMD)		goto out;	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);	if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||	    ((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||	    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_F)) {		printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);		goto out;	}	eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);	if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {		printk(KERN_INFO PFX		       "No frequency change capabilities detected\n");		goto out;	}	cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);	if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {		printk(KERN_INFO PFX "Power state transitions not supported\n");		goto out;	}	rc = 1;out:	set_cpus_allowed(current, oldmask);	return rc;}static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid){	unsigned int j;	u8 lastfid = 0xff;	for (j = 0; j < data->numps; j++) {		if (pst[j].vid > LEAST_VID) {			printk(KERN_ERR PFX "vid %d invalid : 0x%x\n", j, pst[j].vid);			return -EINVAL;		}		if (pst[j].vid < data->rvo) {	/* vid + rvo >= 0 */			printk(KERN_ERR BFX "0 vid exceeded with pstate %d\n", j);			return -ENODEV;		}		if (pst[j].vid < maxvid + data->rvo) {	/* vid + rvo >= maxvid */			printk(KERN_ERR BFX "maxvid exceeded with pstate %d\n", j);			return -ENODEV;		}		if ((pst[j].fid > MAX_FID)		    || (pst[j].fid & 1)		    || (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) {			/* Only first fid is allowed to be in "low" range */			printk(KERN_ERR PFX "two low fids - %d : 0x%x\n", j, pst[j].fid);			return -EINVAL;		}		if (pst[j].fid < lastfid)			lastfid = pst[j].fid;	}	if (lastfid & 1) {		printk(KERN_ERR PFX "lastfid invalid\n");		return -EINVAL;	}	if (lastfid > LO_FID_TABLE_TOP)		printk(KERN_INFO PFX  "first fid not from lo freq table\n");	return 0;}static void print_basics(struct powernow_k8_data *data){	int j;	for (j = 0; j < data->numps; j++) {		if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)			printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,				data->powernow_table[j].index & 0xff,				data->powernow_table[j].frequency/1000,				data->powernow_table[j].index >> 8,				find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));	}	if (data->batps)		printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);}static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid){	struct cpufreq_frequency_table *powernow_table;	unsigned int j;	if (data->batps) {    /* use ACPI support to get full speed on mains power */		printk(KERN_WARNING PFX "Only %d pstates usable (use ACPI driver for full range\n", data->batps);		data->numps = data->batps;	}	for ( j=1; j<data->numps; j++ ) {		if (pst[j-1].fid >= pst[j].fid) {			printk(KERN_ERR PFX "PST out of sequence\n");			return -EINVAL;		}	}	if (data->numps < 2) {		printk(KERN_ERR PFX "no p states to transition\n");		return -ENODEV;	}	if (check_pst_table(data, pst, maxvid))		return -EINVAL;	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)		* (data->numps + 1)), GFP_KERNEL);	if (!powernow_table) {		printk(KERN_ERR PFX "powernow_table memory alloc failure\n");		return -ENOMEM;	}	for (j = 0; j < data->numps; j++) {		powernow_table[j].index = pst[j].fid; /* lower 8 bits */		powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */		powernow_table[j].frequency = find_khz_freq_from_fid(pst[j].fid);	}	powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;	powernow_table[data->numps].index = 0;	if (query_current_values_with_pending_wait(data)) {		kfree(powernow_table);		return -EIO;	}	dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);	data->powernow_table = powernow_table;	print_basics(data);	for (j = 0; j < data->numps; j++)		if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))			return 0;	dprintk("currfid/vid do not match PST, ignoring\n");	return 0;}/* Find and validate the PSB/PST table in BIOS. */static int find_psb_table(struct powernow_k8_data *data){	struct psb_s *psb;	unsigned int i;	u32 mvs;	u8 maxvid;	u32 cpst = 0;	u32 thiscpuid;	for (i = 0xc0000; i < 0xffff0; i += 0x10) {		/* Scan BIOS looking for the signature. */		/* It can not be at ffff0 - it is too big. */		psb = phys_to_virt(i);		if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)			continue;		dprintk("found PSB header at 0x%p\n", psb);		dprintk("table vers: 0x%x\n", psb->tableversion);		if (psb->tableversion != PSB_VERSION_1_4) {			printk(KERN_INFO BFX "PSB table is not v1.4\n");			return -ENODEV;		}		dprintk("flags: 0x%x\n", psb->flags1);		if (psb->flags1) {			printk(KERN_ERR BFX "unknown flags\n");			return -ENODEV;		}		data->vstable = psb->vstable;		dprintk("voltage stabilization time: %d(*20us)\n", data->vstable);		dprintk("flags2: 0x%x\n", psb->flags2);		data->rvo = psb->flags2 & 3;		data->irt = ((psb->flags2) >> 2) & 3;		mvs = ((psb->flags2) >> 4) & 3;		data->vidmvs = 1 << mvs;		data->batps = ((psb->flags2) >> 6) & 3;		dprintk("ramp voltage offset: %d\n", data->rvo);		dprintk("isochronous relief time: %d\n", data->irt);		dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);		dprintk("numpst: 0x%x\n", psb->num_tables);		cpst = psb->num_tables;		if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){			thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);			if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {				cpst = 1;			}		}		if (cpst != 1) {			printk(KERN_ERR BFX "numpst must be 1\n");			return -ENODEV;		}		data->plllock = psb->plllocktime;		dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);		dprintk("maxfid: 0x%x\n", psb->maxfid);		dprintk("maxvid: 0x%x\n", psb->maxvid);		maxvid = psb->maxvid;		data->numps = psb->numps;		dprintk("numpstates: 0x%x\n", data->numps);		return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid);	}	/*	 * If you see this message, complain to BIOS manufacturer. If	 * he tells you "we do not support Linux" or some similar	 * nonsense, remember that Windows 2000 uses the same legacy	 * mechanism that the old Linux PSB driver uses. Tell them it	 * is broken with Windows 2000.	 *	 * The reference to the AMD documentation is chapter 9 in the	 * BIOS and Kernel Developer's Guide, which is available on	 * www.amd.com	 */	printk(KERN_INFO PFX "BIOS error - no PSB or ACPI _PSS objects\n");	return -ENODEV;}#ifdef CONFIG_X86_POWERNOW_K8_ACPIstatic void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index){	if (!data->acpi_data.state_count)		return;	data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;	data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK;	data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;	data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK;	data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK);	data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK;}static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data){	int i;	int cntlofreq = 0;	struct cpufreq_frequency_table *powernow_table;	if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {		dprintk("register performance failed: bad ACPI data\n");		return -EIO;	}	/* verify the data contained in the ACPI structures */	if (data->acpi_data.state_count <= 1) {		dprintk("No ACPI P-States\n");		goto err_out;	}	if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||		(data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {		dprintk("Invalid control/status registers (%x - %x)\n",			data->acpi_data.control_register.space_id,			data->acpi_data.status_register.space_id);		goto err_out;	}	/* fill in data->powernow_table */	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)		* (data->acpi_data.state_count + 1)), GFP_KERNEL);	if (!powernow_table) {		dprintk("powernow_table memory alloc failure\n");		goto err_out;	}	for (i = 0; i < data->acpi_data.state_count; i++) {		u32 fid;		u32 vid;		if (data->exttype) {			fid = data->acpi_data.states[i].status & FID_MASK;			vid = (data->acpi_data.states[i].status >> VID_SHIFT) & VID_MASK;		} else {			fid = data->acpi_data.states[i].control & FID_MASK;			vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;		}		dprintk("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);		powernow_table[i].index = fid; /* lower 8 bits */		powernow_table[i].index |= (vid << 8); /* upper 8 bits */		powernow_table[i].frequency = find_khz_freq_from_fid(fid);		/* verify frequency is OK */		if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||			(powernow_table[i].frequency < (MIN_FREQ * 1000))) {			dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;			continue;		}		/* verify voltage is OK - BIOSs are using "off" to indicate invalid */		if (vid == VID_OFF) {			dprintk("invalid vid %u, ignoring\n", vid);			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;			continue;		}		/* verify only 1 entry from the lo frequency table */		if (fid < HI_FID_TABLE_BOTTOM) {			if (cntlofreq) {				/* if both entries are the same, ignore this				 * one... 				 */				if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||

⌨️ 快捷键说明

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