All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Longhaul - Don't use regs to obtain FSB frequency
@ 2006-12-03 16:17 Rafał Bilski
  0 siblings, 0 replies; 5+ messages in thread
From: Rafał Bilski @ 2006-12-03 16:17 UTC (permalink / raw)
  To: Dave Jones; +Cc: cpufreq

Current code has a problem with FSB on "PowerSaver 1.0" 
CPU. FSB is incorrecly guessed (again) for mini PC by Ebox. 
There is 8x100MHz CPU with "Nehemiah" core. It is reported 
as 8x133MHz. Apparently Longhaul MSR isn't reliable source 
of information if it is RevisionID == 0 for anything else 
then max multiplier. We can't read 200MHz FSB from it nor 
from EBLCR_POWER_ON too. This driver is working only with 
multipliers. FSB frequency is only needed to calculate CPU 
f for Cpufreq core. At boot kernel is calculating processor 
frequency. We know the multiplier. In this way we have bus 
frequency with kHz precision.

Signed-off-by: Rafa³ Bilski <rafalbilski@interia.pl>

--- 

diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -54,7 +54,7 @@
 
 static int cpu_model;
 static unsigned int numscales=16;
-static unsigned int fsb;
+static unsigned int fsb_kHz;
 
 static struct mV_pos *vrm_mV_table;
 static unsigned char *mV_vrm_table;
@@ -109,15 +109,14 @@ static char *print_speed(int speed)
 static unsigned int calc_speed(int mult)
 {
 	int khz;
-	khz = (mult/10)*fsb;
+	khz = (mult/10)*fsb_kHz;
 	if (mult%10)
-		khz += fsb/2;
-	khz *= 1000;
+		khz += fsb_kHz/2;
 	return khz;
 }
 
 
-static int longhaul_get_cpu_mult(void)
+static int get_cpu_mult_eblcr(void)
 {
 	unsigned long invalue=0,lo, hi;
 
@@ -226,14 +225,14 @@ static void longhaul_setstate(unsigned i
 	if ((speed > highest_speed) || (speed < lowest_speed))
 		return;
 
-	freqs.old = calc_speed(longhaul_get_cpu_mult());
+	freqs.old = calc_speed(get_cpu_mult_eblcr());
 	freqs.new = speed;
 	freqs.cpu = 0; /* longhaul.c is UP only driver */
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
 	dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
-			fsb, mult/10, mult%10, print_speed(speed/1000));
+			fsb_kHz/1000, mult/10, mult%10, print_speed(speed/1000));
 
 	preempt_disable();
 	local_irq_save(flags);
@@ -303,60 +302,16 @@ static void longhaul_setstate(unsigned i
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 }
 
