brintos

brintos / linux-shallow public Read only

0
0
Text · 15.8 KiB · 4271446 Raw
696 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  AMD K7 Powernow driver.4 *  (C) 2003 Dave Jones on behalf of SuSE Labs.5 *6 *  Based upon datasheets & sample CPUs kindly provided by AMD.7 *8 * Errata 5:9 *  CPU may fail to execute a FID/VID change in presence of interrupt.10 *  - We cli/sti on stepping A0 CPUs around the FID/VID transition.11 * Errata 15:12 *  CPU with half frequency multipliers may hang upon wakeup from disconnect.13 *  - We disable half multipliers if ACPI is used on A0 stepping CPUs.14 */15 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt17 18#include <linux/kernel.h>19#include <linux/module.h>20#include <linux/moduleparam.h>21#include <linux/init.h>22#include <linux/cpufreq.h>23#include <linux/slab.h>24#include <linux/string.h>25#include <linux/dmi.h>26#include <linux/timex.h>27#include <linux/io.h>28 29#include <asm/timer.h>		/* Needed for recalibrate_cpu_khz() */30#include <asm/msr.h>31#include <asm/cpu_device_id.h>32 33#ifdef CONFIG_X86_POWERNOW_K7_ACPI34#include <linux/acpi.h>35#include <acpi/processor.h>36#endif37 38#include "powernow-k7.h"39 40struct psb_s {41	u8 signature[10];42	u8 tableversion;43	u8 flags;44	u16 settlingtime;45	u8 reserved1;46	u8 numpst;47};48 49struct pst_s {50	u32 cpuid;51	u8 fsbspeed;52	u8 maxfid;53	u8 startvid;54	u8 numpstates;55};56 57#ifdef CONFIG_X86_POWERNOW_K7_ACPI58union powernow_acpi_control_t {59	struct {60		unsigned long fid:5,61			vid:5,62			sgtc:20,63			res1:2;64	} bits;65	unsigned long val;66};67#endif68 69/* divide by 1000 to get VCore voltage in V. */70static const int mobile_vid_table[32] = {71    2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,72    1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,73    1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,74    1075, 1050, 1025, 1000, 975, 950, 925, 0,75};76 77/* divide by 10 to get FID. */78static const int fid_codes[32] = {79    110, 115, 120, 125, 50, 55, 60, 65,80    70, 75, 80, 85, 90, 95, 100, 105,81    30, 190, 40, 200, 130, 135, 140, 210,82    150, 225, 160, 165, 170, 180, -1, -1,83};84 85/* This parameter is used in order to force ACPI instead of legacy method for86 * configuration purpose.87 */88 89static int acpi_force;90 91static struct cpufreq_frequency_table *powernow_table;92 93static unsigned int can_scale_bus;94static unsigned int can_scale_vid;95static unsigned int minimum_speed = -1;96static unsigned int maximum_speed;97static unsigned int number_scales;98static unsigned int fsb;99static unsigned int latency;100static char have_a0;101 102static int check_fsb(unsigned int fsbspeed)103{104	int delta;105	unsigned int f = fsb / 1000;106 107	delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;108	return delta < 5;109}110 111static const struct x86_cpu_id powernow_k7_cpuids[] = {112	X86_MATCH_VENDOR_FAM(AMD, 6, NULL),113	{}114};115MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);116 117static int check_powernow(void)118{119	struct cpuinfo_x86 *c = &cpu_data(0);120	unsigned int maxei, eax, ebx, ecx, edx;121 122	if (!x86_match_cpu(powernow_k7_cpuids))123		return 0;124 125	/* Get maximum capabilities */126	maxei = cpuid_eax(0x80000000);127	if (maxei < 0x80000007) {	/* Any powernow info ? */128#ifdef MODULE129		pr_info("No powernow capabilities detected\n");130#endif131		return 0;132	}133 134	if ((c->x86_model == 6) && (c->x86_stepping == 0)) {135		pr_info("K7 660[A0] core detected, enabling errata workarounds\n");136		have_a0 = 1;137	}138 139	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);140 141	/* Check we can actually do something before we say anything.*/142	if (!(edx & (1 << 1 | 1 << 2)))143		return 0;144 145	pr_info("PowerNOW! Technology present. Can scale: ");146 147	if (edx & 1 << 1) {148		pr_cont("frequency");149		can_scale_bus = 1;150	}151 152	if ((edx & (1 << 1 | 1 << 2)) == 0x6)153		pr_cont(" and ");154 155	if (edx & 1 << 2) {156		pr_cont("voltage");157		can_scale_vid = 1;158	}159 160	pr_cont("\n");161	return 1;162}163 164#ifdef CONFIG_X86_POWERNOW_K7_ACPI165static void invalidate_entry(unsigned int entry)166{167	powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;168}169#endif170 171static int get_ranges(unsigned char *pst)172{173	unsigned int j;174	unsigned int speed;175	u8 fid, vid;176 177	powernow_table = kzalloc((sizeof(*powernow_table) *178				(number_scales + 1)), GFP_KERNEL);179	if (!powernow_table)180		return -ENOMEM;181 182	for (j = 0 ; j < number_scales; j++) {183		fid = *pst++;184 185		powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;186		powernow_table[j].driver_data = fid; /* lower 8 bits */187 188		speed = powernow_table[j].frequency;189 190		if ((fid_codes[fid] % 10) == 5) {191#ifdef CONFIG_X86_POWERNOW_K7_ACPI192			if (have_a0 == 1)193				invalidate_entry(j);194#endif195		}196 197		if (speed < minimum_speed)198			minimum_speed = speed;199		if (speed > maximum_speed)200			maximum_speed = speed;201 202		vid = *pst++;203		powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */204 205		pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "206			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,207			 fid_codes[fid] % 10, speed/1000, vid,208			 mobile_vid_table[vid]/1000,209			 mobile_vid_table[vid]%1000);210	}211	powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;212	powernow_table[number_scales].driver_data = 0;213 214	return 0;215}216 217 218static void change_FID(int fid)219{220	union msr_fidvidctl fidvidctl;221 222	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);223	if (fidvidctl.bits.FID != fid) {224		fidvidctl.bits.SGTC = latency;225		fidvidctl.bits.FID = fid;226		fidvidctl.bits.VIDC = 0;227		fidvidctl.bits.FIDC = 1;228		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);229	}230}231 232 233static void change_VID(int vid)234{235	union msr_fidvidctl fidvidctl;236 237	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);238	if (fidvidctl.bits.VID != vid) {239		fidvidctl.bits.SGTC = latency;240		fidvidctl.bits.VID = vid;241		fidvidctl.bits.FIDC = 0;242		fidvidctl.bits.VIDC = 1;243		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);244	}245}246 247 248static int powernow_target(struct cpufreq_policy *policy, unsigned int index)249{250	u8 fid, vid;251	struct cpufreq_freqs freqs;252	union msr_fidvidstatus fidvidstatus;253	int cfid;254 255	/* fid are the lower 8 bits of the index we stored into256	 * the cpufreq frequency table in powernow_decode_bios,257	 * vid are the upper 8 bits.258	 */259 260	fid = powernow_table[index].driver_data & 0xFF;261	vid = (powernow_table[index].driver_data & 0xFF00) >> 8;262 263	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);264	cfid = fidvidstatus.bits.CFID;265	freqs.old = fsb * fid_codes[cfid] / 10;266 267	freqs.new = powernow_table[index].frequency;268 269	/* Now do the magic poking into the MSRs.  */270 271	if (have_a0 == 1)	/* A0 errata 5 */272		local_irq_disable();273 274	if (freqs.old > freqs.new) {275		/* Going down, so change FID first */276		change_FID(fid);277		change_VID(vid);278	} else {279		/* Going up, so change VID first */280		change_VID(vid);281		change_FID(fid);282	}283 284 285	if (have_a0 == 1)286		local_irq_enable();287 288	return 0;289}290 291 292#ifdef CONFIG_X86_POWERNOW_K7_ACPI293 294static struct acpi_processor_performance *acpi_processor_perf;295 296static int powernow_acpi_init(void)297{298	int i;299	int retval = 0;300	union powernow_acpi_control_t pc;301 302	if (acpi_processor_perf != NULL && powernow_table != NULL) {303		retval = -EINVAL;304		goto err0;305	}306 307	acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);308	if (!acpi_processor_perf) {309		retval = -ENOMEM;310		goto err0;311	}312 313	if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,314								GFP_KERNEL)) {315		retval = -ENOMEM;316		goto err05;317	}318 319	if (acpi_processor_register_performance(acpi_processor_perf, 0)) {320		retval = -EIO;321		goto err1;322	}323 324	if (acpi_processor_perf->control_register.space_id !=325			ACPI_ADR_SPACE_FIXED_HARDWARE) {326		retval = -ENODEV;327		goto err2;328	}329 330	if (acpi_processor_perf->status_register.space_id !=331			ACPI_ADR_SPACE_FIXED_HARDWARE) {332		retval = -ENODEV;333		goto err2;334	}335 336	number_scales = acpi_processor_perf->state_count;337 338	if (number_scales < 2) {339		retval = -ENODEV;340		goto err2;341	}342 343	powernow_table = kzalloc((sizeof(*powernow_table) *344				(number_scales + 1)), GFP_KERNEL);345	if (!powernow_table) {346		retval = -ENOMEM;347		goto err2;348	}349 350	pc.val = (unsigned long) acpi_processor_perf->states[0].control;351	for (i = 0; i < number_scales; i++) {352		u8 fid, vid;353		struct acpi_processor_px *state =354			&acpi_processor_perf->states[i];355		unsigned int speed, speed_mhz;356 357		pc.val = (unsigned long) state->control;358		pr_debug("acpi:  P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",359			 i,360			 (u32) state->core_frequency,361			 (u32) state->power,362			 (u32) state->transition_latency,363			 (u32) state->control,364			 pc.bits.sgtc);365 366		vid = pc.bits.vid;367		fid = pc.bits.fid;368 369		powernow_table[i].frequency = fsb * fid_codes[fid] / 10;370		powernow_table[i].driver_data = fid; /* lower 8 bits */371		powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */372 373		speed = powernow_table[i].frequency;374		speed_mhz = speed / 1000;375 376		/* processor_perflib will multiply the MHz value by 1000 to377		 * get a KHz value (e.g. 1266000). However, powernow-k7 works378		 * with true KHz values (e.g. 1266768). To ensure that all379		 * powernow frequencies are available, we must ensure that380		 * ACPI doesn't restrict them, so we round up the MHz value381		 * to ensure that perflib's computed KHz value is greater than382		 * or equal to powernow's KHz value.383		 */384		if (speed % 1000 > 0)385			speed_mhz++;386 387		if ((fid_codes[fid] % 10) == 5) {388			if (have_a0 == 1)389				invalidate_entry(i);390		}391 392		pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "393			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,394			 fid_codes[fid] % 10, speed_mhz, vid,395			 mobile_vid_table[vid]/1000,396			 mobile_vid_table[vid]%1000);397 398		if (state->core_frequency != speed_mhz) {399			state->core_frequency = speed_mhz;400			pr_debug("   Corrected ACPI frequency to %d\n",401				speed_mhz);402		}403 404		if (latency < pc.bits.sgtc)405			latency = pc.bits.sgtc;406 407		if (speed < minimum_speed)408			minimum_speed = speed;409		if (speed > maximum_speed)410			maximum_speed = speed;411	}412 413	powernow_table[i].frequency = CPUFREQ_TABLE_END;414	powernow_table[i].driver_data = 0;415 416	/* notify BIOS that we exist */417	acpi_processor_notify_smm(THIS_MODULE);418 419	return 0;420 421err2:422	acpi_processor_unregister_performance(0);423err1:424	free_cpumask_var(acpi_processor_perf->shared_cpu_map);425err05:426	kfree(acpi_processor_perf);427err0:428	pr_warn("ACPI perflib can not be used on this platform\n");429	acpi_processor_perf = NULL;430	return retval;431}432#else433static int powernow_acpi_init(void)434{435	pr_info("no support for ACPI processor found - please recompile your kernel with ACPI processor\n");436	return -EINVAL;437}438#endif439 440static void print_pst_entry(struct pst_s *pst, unsigned int j)441{442	pr_debug("PST:%d (@%p)\n", j, pst);443	pr_debug(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",444		pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);445}446 447static int powernow_decode_bios(int maxfid, int startvid)448{449	struct psb_s *psb;450	struct pst_s *pst;451	unsigned int i, j;452	unsigned char *p;453	unsigned int etuple;454	unsigned int ret;455 456	etuple = cpuid_eax(0x80000001);457 458	for (i = 0xC0000; i < 0xffff0 ; i += 16) {459 460		p = phys_to_virt(i);461 462		if (memcmp(p, "AMDK7PNOW!",  10) == 0) {463			pr_debug("Found PSB header at %p\n", p);464			psb = (struct psb_s *) p;465			pr_debug("Table version: 0x%x\n", psb->tableversion);466			if (psb->tableversion != 0x12) {467				pr_info("Sorry, only v1.2 tables supported right now\n");468				return -ENODEV;469			}470 471			pr_debug("Flags: 0x%x\n", psb->flags);472			if ((psb->flags & 1) == 0)473				pr_debug("Mobile voltage regulator\n");474			else475				pr_debug("Desktop voltage regulator\n");476 477			latency = psb->settlingtime;478			if (latency < 100) {479				pr_info("BIOS set settling time to %d microseconds. Should be at least 100. Correcting.\n",480					latency);481				latency = 100;482			}483			pr_debug("Settling Time: %d microseconds.\n",484					psb->settlingtime);485			pr_debug("Has %d PST tables. (Only dumping ones "486					"relevant to this CPU).\n",487					psb->numpst);488 489			p += sizeof(*psb);490 491			pst = (struct pst_s *) p;492 493			for (j = 0; j < psb->numpst; j++) {494				pst = (struct pst_s *) p;495				number_scales = pst->numpstates;496 497				if ((etuple == pst->cpuid) &&498				    check_fsb(pst->fsbspeed) &&499				    (maxfid == pst->maxfid) &&500				    (startvid == pst->startvid)) {501					print_pst_entry(pst, j);502					p = (char *)pst + sizeof(*pst);503					ret = get_ranges(p);504					return ret;505				} else {506					unsigned int k;507					p = (char *)pst + sizeof(*pst);508					for (k = 0; k < number_scales; k++)509						p += 2;510				}511			}512			pr_info("No PST tables match this cpuid (0x%x)\n",513				etuple);514			pr_info("This is indicative of a broken BIOS\n");515 516			return -EINVAL;517		}518		p++;519	}520 521	return -ENODEV;522}523 524 525/*526 * We use the fact that the bus frequency is somehow527 * a multiple of 100000/3 khz, then we compute sgtc according528 * to this multiple.529 * That way, we match more how AMD thinks all of that work.530 * We will then get the same kind of behaviour already tested under531 * the "well-known" other OS.532 */533static int fixup_sgtc(void)534{535	unsigned int sgtc;536	unsigned int m;537 538	m = fsb / 3333;539	if ((m % 10) >= 5)540		m += 5;541 542	m /= 10;543 544	sgtc = 100 * m * latency;545	sgtc = sgtc / 3;546	if (sgtc > 0xfffff) {547		pr_warn("SGTC too large %d\n", sgtc);548		sgtc = 0xfffff;549	}550	return sgtc;551}552 553static unsigned int powernow_get(unsigned int cpu)554{555	union msr_fidvidstatus fidvidstatus;556	unsigned int cfid;557 558	if (cpu)559		return 0;560	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);561	cfid = fidvidstatus.bits.CFID;562 563	return fsb * fid_codes[cfid] / 10;564}565 566 567static int acer_cpufreq_pst(const struct dmi_system_id *d)568{569	pr_warn("%s laptop with broken PST tables in BIOS detected\n",570		d->ident);571	pr_warn("You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");572	pr_warn("cpufreq scaling has been disabled as a result of this\n");573	return 0;574}575 576/*577 * Some Athlon laptops have really fucked PST tables.578 * A BIOS update is all that can save them.579 * Mention this, and disable cpufreq.580 */581static const struct dmi_system_id powernow_dmi_table[] = {582	{583		.callback = acer_cpufreq_pst,584		.ident = "Acer Aspire",585		.matches = {586			DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),587			DMI_MATCH(DMI_BIOS_VERSION, "3A71"),588		},589	},590	{ }591};592 593static int powernow_cpu_init(struct cpufreq_policy *policy)594{595	union msr_fidvidstatus fidvidstatus;596	int result;597 598	if (policy->cpu != 0)599		return -ENODEV;600 601	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);602 603	recalibrate_cpu_khz();604 605	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];606	if (!fsb) {607		pr_warn("can not determine bus frequency\n");608		return -EINVAL;609	}610	pr_debug("FSB: %3dMHz\n", fsb/1000);611 612	if (dmi_check_system(powernow_dmi_table) || acpi_force) {613		pr_info("PSB/PST known to be broken - trying ACPI instead\n");614		result = powernow_acpi_init();615	} else {616		result = powernow_decode_bios(fidvidstatus.bits.MFID,617				fidvidstatus.bits.SVID);618		if (result) {619			pr_info("Trying ACPI perflib\n");620			maximum_speed = 0;621			minimum_speed = -1;622			latency = 0;623			result = powernow_acpi_init();624			if (result) {625				pr_info("ACPI and legacy methods failed\n");626			}627		} else {628			/* SGTC use the bus clock as timer */629			latency = fixup_sgtc();630			pr_info("SGTC: %d\n", latency);631		}632	}633 634	if (result)635		return result;636 637	pr_info("Minimum speed %d MHz - Maximum speed %d MHz\n",638		minimum_speed/1000, maximum_speed/1000);639 640	policy->cpuinfo.transition_latency =641		cpufreq_scale(2000000UL, fsb, latency);642	policy->freq_table = powernow_table;643 644	return 0;645}646 647static void powernow_cpu_exit(struct cpufreq_policy *policy)648{649#ifdef CONFIG_X86_POWERNOW_K7_ACPI650	if (acpi_processor_perf) {651		acpi_processor_unregister_performance(0);652		free_cpumask_var(acpi_processor_perf->shared_cpu_map);653		kfree(acpi_processor_perf);654	}655#endif656 657	kfree(powernow_table);658}659 660static struct cpufreq_driver powernow_driver = {661	.verify		= cpufreq_generic_frequency_table_verify,662	.target_index	= powernow_target,663	.get		= powernow_get,664#ifdef CONFIG_X86_POWERNOW_K7_ACPI665	.bios_limit	= acpi_processor_get_bios_limit,666#endif667	.init		= powernow_cpu_init,668	.exit		= powernow_cpu_exit,669	.name		= "powernow-k7",670	.attr		= cpufreq_generic_attr,671};672 673static int __init powernow_init(void)674{675	if (check_powernow() == 0)676		return -ENODEV;677	return cpufreq_register_driver(&powernow_driver);678}679 680 681static void __exit powernow_exit(void)682{683	cpufreq_unregister_driver(&powernow_driver);684}685 686module_param(acpi_force,  int, 0444);687MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");688 689MODULE_AUTHOR("Dave Jones");690MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");691MODULE_LICENSE("GPL");692 693late_initcall(powernow_init);694module_exit(powernow_exit);695 696