powernow-k7.c 15.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 *  AMD K7 Powernow driver.
D
Dave Jones 已提交
3
 *  (C) 2003 Dave Jones on behalf of SuSE Labs.
L
Linus Torvalds 已提交
4 5 6 7
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *  Based upon datasheets & sample CPUs kindly provided by AMD.
 *
8 9 10 11 12 13
 * Errata 5:
 *  CPU may fail to execute a FID/VID change in presence of interrupt.
 *  - We cli/sti on stepping A0 CPUs around the FID/VID transition.
 * Errata 15:
 *  CPU with half frequency multipliers may hang upon wakeup from disconnect.
 *  - We disable half multipliers if ACPI is used on A0 stepping CPUs.
L
Linus Torvalds 已提交
14 15
 */

16 17
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/dmi.h>
26 27
#include <linux/timex.h>
#include <linux/io.h>
L
Linus Torvalds 已提交
28

29
#include <asm/timer.h>		/* Needed for recalibrate_cpu_khz() */
L
Linus Torvalds 已提交
30
#include <asm/msr.h>
31
#include <asm/cpu_device_id.h>
L
Linus Torvalds 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

#ifdef CONFIG_X86_POWERNOW_K7_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif

#include "powernow-k7.h"

struct psb_s {
	u8 signature[10];
	u8 tableversion;
	u8 flags;
	u16 settlingtime;
	u8 reserved1;
	u8 numpst;
};

struct pst_s {
	u32 cpuid;
	u8 fsbspeed;
	u8 maxfid;
	u8 startvid;
	u8 numpstates;
};

#ifdef CONFIG_X86_POWERNOW_K7_ACPI
union powernow_acpi_control_t {
	struct {
		unsigned long fid:5,
61 62 63
			vid:5,
			sgtc:20,
			res1:2;
L
Linus Torvalds 已提交
64 65 66 67 68 69
	} bits;
	unsigned long val;
};
#endif

/* divide by 1000 to get VCore voltage in V. */
70
static const int mobile_vid_table[32] = {
L
Linus Torvalds 已提交
71 72 73 74 75 76 77
    2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
    1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
    1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
    1075, 1050, 1025, 1000, 975, 950, 925, 0,
};

/* divide by 10 to get FID. */
78
static const int fid_codes[32] = {
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    110, 115, 120, 125, 50, 55, 60, 65,
    70, 75, 80, 85, 90, 95, 100, 105,
    30, 190, 40, 200, 130, 135, 140, 210,
    150, 225, 160, 165, 170, 180, -1, -1,
};

/* This parameter is used in order to force ACPI instead of legacy method for
 * configuration purpose.
 */

static int acpi_force;

static struct cpufreq_frequency_table *powernow_table;

static unsigned int can_scale_bus;
static unsigned int can_scale_vid;
95
static unsigned int minimum_speed = -1;
L
Linus Torvalds 已提交
96 97 98 99 100 101 102 103 104 105 106 107
static unsigned int maximum_speed;
static unsigned int number_scales;
static unsigned int fsb;
static unsigned int latency;
static char have_a0;

static int check_fsb(unsigned int fsbspeed)
{
	int delta;
	unsigned int f = fsb / 1000;

	delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
108
	return delta < 5;
L
Linus Torvalds 已提交
109 110
}

111
static const struct x86_cpu_id powernow_k7_cpuids[] = {
112
	{ X86_VENDOR_AMD, 6, },
113 114 115 116
	{}
};
MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);