-/*
- * Centaur decided to make life a little more tricky.
- * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
- * Samuel2 and above have to try and guess what the FSB is.
- * We do this by assuming we booted at maximum multiplier, and interpolate
- * between that value multiplied by possible FSBs and cpu_mhz which
- * was calculated at boot time. Really ugly, but no other way to do this.
- */
-
-#define ROUNDING	0xf
-
-static int _guess(int guess)
-{
-	int target;
-
-	target = ((maxmult/10)*guess);
-	if (maxmult%10 != 0)
-		target += (guess/2);
-	target += ROUNDING/2;
-	target &= ~ROUNDING;
-	return target;
-}
-
-
-static int guess_fsb(void)
-{
-	int speed = (cpu_khz/1000);
-	int i;
-	int speeds[3] = { 66, 100, 133 };
-
-	speed += ROUNDING/2;
-	speed &= ~ROUNDING;
-
-	for (i=0; i<3; i++) {
-		if (_guess(speeds[i]) == speed)
-			return speeds[i];
-	}
-	return 0;
-}
-
-
 static int __init longhaul_get_ranges(void)
 {
 	unsigned long invalue;
-	unsigned int ezra_t_multipliers[32]= {
+	unsigned int longhaul_multipliers[32]= {
 			90,  30,  40, 100,  55,  35,  45,  95,
 			50,  70,  80,  60, 120,  75,  85,  65,
 			-1, 110, 120,  -1, 135, 115, 125, 105,
 			130, 150, 160, 140,  -1, 155,  -1, 145 };
 	unsigned int j, k = 0;
 	union msr_longhaul longhaul;
-	unsigned long lo, hi;
-	unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 };
-	unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 };
 
 	switch (longhaul_version) {
 	case TYPE_LONGHAUL_V1:
@@ -364,71 +319,43 @@ static int __init longhaul_get_ranges(vo
 		/* Ugh, Longhaul v1 didn't have the min/max MSRs.
 		   Assume min=3.0x & max = whatever we booted at. */
 		minmult = 30;
-		maxmult = longhaul_get_cpu_mult();
-		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
-		invalue = (lo & (1<<18|1<<19)) >>18;
-		if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2)
-			fsb = eblcr_fsb_table_v1[invalue];
-		else
-			fsb = guess_fsb();
+		maxmult = get_cpu_mult_eblcr();
 		break;
 
 	case TYPE_POWERSAVER:
-		/* Ezra-T */
-		if (cpu_model==CPU_EZRA_T) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-			invalue = longhaul.bits.MaxMHzBR;
-			if (longhaul.bits.MaxMHzBR4)
-				invalue += 16;
-			maxmult=ezra_t_multipliers[invalue];
-
+		rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+		invalue = longhaul.bits.MaxMHzBR;
+		if (longhaul.bits.MaxMHzBR4)
+			invalue += 16;
+		maxmult = longhaul_multipliers[invalue];
+		/* Ezra-T
+		 * PowerSaver 2.0 - bus ratio and voltage scaling
+		 * Valid: MinMHzBR, MaxMHzBR, MinMHzFSB, MaxMHzFSB,
+		 * 	  MinVID, MaxVID, VRMRev */
+		if (longhaul.bits.RevisionID > 0) {
 			invalue = longhaul.bits.MinMHzBR;
 			if (longhaul.bits.MinMHzBR4 == 1)
 				minmult = 30;
 			else
-				minmult = ezra_t_multipliers[invalue];
-			fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
-		}
-
-		/* Nehemiah */
-		if (cpu_model==CPU_NEHEMIAH) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
-			/*
-			 * TODO: This code works, but raises a lot of questions.
-			 * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
-			 *   We get around this by using a hardcoded multiplier of 4.0x
-			 *   for the minimimum speed, and the speed we booted up at for the max.
-			 *   This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
-			 * - According to some VIA documentation EBLCR is only
-			 *   in pre-Nehemiah C3s. How this still works is a mystery.
-			 *   We're possibly using something undocumented and unsupported,
-			 *   But it works, so we don't grumble.
-			 */
-			minmult=40;
-			maxmult=longhaul_get_cpu_mult();
-
-			/* Starting with the 1.2GHz parts, theres a 200MHz bus. */
-			if ((cpu_khz/maxmult) > 13400)
-				fsb = 200;
-			else
-				fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
+				minmult = longhaul_multipliers[invalue];
+		/* Nehemiah
+		 * PowerSaver 1.0 - bus ratio scaling
+		 * Valid: MaxMHzBR */
+		} else {
+			minmult = 40;
 		}
+		break;
 	}
+	/* Kernel already knows true FSB speed */
+	fsb_kHz = (cpu_khz * 10) / maxmult;
 
 	dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
 		 minmult/10, minmult%10, maxmult/10, maxmult%10);
 
-	if (fsb == -1) {
-		printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
-		return -EINVAL;
-	}
-
 	highest_speed = calc_speed(maxmult);
 	lowest_speed = calc_speed(minmult);
-	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
+	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n",
+		 fsb_kHz / 1000,
 		 print_speed(lowest_speed/1000), 
 		 print_speed(highest_speed/1000));
 
@@ -475,7 +402,7 @@ static void __init longhaul_setup_voltag
 	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;
 	}
@@ -553,7 +480,7 @@ static unsigned int longhaul_get(unsigne
 {
 	if (cpu)
 		return 0;
-	return calc_speed(longhaul_get_cpu_mult());
+	return calc_speed(get_cpu_mult_eblcr());
 }
 
 static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
@@ -728,7 +655,7 @@ print_support_type:
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 200000;	/* nsec */
-	policy->cur = calc_speed(longhaul_get_cpu_mult());
+	policy->cur = calc_speed(get_cpu_mult_eblcr());
 
 	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
 	if (ret)


----------------------------------------------------------------------
Jestes kierowca? To poczytaj! >>> http://link.interia.pl/f199e

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] Longhaul - Don't use regs to obtain FSB frequency
@ 2006-12-13 22:28 Rafał Bilski
  0 siblings, 0 replies; 5+ messages in thread
