Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ee8099f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq

* 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.
parents c03efdb2 24669f7d
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -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>
@@ -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)
@@ -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;
+123 −63
Original line number Diff line number Diff line
@@ -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>

@@ -52,18 +53,26 @@
#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)

@@ -71,7 +80,6 @@ static int dont_scale_voltage;
/* 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;
@@ -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 */
@@ -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();
@@ -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 */
@@ -227,10 +237,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
	outb(0xFF,0xA1);	/* Overkill */
	outb(0xFE,0x21);	/* TMR0 only */

	if (pr->flags.bm_control) {
 		/* Disable bus master arbitration */
	if (pr->flags.bm_check) {
		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) {
@@ -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;

	/*
@@ -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;
	}

	if (pr->flags.bm_control) {
		/* Enable bus master arbitration */
	if (pr->flags.bm_check) {
		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 */
@@ -446,52 +465,56 @@ 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))
	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;
	}

	/* 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);
	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);
	
	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);
	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++;
	}

	can_scale_voltage = 1;
}
@@ -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;
@@ -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;
@@ -729,8 +788,10 @@ 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.");
@@ -738,4 +799,3 @@ MODULE_LICENSE ("GPL");

late_initcall(longhaul_init);
module_exit(longhaul_exit);
+38 −10
Original line number Diff line number Diff line
@@ -450,17 +450,45 @@ static int __initdata nehemiah_c_eblcr[32] = {
 * Voltage scales. Div/Mod by 1000 to get actual voltage.
 * Which scale to use depends on the VRM type in use.
 */
static int __initdata vrm85scales[32] = {
	1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700,
	1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300,
	1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725,
	1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325,

struct mV_pos {
	unsigned short mV;
	unsigned short pos;
};

static struct mV_pos __initdata vrm85_mV[32] = {
	{1250, 8},	{1200, 6},	{1150, 4},	{1100, 2},
	{1050, 0},	{1800, 30},	{1750, 28},	{1700, 26},
	{1650, 24},	{1600, 22},	{1550, 20},	{1500, 18},
	{1450, 16},	{1400, 14},	{1350, 12},	{1300, 10},
	{1275, 9},	{1225, 7},	{1175, 5},	{1125, 3},
	{1075, 1},	{1825, 31},	{1775, 29},	{1725, 27},
	{1675, 25},	{1625, 23},	{1575, 21},	{1525, 19},
	{1475, 17},	{1425, 15},	{1375, 13},	{1325, 11}
};

static unsigned char __initdata mV_vrm85[32] = {
	0x04,	0x14,	0x03,	0x13,	0x02,	0x12,	0x01,	0x11,
	0x00,	0x10,	0x0f,	0x1f,	0x0e,	0x1e,	0x0d,	0x1d,
	0x0c,	0x1c,	0x0b,	0x1b,	0x0a,	0x1a,	0x09,	0x19,
	0x08,	0x18,	0x07,	0x17,	0x06,	0x16,	0x05,	0x15
};

static struct mV_pos __initdata mobilevrm_mV[32] = {
	{1750, 31},	{1700, 30},	{1650, 29},	{1600, 28},
	{1550, 27},	{1500, 26},	{1450, 25},	{1400, 24},
	{1350, 23},	{1300, 22},	{1250, 21},	{1200, 20},
	{1150, 19},	{1100, 18},	{1050, 17},	{1000, 16},
	{975, 15},	{950, 14},	{925, 13},	{900, 12},
	{875, 11},	{850, 10},	{825, 9},	{800, 8},
	{775, 7},	{750, 6},	{725, 5},	{700, 4},
	{675, 3},	{650, 2},	{625, 1},	{600, 0}
};

static int __initdata mobilevrmscales[32] = {
	2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
	1600, 1550, 1500, 1450, 1500, 1350, 1300, -1,
	1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
	1075, 1050, 1025, 1000, 975, 950, 925, -1,
static unsigned char __initdata mV_mobilevrm[32] = {
	0x1f,	0x1e,	0x1d,	0x1c,	0x1b,	0x1a,	0x19,	0x18,
	0x17,	0x16,	0x15,	0x14,	0x13,	0x12,	0x11,	0x10,
	0x0f,	0x0e,	0x0d,	0x0c,	0x0b,	0x0a,	0x09,	0x08,
	0x07,	0x06,	0x05,	0x04,	0x03,	0x02,	0x01,	0x00
};
+41 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

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

@@ -377,6 +378,35 @@ static int centrino_cpu_early_init_acpi(void)
	return 0;
}


/*
 * 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 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"),
		},
	},
	{ }
};


/*
 * centrino_cpu_init_acpi - register with ACPI P-States library
 *
@@ -398,14 +428,24 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
		dprintk(PFX "obtaining ACPI data failed\n");
		return -EIO;
	}

	policy->shared_type = p->shared_type;
	/*
	 * Will let policy->cpus know about dependency only when software 
	 * 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 = p->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

	/* verify the acpi_data */
	if (p->state_count <= 1) {
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)

/**
 * The "cpufreq driver" - the arch- or hardware-dependend low
 * The "cpufreq driver" - the arch- or hardware-dependent low
 * level driver of CPUFreq support, and its spinlock. This lock
 * also protects the cpufreq_cpu_data array.
 */
Loading