L
Linus Torvalds 已提交
117 118
static int check_powernow(void)
{
119
	struct cpuinfo_x86 *c = &cpu_data(0);
L
Linus Torvalds 已提交
120 121
	unsigned int maxei, eax, ebx, ecx, edx;

122
	if (!x86_match_cpu(powernow_k7_cpuids))
L
Linus Torvalds 已提交
123 124 125
		return 0;

	/* Get maximum capabilities */
126
	maxei = cpuid_eax(0x80000000);
L
Linus Torvalds 已提交
127 128
	if (maxei < 0x80000007) {	/* Any powernow info ? */
#ifdef MODULE
129
		pr_info("No powernow capabilities detected\n");
L
Linus Torvalds 已提交
130 131 132 133 134
#endif
		return 0;
	}

	if ((c->x86_model == 6) && (c->x86_mask == 0)) {
135
		pr_info("K7 660[A0] core detected, enabling errata workarounds\n");
L
Linus Torvalds 已提交
136 137 138 139 140 141 142 143 144
		have_a0 = 1;
	}

	cpuid(0x80000007, &eax, &ebx, &ecx, &edx);

	/* Check we can actually do something before we say anything.*/
	if (!(edx & (1 << 1 | 1 << 2)))
		return 0;

145
	pr_info("PowerNOW! Technology present. Can scale: ");
L
Linus Torvalds 已提交
146 147

	if (edx & 1 << 1) {
148
		pr_cont("frequency");
149
		can_scale_bus = 1;
L
Linus Torvalds 已提交
150 151 152
	}

	if ((edx & (1 << 1 | 1 << 2)) == 0x6)
153
		pr_cont(" and ");
L
Linus Torvalds 已提交
154 155

	if (edx & 1 << 2) {
156
		pr_cont("voltage");
157
		can_scale_vid = 1;
L
Linus Torvalds 已提交
158 159
	}

160
	pr_cont("\n");
L
Linus Torvalds 已提交
161 162 163
	return 1;
}

164
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
165 166 167 168
static void invalidate_entry(unsigned int entry)
{
	powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
}
169
#endif
L
Linus Torvalds 已提交
170

171
static int get_ranges(unsigned char *pst)
L
Linus Torvalds 已提交
172 173 174 175 176
{
	unsigned int j;
	unsigned int speed;
	u8 fid, vid;

177
	powernow_table = kzalloc((sizeof(*powernow_table) *
178
				(number_scales + 1)), GFP_KERNEL);
L
Linus Torvalds 已提交
179 180 181
	if (!powernow_table)
		return -ENOMEM;

182
	for (j = 0 ; j < number_scales; j++) {
L
Linus Torvalds 已提交
183 184 185
		fid = *pst++;

		powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
186
		powernow_table[j].driver_data = fid; /* lower 8 bits */
L
Linus Torvalds 已提交
187 188 189

		speed = powernow_table[j].frequency;

190
		if ((fid_codes[fid] % 10) == 5) {
L
Linus Torvalds 已提交
191 192
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
			if (have_a0 == 1)
193
				invalidate_entry(j);
L
Linus Torvalds 已提交
194 195 196 197 198 199 200 201 202
#endif
		}

		if (speed < minimum_speed)
			minimum_speed = speed;
		if (speed > maximum_speed)
			maximum_speed = speed;

		vid = *pst++;
203
		powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
L
Linus Torvalds 已提交
204

205
		pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
206 207
			 "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
			 fid_codes[fid] % 10, speed/1000, vid,
L
Linus Torvalds 已提交
208 209 210 211
			 mobile_vid_table[vid]/1000,
			 mobile_vid_table[vid]%1000);
	}
	powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
212
	powernow_table[number_scales].driver_data = 0;
L
Linus Torvalds 已提交
213 214 215 216 217 218 219 220 221

	return 0;
}


static void change_FID(int fid)
{
	union msr_fidvidctl fidvidctl;

222
	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
L
Linus Torvalds 已提交
223 224 225 226 227
	if (fidvidctl.bits.FID != fid) {
		fidvidctl.bits.SGTC = latency;
		fidvidctl.bits.FID = fid;
		fidvidctl.bits.VIDC = 0;
		fidvidctl.bits.FIDC = 1;
228
		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
L
Linus Torvalds 已提交
229 230 231 232 233 234 235 236
	}
}


static void change_VID(int vid)
{
	union msr_fidvidctl fidvidctl;

237
	rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
L
Linus Torvalds 已提交
238 239 240 241 242
	if (fidvidctl.bits.VID != vid) {
		fidvidctl.bits.SGTC = latency;
		fidvidctl.bits.VID = vid;
		fidvidctl.bits.FIDC = 0;
		fidvidctl.bits.VIDC = 1;
243
		wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
L
Linus Torvalds 已提交
244 245 246 247
	}
}


