Skip to content

Commit

Permalink
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
Browse files Browse the repository at this point in the history
* master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq:
  [CPUFREQ] sw_any_bug_dmi_table can be used on resume, so it isn't initdata
  [CPUFREQ] Fix some more CPU hotplug locking.
  [CPUFREQ] Workaround for BIOS bug in software coordination of frequency
  [CPUFREQ] Longhaul - Add voltage scaling to driver
  [CPUFREQ] Fix sparse warning in ondemand
  [CPUFREQ] make drivers/cpufreq/cpufreq_ondemand.c:powersave_bias_target() static
  [CPUFREQ] Longhaul - Add ignore_latency option
  [CPUFREQ] Longhaul - Disable arbiter
  [CPUFREQ][2/2] ondemand: updated add powersave_bias tunable
  [CPUFREQ][1/2] ondemand: updated tune for hardware coordination
  [CPUFREQ] Fix typo.
  • Loading branch information
Linus Torvalds committed Sep 23, 2006
2 parents c03efdb + 24669f7 commit 2ee8099
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 101 deletions.
39 changes: 38 additions & 1 deletion arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/seq_file.h>
#include <linux/compiler.h>
#include <linux/sched.h> /* current */
#include <linux/dmi.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
Expand Down Expand Up @@ -387,6 +388,33 @@ static int acpi_cpufreq_early_init_acpi(void)
return acpi_processor_preregister_performance(acpi_perf_data);
}

/*
* Some BIOSes do SW_ANY coordination internally, either set it up in hw
* or do it in BIOS firmware and won't inform about it to OS. If not
* detected, this has a side effect of making CPU run at a different speed
* than OS intended it to run at. Detect it and handle it cleanly.
*/
static int bios_with_sw_any_bug;

static int __init sw_any_bug_found(struct dmi_system_id *d)
{
bios_with_sw_any_bug = 1;
return 0;
}

static struct dmi_system_id __initdata sw_any_bug_dmi_table[] = {
{
.callback = sw_any_bug_found,
.ident = "Supermicro Server X6DLP",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
DMI_MATCH(DMI_BIOS_VERSION, "080010"),
DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
},
},
{ }
};

static int
acpi_cpufreq_cpu_init (
struct cpufreq_policy *policy)
Expand Down Expand Up @@ -422,8 +450,17 @@ acpi_cpufreq_cpu_init (
* coordination is required.
*/
if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
policy->cpus = perf->shared_cpu_map;
}

#ifdef CONFIG_SMP
dmi_check_system(sw_any_bug_dmi_table);
if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
policy->cpus = cpu_core_map[cpu];
}
#endif

if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
Expand Down
186 changes: 123 additions & 63 deletions arch/i386/kernel/cpu/cpufreq/longhaul.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/string.h>

Expand All @@ -52,26 +53,33 @@
#define CPU_NEHEMIAH 5

static int cpu_model;
static unsigned int numscales=16, numvscales;
static unsigned int numscales=16;
static unsigned int fsb;
static int minvid, maxvid;

static struct mV_pos *vrm_mV_table;
static unsigned char *mV_vrm_table;
struct f_msr {
unsigned char vrm;
};
static struct f_msr f_msr_table[32];

static unsigned int highest_speed, lowest_speed; /* kHz */
static unsigned int minmult, maxmult;
static int can_scale_voltage;
static int vrmrev;
static struct acpi_processor *pr = NULL;
static struct acpi_processor_cx *cx = NULL;
static int port22_en;

/* Module parameters */
static int dont_scale_voltage;

static int scale_voltage;
static int ignore_latency;

#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)


/* Clock ratios multiplied by 10 */
static int clock_ratio[32];
static int eblcr_table[32];
static int voltage_table[32];
static unsigned int highest_speed, lowest_speed; /* kHz */
static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
Expand Down Expand Up @@ -124,10 +132,9 @@ static int longhaul_get_cpu_mult(void)

/* For processor with BCR2 MSR */

