Skip to content

Commit

Permalink
cpufreq: Add support for x86 cpuinfo auto loading v4
Browse files Browse the repository at this point in the history
This marks all the x86 cpuinfo tables to the CPU specific device drivers,
to allow auto loading by udev. This should simplify the distribution
startup scripts for this greatly.

I didn't add MODULE_DEVICE_IDs to the centrino and p4-clockmod drivers,
because those probably shouldn't be auto loaded and the acpi driver
be used instead (not fully sure on that, would appreciate feedback)

The old nforce drivers autoload based on the PCI ID.

ACPI cpufreq is autoloaded in another patch.

v3: Autoload gx based on PCI IDs only. Remove cpu check (Dave Jones)
v4: Use newly introduce HW_PSTATE feature for powernow-k8 loading

Cc: Dave Jones <davej@redhat.com>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Thomas Renninger <trenn@suse.de>
Acked-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Andi Kleen authored and gregkh committed Jan 27, 2012
1 parent 2f1e097 commit fa8031a
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 61 deletions.
8 changes: 8 additions & 0 deletions drivers/cpufreq/cpufreq-nforce2.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,14 @@ static struct cpufreq_driver nforce2_driver = {
.owner = THIS_MODULE,
};

#ifdef MODULE
static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
{}
};
MODULE_DEVICE_TABLE(pci, nforce2_ids);
#endif

/**
* nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
*
Expand Down
20 changes: 11 additions & 9 deletions drivers/cpufreq/e_powersaver.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/delay.h>

#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include <asm/tsc.h>

Expand Down Expand Up @@ -437,18 +438,19 @@ static struct cpufreq_driver eps_driver = {
.attr = eps_attr,
};


/* This driver will work only on Centaur C7 processors with
* Enhanced SpeedStep/PowerSaver registers */
static const struct x86_cpu_id eps_cpu_id[] = {
{ X86_VENDOR_CENTAUR, 6, X86_MODEL_ANY, X86_FEATURE_EST },
{}
};
MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);

static int __init eps_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);

/* This driver will work only on Centaur C7 processors with
* Enhanced SpeedStep/PowerSaver registers */
if (c->x86_vendor != X86_VENDOR_CENTAUR
|| c->x86 != 6 || c->x86_model < 10)
return -ENODEV;
if (!cpu_has(c, X86_FEATURE_EST))
if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10)
return -ENODEV;

if (cpufreq_register_driver(&eps_driver))
return -EINVAL;
return 0;
Expand Down
14 changes: 7 additions & 7 deletions drivers/cpufreq/elanfreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/cpufreq.h>

#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include <linux/timex.h>
#include <linux/io.h>
Expand Down Expand Up @@ -277,17 +278,16 @@ static struct cpufreq_driver elanfreq_driver = {
.attr = elanfreq_attr,
};

static const struct x86_cpu_id elan_id[] = {
{ X86_VENDOR_AMD, 4, 10, },
{}
};
MODULE_DEVICE_TABLE(x86cpu, elan_id);

static int __init elanfreq_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);

/* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
(c->x86 != 4) || (c->x86_model != 10)) {
printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
if (!x86_match_cpu(elan_id))
return -ENODEV;
}
return cpufreq_register_driver(&elanfreq_driver);
}

Expand Down
9 changes: 2 additions & 7 deletions drivers/cpufreq/gx-suspmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include <linux/errno.h>
#include <linux/slab.h>

#include <asm/cpu_device_id.h>
#include <asm/processor-cyrix.h>

/* PCI config registers, all at F0 */
Expand Down Expand Up @@ -171,6 +172,7 @@ static struct pci_device_id gx_chipset_tbl[] __initdata = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
{ 0, },
};
MODULE_DEVICE_TABLE(gx_chipset_tbl);

static void gx_write_byte(int reg, int value)
{
Expand All @@ -185,13 +187,6 @@ static __init struct pci_dev *gx_detect_chipset(void)
{
struct pci_dev *gx_pci = NULL;

/* check if CPU is a MediaGX or a Geode. */
if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
pr_debug("error: no MediaGX/Geode processor found!\n");
return NULL;
}

/* detect which companion chip is used */
for_each_pci_dev(gx_pci) {
if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
Expand Down
8 changes: 7 additions & 1 deletion drivers/cpufreq/longhaul.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/acpi.h>

#include <asm/msr.h>
#include <asm/cpu_device_id.h>
#include <acpi/processor.h>

#include "longhaul.h"
Expand Down Expand Up @@ -951,12 +952,17 @@ static struct cpufreq_driver longhaul_driver = {
.attr = longhaul_attr,
};

static const struct x86_cpu_id longhaul_id[] = {
{ X86_VENDOR_CENTAUR, 6 },
{}
};
MODULE_DEVICE_TABLE(x86cpu, longhaul_id);

static int __init longhaul_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);

if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
if (!x86_match_cpu(longhaul_id))
return -ENODEV;

#ifdef CONFIG_SMP
Expand Down
13 changes: 8 additions & 5 deletions drivers/cpufreq/longrun.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>

static struct cpufreq_driver longrun_driver;

Expand Down Expand Up @@ -288,6 +289,12 @@ static struct cpufreq_driver longrun_driver = {
.owner = THIS_MODULE,
};

static const struct x86_cpu_id longrun_ids[] = {
{ X86_VENDOR_TRANSMETA, X86_FAMILY_ANY, X86_MODEL_ANY,
X86_FEATURE_LONGRUN },
{}
};
MODULE_DEVICE_TABLE(x86cpu, longrun_ids);

/**
* longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
Expand All @@ -296,12 +303,8 @@ static struct cpufreq_driver longrun_driver = {
*/
static int __init longrun_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);