248
static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258 259
{
	u8 fid, vid;
	struct cpufreq_freqs freqs;
	union msr_fidvidstatus fidvidstatus;
	int cfid;

	/* fid are the lower 8 bits of the index we stored into
	 * the cpufreq frequency table in powernow_decode_bios,
	 * vid are the upper 8 bits.
	 */

260 261
	fid = powernow_table[index].driver_data & 0xFF;
	vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
L
Linus Torvalds 已提交
262

263
	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	cfid = fidvidstatus.bits.CFID;
	freqs.old = fsb * fid_codes[cfid] / 10;

	freqs.new = powernow_table[index].frequency;

	/* Now do the magic poking into the MSRs.  */

	if (have_a0 == 1)	/* A0 errata 5 */
		local_irq_disable();

	if (freqs.old > freqs.new) {
		/* Going down, so change FID first */
		change_FID(fid);
		change_VID(vid);
	} else {
		/* Going up, so change VID first */
		change_VID(vid);
		change_FID(fid);
	}


	if (have_a0 == 1)
		local_irq_enable();

288
	return 0;
L
Linus Torvalds 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
}


#ifdef CONFIG_X86_POWERNOW_K7_ACPI

static struct acpi_processor_performance *acpi_processor_perf;

static int powernow_acpi_init(void)
{
	int i;
	int retval = 0;
	union powernow_acpi_control_t pc;

	if (acpi_processor_perf != NULL && powernow_table != NULL) {
		retval = -EINVAL;
		goto err0;
	}

307
	acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
L
Linus Torvalds 已提交
308 309 310 311 312
	if (!acpi_processor_perf) {
		retval = -ENOMEM;
		goto err0;
	}

313
	if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map,
314 315 316 317 318
								GFP_KERNEL)) {
		retval = -ENOMEM;
		goto err05;
	}

L
Linus Torvalds 已提交
319 320 321 322 323
	if (acpi_processor_register_performance(acpi_processor_perf, 0)) {
		retval = -EIO;
		goto err1;
	}

324 325
	if (acpi_processor_perf->control_register.space_id !=
			ACPI_ADR_SPACE_FIXED_HARDWARE) {
L
Linus Torvalds 已提交
326 327 328 329
		retval = -ENODEV;
		goto err2;
	}

330 331
	if (acpi_processor_perf->status_register.space_id !=
			ACPI_ADR_SPACE_FIXED_HARDWARE) {
L
Linus Torvalds 已提交
332 333 334 335 336 337 338 339 340 341 342
		retval = -ENODEV;
		goto err2;
	}

	number_scales = acpi_processor_perf->state_count;

	if (number_scales < 2) {
		retval = -ENODEV;
		goto err2;
	}

343
	powernow_table = kzalloc((sizeof(*powernow_table) *
344
				(number_scales + 1)), GFP_KERNEL);
L
Linus Torvalds 已提交
345 346 347 348 349 350 351 352
	if (!powernow_table) {
		retval = -ENOMEM;
		goto err2;
	}

	pc.val = (unsigned long) acpi_processor_perf->states[0].control;
	for (i = 0; i < number_scales; i++) {
		u8 fid, vid;
353 354 355
		struct acpi_processor_px *state =
			&acpi_processor_perf->states[i];
		unsigned int speed, speed_mhz;
L
Linus Torvalds 已提交
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",
L
Linus Torvalds 已提交
359
			 i,
360 361 362 363
			 (u32) state->core_frequency,
			 (u32) state->power,
			 (u32) state->transition_latency,
			 (u32) state->control,
L
Linus Torvalds 已提交
364 365 366 367 368 369
			 pc.bits.sgtc);

		vid = pc.bits.vid;
		fid = pc.bits.fid;

		powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
370 371
		powernow_table[i].driver_data = fid; /* lower 8 bits */
		powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
L
Linus Torvalds 已提交
372 373

		speed = powernow_table[i].frequency;