From: Rafał Bilski @ 2006-12-13 22:28 UTC (permalink / raw)
  To: Dave Jones; +Cc: cpufreq

Current code has a problem with FSB on "PowerSaver 1.0" 
CPU. FSB is incorrecly guessed (again) for mini PC by Ebox. 
There is 8x100MHz CPU with "Nehemiah" core. It is reported 
as 8x133MHz. Apparently Longhaul MSR isn't reliable source 
of information if it is RevisionID == 0 for anything else 
then max multiplier. We can't read 200MHz FSB from it nor 
from EBLCR_POWER_ON too. This driver is working only with 
multipliers. FSB frequency is only needed to calculate CPU 
f for Cpufreq core. At boot kernel is calculating processor 
frequency. We know the multiplier. In this way we have bus 
frequency with kHz precision.

Signed-off-by: Rafa³ Bilski <rafalbilski@interia.pl>

--- 

diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -54,7 +54,7 @@

static int cpu_model;
static unsigned int numscales=16;
-static unsigned int fsb;
+static unsigned int fsb_kHz;

static struct mV_pos *vrm_mV_table;
static unsigned char *mV_vrm_table;
@@ -109,15 +109,14 @@ static char *print_speed(int speed)
static unsigned int calc_speed(int mult)
{
	int khz;
-	khz = (mult/10)*fsb;
+	khz = (mult/10)*fsb_kHz;
	if (mult%10)
-		khz += fsb/2;
-	khz *= 1000;
+		khz += fsb_kHz/2;
	return khz;
}


-static int longhaul_get_cpu_mult(void)
+static int get_cpu_mult_eblcr(void)
{
	unsigned long invalue=0,lo, hi;

@@ -226,14 +225,14 @@ static void longhaul_setstate(unsigned i
	if ((speed > highest_speed) || (speed < lowest_speed))
		return;

-	freqs.old = calc_speed(longhaul_get_cpu_mult());
+	freqs.old = calc_speed(get_cpu_mult_eblcr());
	freqs.new = speed;
	freqs.cpu = 0; /* longhaul.c is UP only driver */

	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);

	dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
-			fsb, mult/10, mult%10, print_speed(speed/1000));
+			fsb_kHz/1000, mult/10, mult%10, print_speed(speed/1000));

	preempt_disable();
	local_irq_save(flags);
@@ -303,60 +302,16 @@ static void longhaul_setstate(unsigned i
	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}