if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
!cpu_has(c, X86_FEATURE_LONGRUN))
if (!x86_match_cpu(longrun_ids))
return -ENODEV;

return cpufreq_register_driver(&longrun_driver);
}

Expand Down
17 changes: 11 additions & 6 deletions drivers/cpufreq/p4-clockmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/timer.h>
#include <asm/cpu_device_id.h>

#include "speedstep-lib.h"

Expand Down Expand Up @@ -289,21 +290,25 @@ static struct cpufreq_driver p4clockmod_driver = {
.attr = p4clockmod_attr,
};

static const struct x86_cpu_id cpufreq_p4_id[] = {
{ X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ACC },
{}
};

/*
* Intentionally no MODULE_DEVICE_TABLE here: this driver should not
* be auto loaded. Please don't add one.
*/

static int __init cpufreq_p4_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
int ret;

/*
* THERM_CONTROL is architectural for IA32 now, so
* we can rely on the capability checks
*/
if (c->x86_vendor != X86_VENDOR_INTEL)
return -ENODEV;

if (!test_cpu_cap(c, X86_FEATURE_ACPI) ||
!test_cpu_cap(c, X86_FEATURE_ACC))
if (!x86_match_cpu(cpufreq_p4_id) || !boot_cpu_has(X86_FEATURE_ACPI))
return -ENODEV;

ret = cpufreq_register_driver(&p4clockmod_driver);
Expand Down
12 changes: 8 additions & 4 deletions drivers/cpufreq/powernow-k6.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/timex.h>
#include <linux/io.h>

#include <asm/cpu_device_id.h>
#include <asm/msr.h>

#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
Expand Down Expand Up @@ -210,6 +211,12 @@ static struct cpufreq_driver powernow_k6_driver = {
.attr = powernow_k6_attr,
};

static const struct x86_cpu_id powernow_k6_ids[] = {
{ X86_VENDOR_AMD, 5, 12 },
{ X86_VENDOR_AMD, 5, 13 },
{}
};


/**
* powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
Expand All @@ -220,10 +227,7 @@ static struct cpufreq_driver powernow_k6_driver = {
*/
static int __init powernow_k6_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);

if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13)))
if (!x86_match_cpu(powernow_k6_ids))
return -ENODEV;

if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
Expand Down
14 changes: 8 additions & 6 deletions drivers/cpufreq/powernow-k7.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
#include <asm/msr.h>
#include <asm/system.h>
#include <asm/cpu_device_id.h>

#ifdef CONFIG_X86_POWERNOW_K7_ACPI
#include <linux/acpi.h>
Expand Down Expand Up @@ -110,18 +111,19 @@ static int check_fsb(unsigned int fsbspeed)
return delta < 5;
}

static const struct x86_cpu_id powernow_k7_cpuids[] = {
{ X86_VENDOR_AMD, 7, },
{}
};
MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);

static int check_powernow(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int maxei, eax, ebx, ecx, edx;

if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
#ifdef MODULE
printk(KERN_INFO PFX "This module only works with "
"AMD K7 CPUs\n");
#endif
if (!x86_match_cpu(powernow_k7_cpuids))
return 0;
}

/* Get maximum capabilities */
maxei = cpuid_eax(0x80000000);
Expand Down
19 changes: 13 additions & 6 deletions drivers/cpufreq/powernow-k8.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/delay.h>

#include <asm/msr.h>
#include <asm/cpu_device_id.h>

#include <linux/acpi.h>
#include <linux/mutex.h>
Expand Down Expand Up @@ -520,20 +521,23 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
return 0;
}

static const struct x86_cpu_id powernow_k8_ids[] = {
/* IO based frequency switching */
{ X86_VENDOR_AMD, 0xf },
/* MSR based frequency switching supported */
X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
{}
};
MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);

static void check_supported_cpu(void *_rc)
{
u32 eax, ebx, ecx, edx;
int *rc = _rc;

*rc = -ENODEV;

if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
return;

eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
((eax & CPUID_XFAM) < CPUID_XFAM_10H))
return;

if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
Expand Down Expand Up @@ -1553,6 +1557,9 @@ static int __cpuinit powernowk8_init(void)
unsigned int i, supported_cpus = 0, cpu;
int rv;

if (!x86_match_cpu(powernow_k8_ids))
return -ENODEV;

for_each_online_cpu(i) {
int rc;
smp_call_function_single(i, check_supported_cpu, &rc, 1);
Expand Down
14 changes: 8 additions & 6 deletions drivers/cpufreq/sc520_freq.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/timex.h>
#include <linux/io.h>

#include <asm/cpu_device_id.h>
#include <asm/msr.h>

#define MMCR_BASE 0xfffef000 /* The default base address */
Expand Down Expand Up @@ -150,18 +151,19 @@ static struct cpufreq_driver sc520_freq_driver = {
.attr = sc520_freq_attr,
};

static const struct x86_cpu_id sc520_ids[] = {
{ X86_VENDOR_AMD, 4, 9 },
{}
};
MODULE_DEVICE_TABLE(x86cpu, sc520_ids);

static int __init sc520_freq_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(0);
int err;

/* Test if we have the right hardware */
if (c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9) {
pr_debug("no Elan SC520 processor found!\n");
if (!x86_match_cpu(sc520_ids))
return -ENODEV;
}

cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
if (!cpuctl) {
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
Expand Down
Loading

0 comments on commit fa8031a

Please sign in to comment.