374 375 376 377 378 379 380 381 382 383 384 385
		speed_mhz = speed / 1000;

		/* processor_perflib will multiply the MHz value by 1000 to
		 * get a KHz value (e.g. 1266000). However, powernow-k7 works
		 * with true KHz values (e.g. 1266768). To ensure that all
		 * powernow frequencies are available, we must ensure that
		 * ACPI doesn't restrict them, so we round up the MHz value
		 * to ensure that perflib's computed KHz value is greater than
		 * or equal to powernow's KHz value.
		 */
		if (speed % 1000 > 0)
			speed_mhz++;
L
Linus Torvalds 已提交
386

387
		if ((fid_codes[fid] % 10) == 5) {
L
Linus Torvalds 已提交
388
			if (have_a0 == 1)
389
				invalidate_entry(i);
L
Linus Torvalds 已提交
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,
L
Linus Torvalds 已提交
395 396 397
			 mobile_vid_table[vid]/1000,
			 mobile_vid_table[vid]%1000);

398 399
		if (state->core_frequency != speed_mhz) {
			state->core_frequency = speed_mhz;
400
			pr_debug("   Corrected ACPI frequency to %d\n",
401 402 403
				speed_mhz);
		}

L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412 413
		if (latency < pc.bits.sgtc)
			latency = pc.bits.sgtc;

		if (speed < minimum_speed)
			minimum_speed = speed;
		if (speed > maximum_speed)
			maximum_speed = speed;
	}

	powernow_table[i].frequency = CPUFREQ_TABLE_END;
414
	powernow_table[i].driver_data = 0;
L
Linus Torvalds 已提交
415 416 417 418 419 420 421

	/* notify BIOS that we exist */
	acpi_processor_notify_smm(THIS_MODULE);

	return 0;

err2:
422
	acpi_processor_unregister_performance(0);
L
Linus Torvalds 已提交
423
err1:
424 425
	free_cpumask_var(acpi_processor_perf->shared_cpu_map);
err05:
L
Linus Torvalds 已提交
426 427
	kfree(acpi_processor_perf);
err0:
428
	pr_warn("ACPI perflib can not be used on this platform\n");
L
Linus Torvalds 已提交
429 430 431 432 433 434
	acpi_processor_perf = NULL;
	return retval;
}
#else
static int powernow_acpi_init(void)
{
435
	pr_info("no support for ACPI processor found - please recompile your kernel with ACPI processor\n");
L
Linus Torvalds 已提交
436 437 438 439
	return -EINVAL;
}
#endif