-/*
- * Centaur decided to make life a little more tricky.
- * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
- * Samuel2 and above have to try and guess what the FSB is.
- * We do this by assuming we booted at maximum multiplier, and interpolate
- * between that value multiplied by possible FSBs and cpu_mhz which
- * was calculated at boot time. Really ugly, but no other way to do this.
- */
-
-#define ROUNDING	0xf
-
-static int _guess(int guess)
-{
-	int target;
-
-	target = ((maxmult/10)*guess);
-	if (maxmult%10 != 0)
-		target += (guess/2);
-	target += ROUNDING/2;
-	target &= ~ROUNDING;
-	return target;
-}
-
-
-static int guess_fsb(void)
-{
-	int speed = (cpu_khz/1000);
-	int i;
-	int speeds[3] = { 66, 100, 133 };
-
-	speed += ROUNDING/2;
-	speed &= ~ROUNDING;
-
-	for (i=0; i<3; i++) {
-		if (_guess(speeds[i]) == speed)
-			return speeds[i];
-	}
-	return 0;
-}
-
-
static int __init longhaul_get_ranges(void)
{
	unsigned long invalue;
-	unsigned int ezra_t_multipliers[32]= {
+	unsigned int longhaul_multipliers[32]= {
			90,  30,  40, 100,  55,  35,  45,  95,
			50,  70,  80,  60, 120,  75,  85,  65,
			-1, 110, 120,  -1, 135, 115, 125, 105,
			130, 150, 160, 140,  -1, 155,  -1, 145 };
	unsigned int j, k = 0;
	union msr_longhaul longhaul;
-	unsigned long lo, hi;
-	unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 };
-	unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 };

	switch (longhaul_version) {
	case TYPE_LONGHAUL_V1:
@@ -364,71 +319,43 @@ static int __init longhaul_get_ranges(vo
		/* Ugh, Longhaul v1 didn't have the min/max MSRs.
		   Assume min=3.0x & max = whatever we booted at. */
		minmult = 30;
-		maxmult = longhaul_get_cpu_mult();
-		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
-		invalue = (lo & (1<<18|1<<19)) >>18;
-		if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2)
-			fsb = eblcr_fsb_table_v1[invalue];
-		else
-			fsb = guess_fsb();
+		maxmult = get_cpu_mult_eblcr();
		break;

	case TYPE_POWERSAVER:
-		/* Ezra-T */
-		if (cpu_model==CPU_EZRA_T) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-			invalue = longhaul.bits.MaxMHzBR;
-			if (longhaul.bits.MaxMHzBR4)
-				invalue += 16;
-			maxmult=ezra_t_multipliers[invalue];
-
+		rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+		invalue = longhaul.bits.MaxMHzBR;
+		if (longhaul.bits.MaxMHzBR4)
+			invalue += 16;
+		maxmult = longhaul_multipliers[invalue];
+		/* Ezra-T
+		 * PowerSaver 2.0 - bus ratio and voltage scaling
+		 * Valid: MinMHzBR, MaxMHzBR, MinMHzFSB, MaxMHzFSB,
+		 * 	  MinVID, MaxVID, VRMRev */
+		if (longhaul.bits.RevisionID > 0) {
			invalue = longhaul.bits.MinMHzBR;
			if (longhaul.bits.MinMHzBR4 == 1)
				minmult = 30;
			else
-				minmult = ezra_t_multipliers[invalue];
-			fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
-		}
-
-		/* Nehemiah */
-		if (cpu_model==CPU_NEHEMIAH) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
-			/*
-			 * TODO: This code works, but raises a lot of questions.
-			 * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
-			 *   We get around this by using a hardcoded multiplier of 4.0x
-			 *   for the minimimum speed, and the speed we booted up at for the max.
-			 *   This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
-			 * - According to some VIA documentation EBLCR is only
-			 *   in pre-Nehemiah C3s. How this still works is a mystery.
-			 *   We're possibly using something undocumented and unsupported,
-			 *   But it works, so we don't grumble.
-			 */
-			minmult=40;
-			maxmult=longhaul_get_cpu_mult();
-
-			/* Starting with the 1.2GHz parts, theres a 200MHz bus. */
-			if ((cpu_khz/maxmult) > 13400)
-				fsb = 200;
-			else
-				fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
+				minmult = longhaul_multipliers[invalue];
+		/* Nehemiah
+		 * PowerSaver 1.0 - bus ratio scaling
+		 * Valid: MaxMHzBR */
+		} else {
+			minmult = 40;
		}
+		break;
	}
+	/* Kernel already knows true FSB speed */
+	fsb_kHz = (cpu_khz * 10) / maxmult;

	dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
		 minmult/10, minmult%10, maxmult/10, maxmult%10);

-	if (fsb == -1) {
-		printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
-		return -EINVAL;
-	}
-
	highest_speed = calc_speed(maxmult);
	lowest_speed = calc_speed(minmult);
-	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
+	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n",
+		 fsb_kHz / 1000,
		 print_speed(lowest_speed/1000), 
		 print_speed(highest_speed/1000));

@@ -475,7 +402,7 @@ static void __init longhaul_setup_voltag
	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;
	}
@@ -553,7 +480,7 @@ static unsigned int longhaul_get(unsigne
{
	if (cpu)
		return 0;
-	return calc_speed(longhaul_get_cpu_mult());
+	return calc_speed(get_cpu_mult_eblcr());
}

static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
@@ -728,7 +655,7 @@ print_support_type:

	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
	policy->cpuinfo.transition_latency = 200000;	/* nsec */
-	policy->cur = calc_speed(longhaul_get_cpu_mult());
+	policy->cur = calc_speed(get_cpu_mult_eblcr());

	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
	if (ret)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] Longhaul - Don't use regs to obtain FSB frequency