static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
static void do_longhaul1(unsigned int clock_ratio_index)
{
union msr_bcr2 bcr2;
u32 t;

rdmsrl(MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
Expand All @@ -136,13 +143,11 @@ static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)

/* Sync to timer tick */
safe_halt();
ACPI_FLUSH_CPU_CACHE();
/* Change frequency on next halt or sleep */
wrmsrl(MSR_VIA_BCR2, bcr2.val);
/* Invoke C3 */
inb(cx_address);
/* Dummy op - must do something useless after P_LVL3 read */
t = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke transition */
ACPI_FLUSH_CPU_CACHE();
halt();

/* Disable software clock multiplier */
local_irq_disable();
Expand All @@ -164,11 +169,16 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
longhaul.bits.EnableSoftBusRatio = 1;

if (can_scale_voltage) {
longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
longhaul.bits.EnableSoftVID = 1;
}

/* Sync to timer tick */
safe_halt();
ACPI_FLUSH_CPU_CACHE();
/* Change frequency on next halt or sleep */
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
ACPI_FLUSH_CPU_CACHE();
/* Invoke C3 */
inb(cx_address);
/* Dummy op - must do something useless after P_LVL3 read */
Expand Down Expand Up @@ -227,10 +237,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
outb(0xFF,0xA1); /* Overkill */
outb(0xFE,0x21); /* TMR0 only */

/* Disable bus master arbitration */
if (pr->flags.bm_check) {
if (pr->flags.bm_control) {
/* Disable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
ACPI_MTX_DO_NOT_LOCK);
} else if (port22_en) {
/* Disable AGP and PCI arbiters */
outb(3, 0x22);
}

switch (longhaul_version) {
Expand All @@ -244,7 +257,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
*/
case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2:
do_longhaul1(cx->address, clock_ratio_index);
do_longhaul1(clock_ratio_index);
break;

/*
Expand All @@ -259,14 +272,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
* to work in practice.
*/
case TYPE_POWERSAVER:
/* Don't allow wakeup */
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
ACPI_MTX_DO_NOT_LOCK);
do_powersaver(cx->address, clock_ratio_index);
break;
}

/* Enable bus master arbitration */
if (pr->flags.bm_check) {
if (pr->flags.bm_control) {
/* Enable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
ACPI_MTX_DO_NOT_LOCK);
} else if (port22_en) {
/* Enable arbiters */
outb(0, 0x22);
}

outb(pic2_mask,0xA1); /* restore mask */
Expand Down Expand Up @@ -446,53 +465,57 @@ static int __init longhaul_get_ranges(void)
static void __init longhaul_setup_voltagescaling(void)
{
union msr_longhaul longhaul;
struct mV_pos minvid, maxvid;
unsigned int j, speed, pos, kHz_step, numvscales;

rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);

if (!(longhaul.bits.RevisionID & 1))
rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
if (!(longhaul.bits.RevisionID & 1)) {
printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n");
return;
}

if (!longhaul.bits.VRMRev) {
printk (KERN_INFO PFX "VRM 8.5\n");
vrm_mV_table = &vrm85_mV[0];
mV_vrm_table = &mV_vrm85[0];
} else {
printk (KERN_INFO PFX "Mobile VRM\n");
vrm_mV_table = &mobilevrm_mV[0];
mV_vrm_table = &mV_mobilevrm[0];
}

minvid = longhaul.bits.MinimumVID;
maxvid = longhaul.bits.MaximumVID;
vrmrev = longhaul.bits.VRMRev;
minvid = vrm_mV_table[longhaul.bits.MinimumVID];
maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
numvscales = maxvid.pos - minvid.pos + 1;
kHz_step = (highest_speed - lowest_speed) / numvscales;

if (minvid == 0 || maxvid == 0) {
if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
"Voltage scaling disabled.\n",
minvid/1000, minvid%1000, maxvid/1000, maxvid%1000);
minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000);
return;
}

if (minvid == maxvid) {
if (minvid.mV == maxvid.mV) {
printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
"both %d.%03d. Voltage scaling disabled\n",
maxvid/1000, maxvid%1000);
maxvid.mV/1000, maxvid.mV%1000);
return;
}

if (vrmrev==0) {
dprintk ("VRM 8.5\n");
memcpy (voltage_table, vrm85scales, sizeof(voltage_table));
numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;
} else {
dprintk ("Mobile VRM\n");
memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));
numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;
printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n",
maxvid.mV/1000, maxvid.mV%1000,
minvid.mV/1000, minvid.mV%1000,
numvscales);

j = 0;
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
speed = longhaul_table[j].frequency;
pos = (speed - lowest_speed) / kHz_step + minvid.pos;
f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
j++;
}

/* Current voltage isn't readable at first, so we need to
set it to a known value. The spec says to use maxvid */
longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */
longhaul.bits.EnableSoftVID = 1;
longhaul.bits.SoftVID = maxvid;
wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);

minvid = voltage_table[minvid];
maxvid = voltage_table[maxvid];

dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);

can_scale_voltage = 1;
}

Expand Down Expand Up @@ -540,21 +563,33 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
return 1;
}

/* VIA don't support PM2 reg, but have something similar */
static int enable_arbiter_disable(void)
{
struct pci_dev *dev;
u8 pci_cmd;

/* Find PLE133 host bridge */
dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
if (dev != NULL) {
/* Enable access to port 0x22 */
pci_read_config_byte(dev, 0x78, &pci_cmd);
if ( !(pci_cmd & 1<<7) ) {
pci_cmd |= 1<<7;
pci_write_config_byte(dev, 0x78, pci_cmd);
}
return 1;
}
return 0;
}

static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
char *cpuname=NULL;
int ret;

/* Check ACPI support for C3 state */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
&longhaul_walk_callback, NULL, (void *)&pr);
if (pr == NULL) goto err_acpi;

cx = &pr->power.states[ACPI_STATE_C3];
if (cx->address == 0 || cx->latency > 1000) goto err_acpi;

/* Now check what we have on this motherboard */
/* Check what we have on this motherboard */
switch (c->x86_model) {
case 6:
cpu_model = CPU_SAMUEL;
Expand Down Expand Up @@ -636,12 +671,36 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
break;
};

/* Find ACPI data for processor */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
&longhaul_walk_callback, NULL, (void *)&pr);
if (pr == NULL)
goto err_acpi;

if (longhaul_version == TYPE_POWERSAVER) {
/* Check ACPI support for C3 state */
cx = &pr->power.states[ACPI_STATE_C3];
if (cx->address == 0 ||
(cx->latency > 1000 && ignore_latency == 0) )
goto err_acpi;

} else {
/* Check ACPI support for bus master arbiter disable */
if (!pr->flags.bm_control) {
if (!enable_arbiter_disable()) {
printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n");
return -ENODEV;
} else
port22_en = 1;
}
}

ret = longhaul_get_ranges();
if (ret != 0)
return ret;

if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
(dont_scale_voltage==0))
(scale_voltage != 0))
longhaul_setup_voltagescaling();

policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
Expand Down Expand Up @@ -729,13 +788,14 @@ static void __exit longhaul_exit(void)
kfree(longhaul_table);
}

module_param (dont_scale_voltage, int, 0644);
MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");
module_param (scale_voltage, int, 0644);
MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
module_param(ignore_latency, int, 0644);
MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test");

MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
MODULE_LICENSE ("GPL");

late_initcall(longhaul_init);
module_exit(longhaul_exit);

Loading

0 comments on commit 2ee8099

Please sign in to comment.