[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *   (c) 2003-2012 Advanced Micro Devices, Inc.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Your use of this code is subject to the terms and conditions of the
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  GNU general public license version 2. See "COPYING" or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  http://www.gnu.org/licenses/gpl.html
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  Maintainer:
829c4bcddaa62e2b9fd2ba85668f6718b0b43f0e3Andreas Herrmann *  Andreas Herrmann <herrmann.der.user@googlemail.com>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Based on the powernow-k7.c module written by Dave Jones.
11f4432c5caec5fa95ea7eefd00f8e6cee17e2e023Dave Jones *  (C) 2003 Dave Jones on behalf of SuSE Labs
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  (C) 2004 Dominik Brodowski <linux@brodo.de>
13a2531293dbb7608fa672ff28efe3ab4027917a2fPavel Machek *  (C) 2004 Pavel Machek <pavel@ucw.cz>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Licensed under the terms of the GNU GPL License version 2.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Based upon datasheets & sample CPUs kindly provided by AMD.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Valuable input gratefully received from Dave Jones, Pavel Machek,
181f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones *  Dominik Brodowski, Jacob Shin, and others.
19065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones *  Originally developed by Paul Devriendt.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
21b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  Processor information obtained from Chapter 9 (Power and Thermal
22b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  Management) of the "BIOS and Kernel Developer's Guide (BKDG) for
23b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  the AMD Athlon 64 and AMD Opteron Processors" and section "2.x
24b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  Power Management" in BKDGs for newer AMD CPU families.
25b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *
26b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  Tables for specific CPUs can be inferred from AMD's processor
27b2bd68e1d5568a3911e991fc71e083f439886d8cAndreas Herrmann *  power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf)
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
39065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones#include <linux/cpumask.h>
400e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones#include <linux/io.h>
410e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones#include <linux/delay.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/msr.h>
44fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen#include <asm/cpu_device_id.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/acpi.h>
4714cc3e2b633bb64063698980974df4535368e98fIngo Molnar#include <linux/mutex.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/processor.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
50c5829cd07ec4c08daa7ff91c821af9b2ac7748dfMark Langsdorf#define VERSION "version 2.20.00"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "powernow-k8.h"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* serialize freq changes  */
5414cc3e2b633bb64063698980974df4535368e98fIngo Molnarstatic DEFINE_MUTEX(fidvid_mutex);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
562c6b8c030cfca334c3d700ee504036c585c4c6a3travis@sgi.comstatic DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58a2fed573f065e526bfd5cbf26e5491973d9e9aaaMark Langsdorfstatic struct cpufreq_driver cpufreq_amd64_driver;
59a2fed573f065e526bfd5cbf26e5491973d9e9aaaMark Langsdorf
60065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones#ifndef CONFIG_SMP
617ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russellstatic inline const struct cpumask *cpu_core_mask(int cpu)
627ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russell{
637ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russell	return cpumask_of(0);
647ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russell}
65065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones#endif
66065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return a frequency in MHz, given an input fid */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 find_freq_from_fid(u32 fid)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 800 + (fid * 100);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return a frequency in KHz, given an input fid */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 find_khz_freq_from_fid(u32 fid)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1000 * find_freq_from_fid(fid);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return the vco fid for an input fid
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Each "low" fid has corresponding "high" fid, and you can get to "low" fids
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only from corresponding high fids. This returns "high" fid corresponding to
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "low" one.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 convert_fid_to_vco_fid(u32 fid)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8732ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones	if (fid < HI_FID_TABLE_BOTTOM)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 8 + (2 * fid);
8932ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones	else
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return fid;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return 1 if the pending bit is set. Unless we just instructed the processor
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to transition to a new state, seeing this bit set is really bad news.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pending_bit_stuck(void)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lo, hi;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rdmsr(MSR_FIDVID_STATUS, lo, hi);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the global current fid / vid values from the status msr.
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 on error.
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int query_current_values_with_pending_wait(struct powernow_k8_data *data)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lo, hi;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 i = 0;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1147153d9612fe5cefc29f9f17d7a6b9f0dcd07b20eDave Jones	do {
1150213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones		if (i++ > 10000) {
1162d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski			pr_debug("detected change pending stuck\n");
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rdmsr(MSR_FIDVID_STATUS, lo, hi);
1207153d9612fe5cefc29f9f17d7a6b9f0dcd07b20eDave Jones	} while (lo & MSR_S_LO_CHANGE_PENDING);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->currvid = hi & MSR_S_HI_CURRENT_VID;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->currfid = lo & MSR_S_LO_CURRENT_FID;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the isochronous relief time */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void count_off_irt(struct powernow_k8_data *data)
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay((1 << data->irt) * 10);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13527b46d7661dc720224813eb4f452e424f1bf3a9aSimon Arlott/* the voltage stabilization time */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void count_off_vst(struct powernow_k8_data *data)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(data->vstable * VST_UNITS_20US);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* need to init the control msr to a safe value (for each cpu) */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fidvid_msr_init(void)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lo, hi;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 fid, vid;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rdmsr(MSR_FIDVID_STATUS, lo, hi);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vid = hi & MSR_S_HI_CURRENT_VID;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fid = lo & MSR_S_LO_CURRENT_FID;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lo = fid | (vid << MSR_C_LO_VID_SHIFT);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hi = MSR_C_HI_STP_GNT_BENIGN;
1532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wrmsr(MSR_FIDVID_CTL, lo, hi);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* write the new fid value along with the other control fields to the msr */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_new_fid(struct powernow_k8_data *data, u32 fid)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lo;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 savevid = data->currvid;
1620213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	u32 i = 0;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
165e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("internal error - overflow on fid write\n");
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1690e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo = fid;
1700e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
1710e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo |= MSR_C_LO_INIT_FID_VID;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1732d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fid, lo, data->plllock * PLL_LOCK_CONVERSION);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1760213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	do {
1770213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones		wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
1780213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones		if (i++ > 100) {
179e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err("Hardware error - pending bit very stuck - no further pstate changes possible\n");
18063172cb3d5ef762dcb60a292bc7f016b85cf6e1fChris Wright			return 1;
18132ee8c3e470d86588b51dc42ed01e85c5fa0f180Dave Jones		}
1820213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	} while (query_current_values_with_pending_wait(data));
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count_off_irt(data);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savevid != data->currvid) {
187e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("vid change on fid trans, old 0x%x, new 0x%x\n",
188e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		       savevid, data->currvid);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fid != data->currfid) {
193e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("fid trans failed, fid 0x%x, curr 0x%x\n", fid,
1940e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			data->currfid);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Write a new vid to the hardware */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_new_vid(struct powernow_k8_data *data, u32 vid)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 lo;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 savefid = data->currfid;
2060213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	int i = 0;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
209e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("internal error - overflow on vid write\n");
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2130e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo = data->currfid;
2140e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo |= (vid << MSR_C_LO_VID_SHIFT);
2150e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	lo |= MSR_C_LO_INIT_FID_VID;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2172d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vid, lo, STOP_GRANT_5NS);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2200213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	do {
2210213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones		wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
2226df8900676c3f5c133328332fb8ad889fd0cc9e3Dave Jones		if (i++ > 100) {
223e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err("internal error - pending bit very stuck - no further pstate changes possible\n");
2246df8900676c3f5c133328332fb8ad889fd0cc9e3Dave Jones			return 1;
2256df8900676c3f5c133328332fb8ad889fd0cc9e3Dave Jones		}
2260213df74315bbab9ccaa73146f3e11972ea6de46Dave Jones	} while (query_current_values_with_pending_wait(data));
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savefid != data->currfid) {
229e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("fid changed on vid trans, old 0x%x new 0x%x\n",
230e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			savefid, data->currfid);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vid != data->currvid) {
235e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("vid trans failed, vid 0x%x, curr 0x%x\n",
2360e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				vid, data->currvid);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reduce the vid by the max of step or reqvid.
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Decreasing vid codes represent increasing voltages:
246841e40b380a70933e8dc1184e0f9ba1c6cac48afDave Jones * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2480e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int decrease_vid_code_by_step(struct powernow_k8_data *data,
2490e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		u32 reqvid, u32 step)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->currvid - reqvid) > step)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reqvid = data->currvid - step;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (write_new_vid(data, reqvid))
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count_off_vst(data);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
2630e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int transition_fid_vid(struct powernow_k8_data *data,
2640e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		u32 reqfid, u32 reqvid)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
266a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	if (core_voltage_pre_transition(data, reqvid, reqfid))
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (core_frequency_transition(data, reqfid))
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (core_voltage_post_transition(data, reqvid))
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data))
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
279e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n",
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				smp_processor_id(),
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				reqfid, reqvid, data->currfid, data->currvid);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2852d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_processor_id(), data->currfid, data->currvid);
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Phase 1 - core voltage transition ... setup voltage */
2920e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int core_voltage_pre_transition(struct powernow_k8_data *data,
293a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf		u32 reqvid, u32 reqfid)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rvosteps = data->rvo;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 savefid = data->currfid;
297a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	u32 maxvid, lo, rvomult = 1;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_processor_id(),
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid, reqvid, data->rvo);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
303a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP))
304a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf		rvomult = 2;
305a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	rvosteps *= rvomult;
306065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones	rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
307065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones	maxvid = 0x1f & (maxvid >> 16);
3082d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("ph1 maxvid=0x%x\n", maxvid);
309065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones	if (reqvid < maxvid) /* lower numbers are higher voltages */
310065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones		reqvid = maxvid;
311065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (data->currvid > reqvid) {
3132d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("ph1: curr 0x%x, req vid 0x%x\n",
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->currvid, reqvid);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (decrease_vid_code_by_step(data, reqvid, data->vidmvs))
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
319a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	while ((rvosteps > 0) &&
320a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf			((rvomult * data->rvo + data->currvid) > reqvid)) {
321065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones		if (data->currvid == maxvid) {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rvosteps = 0;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3242d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski			pr_debug("ph1: changing vid for rvo, req 0x%x\n",
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->currvid - 1);
3260e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			if (decrease_vid_code_by_step(data, data->currvid-1, 1))
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rvosteps--;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data))
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savefid != data->currfid) {
336e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("ph1 err, currfid changed 0x%x\n", data->currfid);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3402d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n",
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Phase 2 - core frequency transition */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3490e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	u32 vcoreqfid, vcocurrfid, vcofiddiff;
3500e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	u32 fid_interval, savevid = data->currvid;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->currfid == reqfid) {
353e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("ph2 null fid transition 0x%x\n", data->currfid);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
357e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_processor_id(),
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid, reqfid);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vcoreqfid = convert_fid_to_vco_fid(reqfid);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vcocurrfid = convert_fid_to_vco_fid(data->currfid);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    : vcoreqfid - vcocurrfid;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
366a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf	if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP))
367a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf		vcofiddiff = 0;
368a2e1b4c31257c07f148a89eb7eea7ca959fd0642Mark Langsdorf
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (vcofiddiff > 2) {
370019a61b99338d0ac05de25317b85da88e7ec4b35Langsdorf, Mark		(data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2);
371019a61b99338d0ac05de25317b85da88e7ec4b35Langsdorf, Mark
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reqfid > data->currfid) {
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (data->currfid > LO_FID_TABLE_TOP) {
3740e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				if (write_new_fid(data,
3750e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones						data->currfid + fid_interval))
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 1;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (write_new_fid
3790e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				    (data,
3800e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				     2 + convert_fid_to_vco_fid(data->currfid)))
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 1;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
384019a61b99338d0ac05de25317b85da88e7ec4b35Langsdorf, Mark			if (write_new_fid(data, data->currfid - fid_interval))
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vcocurrfid = convert_fid_to_vco_fid(data->currfid);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    : vcoreqfid - vcocurrfid;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (write_new_fid(data, reqfid))
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data))
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->currfid != reqfid) {
400e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n",
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->currfid, reqfid);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savevid != data->currvid) {
406e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("ph2: vid changed, save 0x%x, curr 0x%x\n",
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			savevid, data->currvid);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4112d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n",
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Phase 3 - core voltage transition flow ... jump to the final vid. */
4180e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int core_voltage_post_transition(struct powernow_k8_data *data,
4190e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		u32 reqvid)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 savefid = data->currfid;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 savereqvid = reqvid;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4242d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_processor_id(),
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reqvid != data->currvid) {
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (write_new_vid(data, reqvid))
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (savefid != data->currfid) {
433e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err("ph3: bad fid change, save 0x%x, curr 0x%x\n",
434e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				savefid, data->currfid);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->currvid != reqvid) {
439e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err("ph3: failed vid transition\n, req 0x%x, curr 0x%x",
440e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				reqvid, data->currvid);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data))
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savereqvid != data->currvid) {
4492d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("ph3 failed, currvid 0x%x\n", data->currvid);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (savefid != data->currfid) {
4542d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("ph3 failed, currfid changed 0x%x\n",
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->currfid);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4592d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n",
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->currfid, data->currvid);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
465fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleenstatic const struct x86_cpu_id powernow_k8_ids[] = {
466fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen	/* IO based frequency switching */
467fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen	{ X86_VENDOR_AMD, 0xf },
468fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen	{}
469fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen};
470fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi KleenMODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);
471fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen
4721ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russellstatic void check_supported_cpu(void *_rc)
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 eax, ebx, ecx, edx;
4751ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	int *rc = _rc;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4771ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	*rc = -ENODEV;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
4802c906ae67b5b2fc3585230b16406400a363b42e4Dave Jones
4811f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
4821f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
48399fbe1ac217e8b9d4141504e879327cb4e42d4ffDave Jones		    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
484e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_info("Processor cpuid %x not supported\n", eax);
4851ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell			return;
4861f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		}
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
4891f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
490e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_info("No frequency change capabilities detected\n");
4911ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell			return;
4921f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
4950e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if ((edx & P_STATE_TRANSITION_CAPABLE)
4960e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			!= P_STATE_TRANSITION_CAPABLE) {
497e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_info("Power state transitions not supported\n");
4981ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell			return;
4991f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		}
500e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett		*rc = 0;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5040e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
5050e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		u8 maxvid)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int j;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 lastfid = 0xff;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < data->numps; j++) {
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pst[j].vid > LEAST_VID) {
512e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "vid %d invalid : 0x%x\n", j,
513e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				pst[j].vid);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5160e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if (pst[j].vid < data->rvo) {
5170e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			/* vid + rvo >= 0 */
518e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "0 vid exceeded with pstate %d\n", j);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5210e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if (pst[j].vid < maxvid + data->rvo) {
5220e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			/* vid + rvo >= maxvid */
523e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "maxvid exceeded with pstate %d\n", j);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5268aae8284fece2b8fc404ccd40b7a30aa96f317b5Jacob Shin		if (pst[j].fid > MAX_FID) {
527e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "maxfid exceeded with pstate %d\n", j);
5288aae8284fece2b8fc404ccd40b7a30aa96f317b5Jacob Shin			return -ENODEV;
5298aae8284fece2b8fc404ccd40b7a30aa96f317b5Jacob Shin		}
5308aae8284fece2b8fc404ccd40b7a30aa96f317b5Jacob Shin		if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Only first fid is allowed to be in "low" range */
532e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "two low fids - %d : 0x%x\n", j,
533e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				pst[j].fid);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pst[j].fid < lastfid)
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lastfid = pst[j].fid;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lastfid & 1) {
540e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err(FW_BUG "lastfid invalid\n");
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lastfid > LO_FID_TABLE_TOP)
544e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_info(FW_BUG "first fid not from lo freq table\n");
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
549f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckxstatic void invalidate_entry(struct cpufreq_frequency_table *powernow_table,
550f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckx		unsigned int entry)
5510e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones{
552f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckx	powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
5530e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones}
5540e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void print_basics(struct powernow_k8_data *data)
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < data->numps; j++) {
5590e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if (data->powernow_table[j].frequency !=
5600e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				CPUFREQ_ENTRY_INVALID) {
561e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_info("fid 0x%x (%d MHz), vid 0x%x\n",
562e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				data->powernow_table[j].driver_data & 0xff,
563e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				data->powernow_table[j].frequency/1000,
564e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				data->powernow_table[j].driver_data >> 8);
5651f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->batps)
568e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_info("Only %d pstates on battery\n", data->batps);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5710e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int fill_powernow_table(struct powernow_k8_data *data,
5720e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		struct pst_s *pst, u8 maxvid)
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpufreq_frequency_table *powernow_table;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int j;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5770e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	if (data->batps) {
5780e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		/* use ACPI support to get full speed on mains power */
579e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_warn("Only %d pstates usable (use ACPI driver for full range\n",
580e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			data->batps);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->numps = data->batps;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5840e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	for (j = 1; j < data->numps; j++) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pst[j-1].fid >= pst[j].fid) {
586e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err("PST out of sequence\n");
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (data->numps < 2) {
592e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("no p states to transition\n");
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (check_pst_table(data, pst, maxvid))
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59971508a1f4f2286eea728a5994f1fb14b77340b47Viresh Kumar	powernow_table = kzalloc((sizeof(*powernow_table)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		* (data->numps + 1)), GFP_KERNEL);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!powernow_table) {
602e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("powernow_table memory alloc failure\n");
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < data->numps; j++) {
6070e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		int freq;
6085070158804b5339c71809f5e673cea1cfacd804dViresh Kumar		powernow_table[j].driver_data = pst[j].fid; /* lower 8 bits */
6095070158804b5339c71809f5e673cea1cfacd804dViresh Kumar		powernow_table[j].driver_data |= (pst[j].vid << 8); /* upper 8 bits */
6100e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		freq = find_khz_freq_from_fid(pst[j].fid);
6110e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		powernow_table[j].frequency = freq;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
6145070158804b5339c71809f5e673cea1cfacd804dViresh Kumar	powernow_table[data->numps].driver_data = 0;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data)) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(powernow_table);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6212d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->powernow_table = powernow_table;
6237ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russell	if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
6242e4976206396274cf66590328c6913811c271495Mark Langsdorf		print_basics(data);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < data->numps; j++)
6270e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if ((pst[j].fid == data->currfid) &&
6280e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		    (pst[j].vid == data->currvid))
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6312d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("currfid/vid do not match PST, ignoring\n");
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Find and validate the PSB/PST table in BIOS. */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int find_psb_table(struct powernow_k8_data *data)
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct psb_s *psb;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mvs;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 maxvid;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 cpst = 0;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 thiscpuid;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0xc0000; i < 0xffff0; i += 0x10) {
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Scan BIOS looking for the signature. */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* It can not be at ffff0 - it is too big. */
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psb = phys_to_virt(i);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("found PSB header at 0x%p\n", psb);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6552d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("table vers: 0x%x\n", psb->tableversion);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (psb->tableversion != PSB_VERSION_1_4) {
657e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "PSB table is not v1.4\n");
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6612d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("flags: 0x%x\n", psb->flags1);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (psb->flags1) {
663e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "unknown flags\n");
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vstable = psb->vstable;
6682d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("voltage stabilization time: %d(*20us)\n",
6690e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				data->vstable);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6712d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("flags2: 0x%x\n", psb->flags2);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->rvo = psb->flags2 & 3;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->irt = ((psb->flags2) >> 2) & 3;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mvs = ((psb->flags2) >> 4) & 3;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->vidmvs = 1 << mvs;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->batps = ((psb->flags2) >> 6) & 3;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6782d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("ramp voltage offset: %d\n", data->rvo);
6792d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("isochronous relief time: %d\n", data->irt);
6802d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6822d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("numpst: 0x%x\n", psb->num_tables);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpst = psb->num_tables;
6840e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if ((psb->cpuid == 0x00000fc0) ||
6850e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		    (psb->cpuid == 0x00000fe0)) {
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
6870e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			if ((thiscpuid == 0x00000fc0) ||
6880e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			    (thiscpuid == 0x00000fe0))
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpst = 1;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cpst != 1) {
692e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "numpst must be 1\n");
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->plllock = psb->plllocktime;
6972d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
6982d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("maxfid: 0x%x\n", psb->maxfid);
6992d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("maxvid: 0x%x\n", psb->maxvid);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		maxvid = psb->maxvid;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->numps = psb->numps;
7032d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("numpstates: 0x%x\n", data->numps);
7040e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		return fill_powernow_table(data,
7050e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				(struct pst_s *)(psb+1), maxvid);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If you see this message, complain to BIOS manufacturer. If
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * he tells you "we do not support Linux" or some similar
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * nonsense, remember that Windows 2000 uses the same legacy
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * mechanism that the old Linux PSB driver uses. Tell them it
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * is broken with Windows 2000.
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The reference to the AMD documentation is chapter 9 in the
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * BIOS and Kernel Developer's Guide, which is available on
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * www.amd.com
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
718e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_err(FW_BUG "No PSB or ACPI _PSS objects\n");
719e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_err("Make sure that your BIOS is up to date and Cool'N'Quiet support is enabled in BIOS setup\n");
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7230e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
7240e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		unsigned int index)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
726439913fffd39374c3737186b22d2d56c3a0ae526Lin Ming	u64 control;
7270e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones
728e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	if (!data->acpi_data.state_count)
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
73121335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	control = data->acpi_data.states[index].control;
73221335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->irt = (control >> IRT_SHIFT) & IRT_MASK;
73321335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->rvo = (control >> RVO_SHIFT) & RVO_MASK;
73421335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->exttype = (control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
73521335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK;
73621335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->vidmvs = 1 << ((control >> MVS_SHIFT) & MVS_MASK);
73721335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques	data->vstable = (control >> VST_SHIFT) & VST_MASK;
73821335d021464c3ba3c20fc7207ffe2bdd2458568Luis Henriques}
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpufreq_frequency_table *powernow_table;
7432fdf66b491ac706657946442789ec644cc317e1aRusty Russell	int ret_val = -ENODEV;
744439913fffd39374c3737186b22d2d56c3a0ae526Lin Ming	u64 control, status;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
746f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
7472d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("register performance failed: bad ACPI data\n");
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* verify the data contained in the ACPI structures */
752f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	if (data->acpi_data.state_count <= 1) {
7532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("No ACPI P-States\n");
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7572c701b10283b58937201004276319ef9d9051b5dDave Jones	control = data->acpi_data.control_register.space_id;
7582c701b10283b58937201004276319ef9d9051b5dDave Jones	status = data->acpi_data.status_register.space_id;
7592c701b10283b58937201004276319ef9d9051b5dDave Jones
7602c701b10283b58937201004276319ef9d9051b5dDave Jones	if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
7612c701b10283b58937201004276319ef9d9051b5dDave Jones	    (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
7622d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("Invalid control/status registers (%llx - %llx)\n",
7632c701b10283b58937201004276319ef9d9051b5dDave Jones			control, status);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* fill in data->powernow_table */
76871508a1f4f2286eea728a5994f1fb14b77340b47Viresh Kumar	powernow_table = kzalloc((sizeof(*powernow_table)
769f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds		* (data->acpi_data.state_count + 1)), GFP_KERNEL);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!powernow_table) {
7712d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("powernow_table memory alloc failure\n");
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
775db39d5529d347de5e2eec1a72d67fcfacae6c5a2Mark Langsdorf	/* fill in data */
776db39d5529d347de5e2eec1a72d67fcfacae6c5a2Mark Langsdorf	data->numps = data->acpi_data.state_count;
777db39d5529d347de5e2eec1a72d67fcfacae6c5a2Mark Langsdorf	powernow_k8_acpi_pst_values(data, 0);
778db39d5529d347de5e2eec1a72d67fcfacae6c5a2Mark Langsdorf
779e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	ret_val = fill_powernow_table_fidvid(data, powernow_table);
7801f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	if (ret_val)
7811f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones		goto err_out_mem;
7821f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
7830e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	powernow_table[data->acpi_data.state_count].frequency =
7840e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		CPUFREQ_TABLE_END;
7851f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	data->powernow_table = powernow_table;
7861f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
7877ad728f98162cb1af06a85b2a5fc422dddd4fb78Rusty Russell	if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
7882e4976206396274cf66590328c6913811c271495Mark Langsdorf		print_basics(data);
7891f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
7901f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	/* notify BIOS that we exist */
7911f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	acpi_processor_notify_smm(THIS_MODULE);
7921f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
793eaa958402ea40851097d051f52ba1bb7a885efe9Yinghai Lu	if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) {
794e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("unable to alloc powernow_k8_data cpumask\n");
7952fdf66b491ac706657946442789ec644cc317e1aRusty Russell		ret_val = -ENOMEM;
7962fdf66b491ac706657946442789ec644cc317e1aRusty Russell		goto err_out_mem;
7972fdf66b491ac706657946442789ec644cc317e1aRusty Russell	}
7982fdf66b491ac706657946442789ec644cc317e1aRusty Russell
7991f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	return 0;
8001f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
8011f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Joneserr_out_mem:
8021f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	kfree(powernow_table);
8031f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
8041f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Joneserr_out:
805f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
8061f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
8070e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	/* data->acpi_data.state_count informs us at ->exit()
8080e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones	 * whether ACPI was used */
809f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	data->acpi_data.state_count = 0;
8101f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
8112fdf66b491ac706657946442789ec644cc317e1aRusty Russell	return ret_val;
8121f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones}
8131f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
8140e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int fill_powernow_table_fidvid(struct powernow_k8_data *data,
8150e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		struct cpufreq_frequency_table *powernow_table)
8161f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones{
8171f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	int i;
8180e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones
819f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	for (i = 0; i < data->acpi_data.state_count; i++) {
820094ce7fde493a1196b8152f9f9e73c20e24a2b05Dave Jones		u32 fid;
821094ce7fde493a1196b8152f9f9e73c20e24a2b05Dave Jones		u32 vid;
8220e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		u32 freq, index;
823439913fffd39374c3737186b22d2d56c3a0ae526Lin Ming		u64 status, control;
824094ce7fde493a1196b8152f9f9e73c20e24a2b05Dave Jones
825094ce7fde493a1196b8152f9f9e73c20e24a2b05Dave Jones		if (data->exttype) {
8260e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			status =  data->acpi_data.states[i].status;
8270e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			fid = status & EXT_FID_MASK;
8280e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			vid = (status >> VID_SHIFT) & EXT_VID_MASK;
829841e40b380a70933e8dc1184e0f9ba1c6cac48afDave Jones		} else {
8300e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			control =  data->acpi_data.states[i].control;
8310e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			fid = control & FID_MASK;
8320e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones			vid = (control >> VID_SHIFT) & VID_MASK;
833841e40b380a70933e8dc1184e0f9ba1c6cac48afDave Jones		}
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8352d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8370e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		index = fid | (vid<<8);
8385070158804b5339c71809f5e673cea1cfacd804dViresh Kumar		powernow_table[i].driver_data = index;
8390e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones
8400e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		freq = find_khz_freq_from_fid(fid);
8410e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		powernow_table[i].frequency = freq;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* verify frequency is OK */
8440e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
8452d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski			pr_debug("invalid freq %u kHz, ignoring\n", freq);
846f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckx			invalidate_entry(powernow_table, i);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8500e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		/* verify voltage is OK -
8510e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		 * BIOSs are using "off" to indicate invalid */
852841e40b380a70933e8dc1184e0f9ba1c6cac48afDave Jones		if (vid == VID_OFF) {
8532d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski			pr_debug("invalid vid %u, ignoring\n", vid);
854f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckx			invalidate_entry(powernow_table, i);
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8580e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
859e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_info("invalid freq entries %u kHz vs. %u kHz\n",
860e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis				freq, (unsigned int)
8610e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				(data->acpi_data.states[i].core_frequency
8620e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				 * 1000));
863f0adb134d8dc9993a9998dc50845ec4f6ff4fadcKurt Roeckx			invalidate_entry(powernow_table, i);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
872f607e3a03c90e8c050cb0c12ec9967c2925cc812Linus Torvalds	if (data->acpi_data.state_count)
8730e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		acpi_processor_unregister_performance(&data->acpi_data,
8740e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones				data->cpu);
8752fdf66b491ac706657946442789ec644cc317e1aRusty Russell	free_cpumask_var(data->acpi_data.shared_cpu_map);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
878732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorfstatic int get_transition_latency(struct powernow_k8_data *data)
879732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf{
880732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	int max_latency = 0;
881732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	int i;
882732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	for (i = 0; i < data->acpi_data.state_count; i++) {
883732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		int cur_latency = data->acpi_data.states[i].transition_latency
884732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf			+ data->acpi_data.states[i].bus_master_latency;
885732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		if (cur_latency > max_latency)
886732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf			max_latency = cur_latency;
887732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	}
88886e13684aa77f07c77db352f437d9e53a84dde90Thomas Renninger	if (max_latency == 0) {
889e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err(FW_WARN "Invalid zero transition latency\n");
89086e13684aa77f07c77db352f437d9e53a84dde90Thomas Renninger		max_latency = 1;
89186e13684aa77f07c77db352f437d9e53a84dde90Thomas Renninger	}
892732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	/* value in usecs, needs to be in nanoseconds */
893732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	return 1000 * max_latency;
894732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf}
895732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Take a frequency, and issue the fid/vid transition command */
8970e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic int transition_frequency_fidvid(struct powernow_k8_data *data,
8980e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jones		unsigned int index)
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
900b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2Viresh Kumar	struct cpufreq_policy *policy;
9011f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	u32 fid = 0;
9021f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	u32 vid = 0;
903b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2Viresh Kumar	int res;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpufreq_freqs freqs;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9062d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	/* fid/vid correctness check for k8 */
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* fid are the lower 8 bits of the index we stored into
9101f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	 * the cpufreq frequency table in find_psb_table, vid
9111f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	 * are the upper 8 bits.
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9135070158804b5339c71809f5e673cea1cfacd804dViresh Kumar	fid = data->powernow_table[index].driver_data & 0xFF;
9145070158804b5339c71809f5e673cea1cfacd804dViresh Kumar	vid = (data->powernow_table[index].driver_data & 0xFF00) >> 8;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9162d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (query_current_values_with_pending_wait(data))
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((data->currvid == vid) && (data->currfid == fid)) {
9222d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski		pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n",
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fid, vid);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9272d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n",
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		smp_processor_id(), fid, vid);
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freqs.old = find_khz_freq_from_fid(data->currfid);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	freqs.new = find_khz_freq_from_fid(fid);
9311f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
932b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2Viresh Kumar	policy = cpufreq_cpu_get(smp_processor_id());
933b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2Viresh Kumar	cpufreq_cpu_put(policy);
934b43a7ffbf33be7e4d3b10b7714ee663ea2c52fe2Viresh Kumar
9358fec051eea736ec1d8060a2c8766bf3a6b32c3d2Viresh Kumar	cpufreq_freq_transition_begin(policy, &freqs);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	res = transition_fid_vid(data, fid, vid);
9378fec051eea736ec1d8060a2c8766bf3a6b32c3d2Viresh Kumar	cpufreq_freq_transition_end(policy, &freqs, res);
9381f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
9391f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	return res;
9401f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones}
9411f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones
9426889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heostruct powernowk8_target_arg {
9436889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo	struct cpufreq_policy		*pol;
9449c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar	unsigned			newstate;
9456889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo};
9466889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo
9476889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heostatic long powernowk8_target_fn(void *arg)
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9496889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo	struct powernowk8_target_arg *pta = arg;
9506889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo	struct cpufreq_policy *pol = pta->pol;
9519c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar	unsigned newstate = pta->newstate;
9522c6b8c030cfca334c3d700ee504036c585c4c6a3travis@sgi.com	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
9539180053cacfec4aa233a6cabf1256960e75b0abdAdrian Bunk	u32 checkfid;
9549180053cacfec4aa233a6cabf1256960e75b0abdAdrian Bunk	u32 checkvid;
9556889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo	int ret;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9574211a30349e8d2b724cfb4ce2584604f5e59c299Jacob Shin	if (!data)
9584211a30349e8d2b724cfb4ce2584604f5e59c299Jacob Shin		return -EINVAL;
9594211a30349e8d2b724cfb4ce2584604f5e59c299Jacob Shin
9609180053cacfec4aa233a6cabf1256960e75b0abdAdrian Bunk	checkfid = data->currfid;
9619180053cacfec4aa233a6cabf1256960e75b0abdAdrian Bunk	checkvid = data->currvid;
9629180053cacfec4aa233a6cabf1256960e75b0abdAdrian Bunk
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pending_bit_stuck()) {
964e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("failing targ, change pending bit set\n");
9656889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo		return -EIO;
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9689c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar	pr_debug("targ: cpu %d, %d kHz, min %d, max %d\n",
9699c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar		pol->cpu, data->powernow_table[newstate].frequency, pol->min,
9709c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar		pol->max);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
97283844510ec9dc89a676e71d3cc28289905c2caecDave Jones	if (query_current_values_with_pending_wait(data))
9736889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo		return -EIO;
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
975e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
976e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		data->currfid, data->currvid);
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
978e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	if ((checkvid != data->currvid) ||
979e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	    (checkfid != data->currfid)) {
980e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_info("error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
981e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett		       checkfid, data->currfid,
982e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett		       checkvid, data->currvid);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98514cc3e2b633bb64063698980974df4535368e98fIngo Molnar	mutex_lock(&fidvid_mutex);
986065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	powernow_k8_acpi_pst_values(data, newstate);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
989e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	ret = transition_frequency_fidvid(data, newstate);
990e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett
9911f729e0660f974cec1f0f7f4fba03ea4c2c4b9a9Dave Jones	if (ret) {
992e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("transition frequency failed\n");
99314cc3e2b633bb64063698980974df4535368e98fIngo Molnar		mutex_unlock(&fidvid_mutex);
9946889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo		return 1;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
99614cc3e2b633bb64063698980974df4535368e98fIngo Molnar	mutex_unlock(&fidvid_mutex);
997065b807ca1f5bdbeb081e3cf75ac8de9be8ac212Dave Jones
998e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	pol->cur = find_khz_freq_from_fid(data->currfid);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10006889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo	return 0;
10016889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo}
10026889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo
10036889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo/* Driver entry point to switch to the target frequency */
10049c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumarstatic int powernowk8_target(struct cpufreq_policy *pol, unsigned index)
10056889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo{
10069c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar	struct powernowk8_target_arg pta = { .pol = pol, .newstate = index };
10076889125b8b4e09c5e53e6ecab3433bed1ce198c9Tejun Heo
1008e4df1cbcc1f329e53a1fff7450b2229e0addff20Andreas Herrmann	return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russellstruct init_on_cpu {
10121ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	struct powernow_k8_data *data;
10131ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	int rc;
10141ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell};
10151ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
10162760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic void powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
10171ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell{
10181ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	struct init_on_cpu *init_on_cpu = _init_on_cpu;
10191ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
10201ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	if (pending_bit_stuck()) {
1021e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("failing init, change pending bit set\n");
10221ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell		init_on_cpu->rc = -ENODEV;
10231ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell		return;
10241ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	}
10251ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
10261ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	if (query_current_values_with_pending_wait(init_on_cpu->data)) {
10271ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell		init_on_cpu->rc = -ENODEV;
10281ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell		return;
10291ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	}
10301ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
1031e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	fidvid_msr_init();
10321ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
10331ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	init_on_cpu->rc = 0;
10341ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell}
10351ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
1036e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis#define MISSING_PSS_MSG \
1037e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	FW_BUG "No compatible ACPI _PSS objects found.\n" \
1038e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	FW_BUG "First, make sure Cool'N'Quiet is enabled in the BIOS.\n" \
1039e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	FW_BUG "If that doesn't help, try upgrading your BIOS.\n"
104056835e6cc053c29bf1a15a07dbeb78f219a15214Borislav Petkov
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* per CPU init entry point to the driver */
10422760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic int powernowk8_cpu_init(struct cpufreq_policy *pol)
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct powernow_k8_data *data;
10451ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	struct init_on_cpu init_on_cpu;
1046c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat	int rc, cpu;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10481ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
10491ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	if (rc)
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1052d5b73cd870e2b049ef566aec2791dbf5fd26a7ecViresh Kumar	data = kzalloc(sizeof(*data), GFP_KERNEL);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!data) {
1054e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err("unable to alloc powernow_k8_data");
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data->cpu = pol->cpu;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1060a0abd520fd69295f4a3735e29a9448a32e101d47Rusty Russell	if (powernow_k8_cpu_init_acpi(data)) {
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
10620d2eb44f631d9d0a826efa3156f157477fdaecf4Lucas De Marchi		 * Use the PSB BIOS structure. This is only available on
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * an UP version, and is deprecated by AMD.
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10659ed059e1551bf36092215b965838502ac21f42e4Randy Dunlap		if (num_online_cpus() != 1) {
1066e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err_once(MISSING_PSS_MSG);
10670cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Jones			goto err_out;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pol->cpu != 0) {
1070e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis			pr_err(FW_BUG "No ACPI _PSS objects for CPU other than CPU0. Complain to your BIOS vendor.\n");
10710cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Jones			goto err_out;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = find_psb_table(data);
10740cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Jones		if (rc)
10750cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Jones			goto err_out;
10760cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Jones
1077732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		/* Take a crude guess here.
1078732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		 * That guess was in microseconds, so multiply with 1000 */
1079732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		pol->cpuinfo.transition_latency = (
1080732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf			 ((data->rvo + 8) * data->vstable * VST_UNITS_20US) +
1081732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf			 ((1 << data->irt) * 30)) * 1000;
1082732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf	} else /* ACPI _PSS objects available */
1083732553e567c2700ba5b9bccc6ec885c75779a94bMark Langsdorf		pol->cpuinfo.transition_latency = get_transition_latency(data);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* only run on specific CPU from here on */
10861ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	init_on_cpu.data = data;
10871ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	smp_call_function_single(data->cpu, powernowk8_cpu_init_on_cpu,
10881ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell				 &init_on_cpu, 1);
10891ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	rc = init_on_cpu.rc;
10901ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	if (rc != 0)
10911ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell		goto err_out_exit_acpi;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1093e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu));
1094835481d9bcd65720b473db6b38746a74a3964218Rusty Russell	data->available_cores = pol->cpus;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* min/max the cpu is capable of */
1097b147405aa8e568750bfa99501c7fa831edef47c9Viresh Kumar	if (cpufreq_table_validate_and_show(pol, data->powernow_table)) {
1098e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_err(FW_BUG "invalid powernow_table\n");
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		powernow_k8_cpu_exit_acpi(data);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(data->powernow_table);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(data);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1105e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
1106e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		data->currfid, data->currvid);
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1108c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat	/* Point all the CPUs in this policy to the same data */
1109c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat	for_each_cpu(cpu, pol->cpus)
1110c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat		per_cpu(powernow_data, cpu) = data;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11141ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russellerr_out_exit_acpi:
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	powernow_k8_cpu_exit_acpi(data);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11170cb8bc256093e716d2a0a4a721f36c625a3f7634Dave Joneserr_out:
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1122c0e61cb151f2ff8edd02af23b2bd49f625288124Bill Pembertonstatic int powernowk8_cpu_exit(struct cpufreq_policy *pol)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11242c6b8c030cfca334c3d700ee504036c585c4c6a3travis@sgi.com	struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
1125c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat	int cpu;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!data)
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	powernow_k8_cpu_exit_acpi(data);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data->powernow_table);
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(data);
1134c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat	for_each_cpu(cpu, pol->cpus)
1135c3274763bfc3bf1ececa269ed6e6c4d7ec1c3e5eSrivatsa S. Bhat		per_cpu(powernow_data, cpu) = NULL;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russellstatic void query_values_on_cpu(void *_err)
11411ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell{
11421ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	int *err = _err;
11430a3aee0da4402aa19b66e458038533c896fb80c6Tejun Heo	struct powernow_k8_data *data = __this_cpu_read(powernow_data);
11441ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
11451ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	*err = query_current_values_with_pending_wait(data);
11461ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell}
11471ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell
11480e64a0c982c06a6b8f5e2a7f29eb108fdf257b2fDave Jonesstatic unsigned int powernowk8_get(unsigned int cpu)
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1150e15bc4559b397a611441a135b1f5992f07d0f436Naga Chumbalkar	struct powernow_k8_data *data = per_cpu(powernow_data, cpu);
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int khz = 0;
11521ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	int err;
1153eef5167e5045fa8265b3e72cac9dbc4bc7dd82a6Jacob Shin
1154eef5167e5045fa8265b3e72cac9dbc4bc7dd82a6Jacob Shin	if (!data)
1155557a701c16553b0b691dbb64ef30361115a80f64Thomas Renninger		return 0;
1156eef5167e5045fa8265b3e72cac9dbc4bc7dd82a6Jacob Shin
11571ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	smp_call_function_single(cpu, query_values_on_cpu, &err, true);
11581ff6e97f1d993dff2f9b6f4a9173687370660232Rusty Russell	if (err)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	khz = find_khz_freq_from_fid(data->currfid);
116258389a86df48ff927846df9537ea34d9961b5c44Joachim Deguara
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1164b9111b7b7f46b0ec1ccb451d60ec439b92e4df65Dave Jonesout:
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return khz;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1168221dee285ee38099b82437531bcae9fa9cb64cc4Linus Torvaldsstatic struct cpufreq_driver cpufreq_amd64_driver = {
11697dbf694db6ac7c759599316d50d7050efcbd512aViresh Kumar	.flags		= CPUFREQ_ASYNC_NOTIFICATION,
1170d63bd27fe953daa402a108e141c36dcc59c6931cViresh Kumar	.verify		= cpufreq_generic_frequency_table_verify,
11719c0ebcf78fde0ffa348a95a544c6d3f2dac5af65Viresh Kumar	.target_index	= powernowk8_target,
1172e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger	.bios_limit	= acpi_processor_get_bios_limit,
1173e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger	.init		= powernowk8_cpu_init,
1174ce2650d40dff23f2c6f9718bb3ec63e12c5c7f27Bill Pemberton	.exit		= powernowk8_cpu_exit,
1175e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger	.get		= powernowk8_get,
1176e2f74f355e9e2914483db10c05d70e69e0b7ae04Thomas Renninger	.name		= "powernow-k8",
1177d63bd27fe953daa402a108e141c36dcc59c6931cViresh Kumar	.attr		= cpufreq_generic_attr,
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11804827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkovstatic void __request_acpi_cpufreq(void)
11814827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov{
11824827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	const char *cur_drv, *drv = "acpi-cpufreq";
11834827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov
11844827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	cur_drv = cpufreq_get_current_driver();
11854827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	if (!cur_drv)
11864827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov		goto request;
11874827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov
11884827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv))))
1189e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis		pr_warn("WTF driver: %s\n", cur_drv);
11904827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov
11914827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	return;
11924827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov
11934827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov request:
1194e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_warn("This CPU is not supported anymore, using acpi-cpufreq instead.\n");
11954827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov	request_module(drv);
11964827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov}
11974827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* driver entry point for init */
11992760984f6578d5a462155bb4727766d0c8b68387Paul Gortmakerstatic int powernowk8_init(void)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1201e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	unsigned int i, supported_cpus = 0;
1202c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	int ret;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1204e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	if (static_cpu_has(X86_FEATURE_HW_PSTATE)) {
12054827ea6ec9ca1e873a6d387a3ee287f78ea5ee83Borislav Petkov		__request_acpi_cpufreq();
1206fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen		return -ENODEV;
1207e1f0b8e9b04a262834ed111e605e5d215685dfabMatthew Garrett	}
1208fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen
1209fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen	if (!x86_match_cpu(powernow_k8_ids))
1210fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen		return -ENODEV;
1211fa8031aefec0cf7ea6c2387c93610d99d9659aa2Andi Kleen
1212c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	get_online_cpus();
1213a72011567812cbd93788cc5facda160a3cba5905Andrew Morton	for_each_online_cpu(i) {
1214c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov		smp_call_function_single(i, check_supported_cpu, &ret, 1);
1215c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov		if (!ret)
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			supported_cpus++;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1219c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	if (supported_cpus != num_online_cpus()) {
1220c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov		put_online_cpus();
122173860c6b2fd159a35637e233d735e36887c266adBorislav Petkov		return -ENODEV;
1222c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	}
1223c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	put_online_cpus();
122473860c6b2fd159a35637e233d735e36887c266adBorislav Petkov
1225c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	ret = cpufreq_register_driver(&cpufreq_amd64_driver);
1226c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	if (ret)
1227c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov		return ret;
122873860c6b2fd159a35637e233d735e36887c266adBorislav Petkov
1229e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos Karafotis	pr_info("Found %d %s (%d cpu cores) (" VERSION ")\n",
1230c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov		num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
123173860c6b2fd159a35637e233d735e36887c266adBorislav Petkov
1232c0939e46a84c6af89d6f093a34c1c9341dfe1d6eBorislav Petkov	return ret;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* driver entry point for term */
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit powernowk8_exit(void)
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12382d06d8c49afdcc9bb35a85039fa50f0fe35bd40eDominik Brodowski	pr_debug("exit\n");
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpufreq_unregister_driver(&cpufreq_amd64_driver);
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1243e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos KarafotisMODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
1244e54173b4ed0fca1a5dce9911f54e71f2917d4869Stratos KarafotisMODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@amd.com>");
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslate_initcall(powernowk8_init);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(powernowk8_exit);
1250