440 441
static void print_pst_entry(struct pst_s *pst, unsigned int j)
{
442 443
	pr_debug("PST:%d (@%p)\n", j, pst);
	pr_debug(" cpuid: 0x%x  fsb: %d  maxFID: 0x%x  startvid: 0x%x\n",
444 445 446 447
		pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
}

static int powernow_decode_bios(int maxfid, int startvid)
L
Linus Torvalds 已提交
448 449 450 451 452 453 454 455 456 457
{
	struct psb_s *psb;
	struct pst_s *pst;
	unsigned int i, j;
	unsigned char *p;
	unsigned int etuple;
	unsigned int ret;

	etuple = cpuid_eax(0x80000001);

458
	for (i = 0xC0000; i < 0xffff0 ; i += 16) {
L
Linus Torvalds 已提交
459 460 461

		p = phys_to_virt(i);

462
		if (memcmp(p, "AMDK7PNOW!",  10) == 0) {
463
			pr_debug("Found PSB header at %p\n", p);
L
Linus Torvalds 已提交
464
			psb = (struct psb_s *) p;
465
			pr_debug("Table version: 0x%x\n", psb->tableversion);
L
Linus Torvalds 已提交
466
			if (psb->tableversion != 0x12) {
467
				pr_info("Sorry, only v1.2 tables supported right now\n");
L
Linus Torvalds 已提交
468 469 470
				return -ENODEV;
			}

471
			pr_debug("Flags: 0x%x\n", psb->flags);
472
			if ((psb->flags & 1) == 0)
473
				pr_debug("Mobile voltage regulator\n");
474
			else
475
				pr_debug("Desktop voltage regulator\n");
L
Linus Torvalds 已提交
476 477 478

			latency = psb->settlingtime;
			if (latency < 100) {
479
				pr_info("BIOS set settling time to %d microseconds. Should be at least 100. Correcting.\n",
480
					latency);
L
Linus Torvalds 已提交
481 482
				latency = 100;
			}
483
			pr_debug("Settling Time: %d microseconds.\n",
484
					psb->settlingtime);
485
			pr_debug("Has %d PST tables. (Only dumping ones "
486 487
					"relevant to this CPU).\n",
					psb->numpst);
L
Linus Torvalds 已提交
488

489
			p += sizeof(*psb);
L
Linus Torvalds 已提交
490 491 492

			pst = (struct pst_s *) p;

493
			for (j = 0; j < psb->numpst; j++) {
L
Linus Torvalds 已提交
494 495 496
				pst = (struct pst_s *) p;
				number_scales = pst->numpstates;

497 498 499 500 501
				if ((etuple == pst->cpuid) &&
				    check_fsb(pst->fsbspeed) &&
				    (maxfid == pst->maxfid) &&
				    (startvid == pst->startvid)) {
					print_pst_entry(pst, j);
502
					p = (char *)pst + sizeof(*pst);
503
					ret = get_ranges(p);
L
Linus Torvalds 已提交
504 505
					return ret;
				} else {
506
					unsigned int k;
507
					p = (char *)pst + sizeof(*pst);
508 509
					for (k = 0; k < number_scales; k++)
						p += 2;
L
Linus Torvalds 已提交
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");
L
Linus Torvalds 已提交
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

			return -EINVAL;
		}
		p++;
	}

	return -ENODEV;
}


/*
 * We use the fact that the bus frequency is somehow
 * a multiple of 100000/3 khz, then we compute sgtc according
 * to this multiple.
 * That way, we match more how AMD thinks all of that work.
 * We will then get the same kind of behaviour already tested under
 * the "well-known" other OS.
 */
533
static int fixup_sgtc(void)
L
Linus Torvalds 已提交
534 535 536 537 538 539 540 541 542 543 544 545 546
{
	unsigned int sgtc;
	unsigned int m;

	m = fsb / 3333;
	if ((m % 10) >= 5)
		m += 5;

	m /= 10;

	sgtc = 100 * m * latency;
	sgtc = sgtc / 3;
	if (sgtc > 0xfffff) {
547
		pr_warn("SGTC too large %d\n", sgtc);
L
Linus Torvalds 已提交
548 549 550 551 552 553 554 555 556 557 558 559
		sgtc = 0xfffff;
	}
	return sgtc;
}

static unsigned int powernow_get(unsigned int cpu)
{
	union msr_fidvidstatus fidvidstatus;
	unsigned int cfid;

	if (cpu)
		return 0;
560
	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
L
Linus Torvalds 已提交
561 562
	cfid = fidvidstatus.bits.CFID;

563
	return fsb * fid_codes[cfid] / 10;
L
Linus Torvalds 已提交
564 565 566
}


567
static int acer_cpufreq_pst(const struct dmi_system_id *d)
L
Linus Torvalds 已提交
568
{
569
	pr_warn("%s laptop with broken PST tables in BIOS detected\n",
570
		d->ident);
571 572
	pr_warn("You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
	pr_warn("cpufreq scaling has been disabled as a result of this\n");
L
Linus Torvalds 已提交
573 574 575 576 577 578 579 580
	return 0;
}

/*
 * Some Athlon laptops have really fucked PST tables.
 * A BIOS update is all that can save them.
 * Mention this, and disable cpufreq.
 */
581
static struct dmi_system_id powernow_dmi_table[] = {
L
Linus Torvalds 已提交
582 583 584 585 586 587 588 589 590 591 592
	{
		.callback = acer_cpufreq_pst,
		.ident = "Acer Aspire",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
			DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
		},
	},
	{ }
};

593
static int powernow_cpu_init(struct cpufreq_policy *policy)
L
Linus Torvalds 已提交
594 595 596 597 598 599 600
{
	union msr_fidvidstatus fidvidstatus;
	int result;

	if (policy->cpu != 0)
		return -ENODEV;

601
	rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
L
Linus Torvalds 已提交
602

603
	recalibrate_cpu_khz();
D
Dave Jones 已提交
604 605

	fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
L
Linus Torvalds 已提交
606
	if (!fsb) {
607
		pr_warn("can not determine bus frequency\n");
L
Linus Torvalds 已提交
608 609
		return -EINVAL;
	}
610
	pr_debug("FSB: %3dMHz\n", fsb/1000);
L
Linus Torvalds 已提交
611 612

	if (dmi_check_system(powernow_dmi_table) || acpi_force) {
613
		pr_info("PSB/PST known to be broken - trying ACPI instead\n");
L
Linus Torvalds 已提交
614 615
		result = powernow_acpi_init();
	} else {
616 617
		result = powernow_decode_bios(fidvidstatus.bits.MFID,
				fidvidstatus.bits.SVID);
L
Linus Torvalds 已提交
618
		if (result) {
619
			pr_info("Trying ACPI perflib\n");
L
Linus Torvalds 已提交
620 621 622 623 624
			maximum_speed = 0;
			minimum_speed = -1;
			latency = 0;
			result = powernow_acpi_init();
			if (result) {
625
				pr_info("ACPI and legacy methods failed\n");
L
Linus Torvalds 已提交
626 627 628 629
			}
		} else {
			/* SGTC use the bus clock as timer */
			latency = fixup_sgtc();
630
			pr_info("SGTC: %d\n", latency);
L
Linus Torvalds 已提交
631 632 633 634 635 636
		}
	}

	if (result)
		return result;

637
	pr_info("Minimum speed %d MHz - Maximum speed %d MHz\n",
638
		minimum_speed/1000, maximum_speed/1000);
L
Linus Torvalds 已提交
639

640 641
	policy->cpuinfo.transition_latency =
		cpufreq_scale(2000000UL, fsb, latency);
L
Linus Torvalds 已提交
642

643
	return cpufreq_table_validate_and_show(policy, powernow_table);
L
Linus Torvalds 已提交
644 645
}

646 647
static int powernow_cpu_exit(struct cpufreq_policy *policy)
{
L
Linus Torvalds 已提交
648 649
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
	if (acpi_processor_perf) {
650
		acpi_processor_unregister_performance(0);
651
		free_cpumask_var(acpi_processor_perf->shared_cpu_map);
L
Linus Torvalds 已提交
652 653 654 655
		kfree(acpi_processor_perf);
	}
#endif

656
	kfree(powernow_table);
L
Linus Torvalds 已提交
657 658 659
	return 0;
}

660
static struct cpufreq_driver powernow_driver = {
661
	.verify		= cpufreq_generic_frequency_table_verify,
662
	.target_index	= powernow_target,
663 664 665 666 667 668 669
	.get		= powernow_get,
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
	.bios_limit	= acpi_processor_get_bios_limit,
#endif
	.init		= powernow_cpu_init,
	.exit		= powernow_cpu_exit,
	.name		= "powernow-k7",
670
	.attr		= cpufreq_generic_attr,
L
Linus Torvalds 已提交
671 672
};

673
static int __init powernow_init(void)
L
Linus Torvalds 已提交
674
{
675
	if (check_powernow() == 0)
L
Linus Torvalds 已提交
676 677 678 679 680
		return -ENODEV;
	return cpufreq_register_driver(&powernow_driver);
}


681
static void __exit powernow_exit(void)
L
Linus Torvalds 已提交
682 683 684 685 686 687 688
{
	cpufreq_unregister_driver(&powernow_driver);
}

module_param(acpi_force,  int, 0444);
MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");

689
MODULE_AUTHOR("Dave Jones");
690 691
MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
MODULE_LICENSE("GPL");
L
Linus Torvalds 已提交
692 693 694 695

late_initcall(powernow_init);
module_exit(powernow_exit);