@ 2006-12-13 22:38 Rafał Bilski
  2006-12-13 22:50 ` Dave Jones
  0 siblings, 1 reply; 5+ messages in thread
From: Rafał Bilski @ 2006-12-13 22:38 UTC (permalink / raw)
  To: Dave Jones; +Cc: cpufreq

Current code has a problem with FSB on "PowerSaver 1.0" 
CPU. FSB is incorrecly guessed (again) for mini PC by Ebox. 
There is 8x100MHz CPU with "Nehemiah" core. It is reported 
as 8x133MHz. Apparently Longhaul MSR isn't reliable source 
of information if it is RevisionID == 0 for anything else 
then max multiplier. We can't read 200MHz FSB from it nor 
from EBLCR_POWER_ON too. This driver is working only with 
multipliers. FSB frequency is only needed to calculate CPU 
f for Cpufreq core. At boot kernel is calculating processor 
frequency. We know the multiplier. In this way we have bus 
frequency with kHz precision.

Signed-off-by: Rafa³ Bilski <rafalbilski@interia.pl>

--- 

diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -54,7 +54,7 @@

static int cpu_model;
static unsigned int numscales=16;
-static unsigned int fsb;
+static unsigned int fsb_kHz;

static struct mV_pos *vrm_mV_table;
static unsigned char *mV_vrm_table;
@@ -109,15 +109,14 @@ static char *print_speed(int speed)
static unsigned int calc_speed(int mult)
{
	int khz;
-	khz = (mult/10)*fsb;
+	khz = (mult/10)*fsb_kHz;
	if (mult%10)
-		khz += fsb/2;
-	khz *= 1000;
+		khz += fsb_kHz/2;
	return khz;
}


-static int longhaul_get_cpu_mult(void)
+static int get_cpu_mult_eblcr(void)
{
	unsigned long invalue=0,lo, hi;

@@ -226,14 +225,14 @@ static void longhaul_setstate(unsigned i
	if ((speed > highest_speed) || (speed < lowest_speed))
		return;

-	freqs.old = calc_speed(longhaul_get_cpu_mult());
+	freqs.old = calc_speed(get_cpu_mult_eblcr());
	freqs.new = speed;
	freqs.cpu = 0; /* longhaul.c is UP only driver */

	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);

	dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
-			fsb, mult/10, mult%10, print_speed(speed/1000));
+			fsb_kHz/1000, mult/10, mult%10, print_speed(speed/1000));

	preempt_disable();
	local_irq_save(flags);
@@ -303,60 +302,16 @@ static void longhaul_setstate(unsigned i
	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}

-/*
- * Centaur decided to make life a little more tricky.
- * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
- * Samuel2 and above have to try and guess what the FSB is.
- * We do this by assuming we booted at maximum multiplier, and interpolate
- * between that value multiplied by possible FSBs and cpu_mhz which
- * was calculated at boot time. Really ugly, but no other way to do this.
- */
-
-#define ROUNDING	0xf
-
-static int _guess(int guess)
-{
-	int target;
-
-	target = ((maxmult/10)*guess);
-	if (maxmult%10 != 0)
-		target += (guess/2);
-	target += ROUNDING/2;
-	target &= ~ROUNDING;
-	return target;
-}
-
-
-static int guess_fsb(void)
-{
-	int speed = (cpu_khz/1000);
-	int i;
-	int speeds[3] = { 66, 100, 133 };
-
-	speed += ROUNDING/2;
-	speed &= ~ROUNDING;
-
-	for (i=0; i<3; i++) {
-		if (_guess(speeds[i]) == speed)
-			return speeds[i];
-	}
-	return 0;
-}
-
-
static int __init longhaul_get_ranges(void)
{
	unsigned long invalue;
-	unsigned int ezra_t_multipliers[32]= {
+	unsigned int longhaul_multipliers[32]= {
			90,  30,  40, 100,  55,  35,  45,  95,
			50,  70,  80,  60, 120,  75,  85,  65,
			-1, 110, 120,  -1, 135, 115, 125, 105,
			130, 150, 160, 140,  -1, 155,  -1, 145 };
	unsigned int j, k = 0;
	union msr_longhaul longhaul;
-	unsigned long lo, hi;
-	unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 };
-	unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 };

	switch (longhaul_version) {
	case TYPE_LONGHAUL_V1:
@@ -364,71 +319,43 @@ static int __init longhaul_get_ranges(vo
		/* Ugh, Longhaul v1 didn't have the min/max MSRs.
		   Assume min=3.0x & max = whatever we booted at. */
		minmult = 30;
-		maxmult = longhaul_get_cpu_mult();
-		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
-		invalue = (lo & (1<<18|1<<19)) >>18;
-		if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2)
-			fsb = eblcr_fsb_table_v1[invalue];
-		else
-			fsb = guess_fsb();
+		maxmult = get_cpu_mult_eblcr();
		break;

	case TYPE_POWERSAVER:
-		/* Ezra-T */
-		if (cpu_model==CPU_EZRA_T) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-			invalue = longhaul.bits.MaxMHzBR;
-			if (longhaul.bits.MaxMHzBR4)
-				invalue += 16;
-			maxmult=ezra_t_multipliers[invalue];
-
+		rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+		invalue = longhaul.bits.MaxMHzBR;
+		if (longhaul.bits.MaxMHzBR4)
+			invalue += 16;
+		maxmult = longhaul_multipliers[invalue];
+		/* Ezra-T
+		 * PowerSaver 2.0 - bus ratio and voltage scaling
+		 * Valid: MinMHzBR, MaxMHzBR, MinMHzFSB, MaxMHzFSB,
+		 * 	  MinVID, MaxVID, VRMRev */
+		if (longhaul.bits.RevisionID > 0) {
			invalue = longhaul.bits.MinMHzBR;
			if (longhaul.bits.MinMHzBR4 == 1)
				minmult = 30;
			else
-				minmult = ezra_t_multipliers[invalue];
-			fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
-		}
-
-		/* Nehemiah */
-		if (cpu_model==CPU_NEHEMIAH) {
-			rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
-			/*
-			 * TODO: This code works, but raises a lot of questions.
-			 * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
-			 *   We get around this by using a hardcoded multiplier of 4.0x
-			 *   for the minimimum speed, and the speed we booted up at for the max.
-			 *   This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
-			 * - According to some VIA documentation EBLCR is only
-			 *   in pre-Nehemiah C3s. How this still works is a mystery.
-			 *   We're possibly using something undocumented and unsupported,
-			 *   But it works, so we don't grumble.
-			 */
-			minmult=40;
-			maxmult=longhaul_get_cpu_mult();
-
-			/* Starting with the 1.2GHz parts, theres a 200MHz bus. */
-			if ((cpu_khz/maxmult) > 13400)
-				fsb = 200;
-			else
-				fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
+				minmult = longhaul_multipliers[invalue];
+		/* Nehemiah
+		 * PowerSaver 1.0 - bus ratio scaling
+		 * Valid: MaxMHzBR */
+		} else {
+			minmult = 40;
		}
+		break;
	}
+	/* Kernel already knows true FSB speed */
+	fsb_kHz = (cpu_khz * 10) / maxmult;

	dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
		 minmult/10, minmult%10, maxmult/10, maxmult%10);

-	if (fsb == -1) {
-		printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
-		return -EINVAL;
-	}
-
	highest_speed = calc_speed(maxmult);
	lowest_speed = calc_speed(minmult);
-	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
+	dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n",
+		 fsb_kHz / 1000,
		 print_speed(lowest_speed/1000), 
		 print_speed(highest_speed/1000));

@@ -475,7 +402,7 @@ static void __init longhaul_setup_voltag
	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;
	}
@@ -553,7 +480,7 @@ static unsigned int longhaul_get(unsigne
{
	if (cpu)
		return 0;
-	return calc_speed(longhaul_get_cpu_mult());
+	return calc_speed(get_cpu_mult_eblcr());
}

static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
@@ -728,7 +655,7 @@ print_support_type:

	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
	policy->cpuinfo.transition_latency = 200000;	/* nsec */
-	policy->cur = calc_speed(longhaul_get_cpu_mult());
+	policy->cur = calc_speed(get_cpu_mult_eblcr());

	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
	if (ret)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Longhaul - Don't use regs to obtain FSB frequency
  2006-12-13 22:38 [PATCH] Longhaul - Don't use regs to obtain FSB frequency Rafał Bilski
@ 2006-12-13 22:50 ` Dave Jones
  2006-12-13 23:22   ` Rafał Bilski
  0 siblings, 1 reply; 5+ messages in thread
From: Dave Jones @ 2006-12-13 22:50 UTC (permalink / raw)
  To: Rafał Bilski; +Cc: Dave Jones, cpufreq

On Wed, Dec 13, 2006 at 11:38:18PM +0100, Rafał Bilski wrote:
 > Current code has a problem with FSB on "PowerSaver 1.0" 
 > CPU. FSB is incorrecly guessed (again) for mini PC by Ebox. 
 > There is 8x100MHz CPU with "Nehemiah" core. It is reported 
 > as 8x133MHz. Apparently Longhaul MSR isn't reliable source 
 > of information if it is RevisionID == 0 for anything else 
 > then max multiplier. We can't read 200MHz FSB from it nor 
 > from EBLCR_POWER_ON too. This driver is working only with 
 > multipliers. FSB frequency is only needed to calculate CPU 
 > f for Cpufreq core. At boot kernel is calculating processor 
 > frequency. We know the multiplier. In this way we have bus 
 > frequency with kHz precision.

I'm puzzled.  This description talks exclusively about Nehemiah,
and yet it's making changes to code only run by the pre-Nehemiah cores.
This makes me especially nervous as those chips don't get a
great deal of testing any more, and we typically learn that we
broke them months after making changes.

Has this been tested on anything other than the system mentioned above?
It seems like huge potential for regressions here, due to the size
and impact of the changes.

		Dave

-- 
http://www.codemonkey.org.uk

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Longhaul - Don't use regs to obtain FSB frequency
  2006-12-13 22:50 ` Dave Jones
@ 2006-12-13 23:22   ` Rafał Bilski
  0 siblings, 0 replies; 5+ messages in thread
From: Rafał Bilski @ 2006-12-13 23:22 UTC (permalink / raw)
  To: Dave Jones; +Cc: cpufreq

> On Wed, Dec 13, 2006 at 11:38:18PM +0100, Rafa³ Bilski wrote:
>  > Current code has a problem with FSB on "PowerSaver 1.0" 
>  > CPU. FSB is incorrecly guessed (again) for mini PC by Ebox. 
>  > There is 8x100MHz CPU with "Nehemiah" core. It is reported 
>  > as 8x133MHz. Apparently Longhaul MSR isn't reliable source 
>  > of information if it is RevisionID == 0 for anything else 
>  > then max multiplier. We can't read 200MHz FSB from it nor 
>  > from EBLCR_POWER_ON too. This driver is working only with 
>  > multipliers. FSB frequency is only needed to calculate CPU 
>  > f for Cpufreq core. At boot kernel is calculating processor 
>  > frequency. We know the multiplier. In this way we have bus 
>  > frequency with kHz precision.
> 
> I'm puzzled.  This description talks exclusively about Nehemiah,
> and yet it's making changes to code only run by the pre-Nehemiah cores.
> This makes me especially nervous as those chips don't get a
> great deal of testing any more, and we typically learn that we
> broke them months after making changes.
Well. I don't see a reason for not making this change. It is even more 
compatible with older CPU's, because EBL_CR_POWERON is returning current 
multiplier. And according to Your comments in source it isn't good to 
depend on EBL_CR_POWERON for "PowerSaver" CPU's. Why guess FSB if 
kernel calculated it at boot? In this way it is much simplier. Only 
possible bug is for "PowerSaver" processor running at lower multiplier 
then max.
My point is: can't use EBL_CR_POWERON FSB bits, nor Longhaul MSR FSB bits, 
for "Powersaver" - don't use it at all for any CPU. Find the way that will 
work for all of them.
> Has this been tested on anything other than the system mentioned above?
> It seems like huge potential for regressions here, due to the size
> and impact of the changes.
It has been tested on my Epia M-10000, system mentioned above and two 
Epia SP-13000. I'm currently exchanging e-mails with user who has 
Ezra with "Longhaul ver. 2" connected to SIS630 chipset. Version 2 seems 
to have only max BR bits - same as "Powersaver 1.0". I was planing to use 
same code for V2. I'm not sure yet if Longhaul version 2 can use ACPI C3 
to change frequency.
> 
> 		Dave
Rafa³


----------------------------------------------------------------------
smieszne, muzyka, pilka, sexy, kibice, kino, ciekawe, extreme, kabaret
http://link.interia.pl/f19d4 - najlepsze filmy w intermecie

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-12-13 23:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-13 22:38 [PATCH] Longhaul - Don't use regs to obtain FSB frequency Rafał Bilski
2006-12-13 22:50 ` Dave Jones
2006-12-13 23:22   ` Rafał Bilski
  -- strict thread matches above, loose matches on Subject: below --
2006-12-13 22:28 Rafał Bilski
2006-12-03 16:17 Rafał Bilski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.