All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Longhaul - Use information from Longhaul
@ 2006-07-09  9:53 Rafał Bilski
  2006-07-09 19:00 ` Dave Jones
  0 siblings, 1 reply; 8+ messages in thread
From: Rafał Bilski @ 2006-07-09  9:53 UTC (permalink / raw)
  To: Dave Jones; +Cc: cpufreq

First. I lost very important line in do_powersaver. Again. Sorry.

Longhaul don't report minimum multiplier. It reports minimum frequency.
So not always minimum multiplier at minimum FSB is really minimum.
This is most important for Nehemiah witch allows FSB 66MHz, 100MHz and 
133MHz. Ezra seems to support only 100MHz and 133MHz so in this case 
minimum multiplier at min FSB reported is in fact minimum PLL multiplier.
So we are testing against min/max frequency. Minimum PLL multiplier is 
from clock_ratio table. If processor will report multiplier less then 
5.0 then reported multiplier will be added to clock_ratio table.

Looks like all VIA CPUs allow to read FSB frequency from EBL_CR_POWERON.
Only some have 66MHz reserved.

More precise speed calculations. This is bad when kernel first reports 
999MHz and we are saying later that max is 997MHz.

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

---

--- linux-2.6.17-git20/arch/i386/kernel/cpu/cpufreq/longhaul.c.orig	2006-07-08 22:21:35.000000000 +0200
+++ linux-2.6.17-git20/arch/i386/kernel/cpu/cpufreq/longhaul.c	2006-07-09 11:14:17.000000000 +0200
@@ -53,11 +53,12 @@
 
 static int cpu_model;
 static unsigned int numscales=16, numvscales;
-static unsigned int fsb;
+static unsigned int fsb, fsb_min;
 static int minvid, maxvid;
 static unsigned int minmult, maxmult;
 static int can_scale_voltage;
 static int vrmrev;
+static int old_speed;
 static struct acpi_processor *pr = NULL;
 static struct acpi_processor_cx *cx = NULL;
 
@@ -98,12 +99,10 @@ static char *print_speed(int speed)
 #endif
 
 
-static unsigned int calc_speed(int mult)
+static unsigned int calc_speed(int mult, int fsb)
 {
 	int khz;
-	khz = (mult/10)*fsb;
-	if (mult%10)
-		khz += fsb/2;
+	khz = (mult * fsb + 50) / 100;
 	khz *= 1000;
 	return khz;
 }
@@ -162,6 +161,7 @@ static void do_powersaver(int cx_address
 	longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
 	longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
 	longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+	longhaul.bits.EnableSoftBusRatio = 1;
 
 	/* Sync to timer tick */
 	safe_halt();
@@ -193,23 +193,20 @@ static void longhaul_setstate(unsigned i
 {
 	int speed, mult;
 	struct cpufreq_freqs freqs;
-	static unsigned int old_ratio=-1;
 	unsigned long flags;
 	unsigned int pic1_mask, pic2_mask;
 
-	if (old_ratio == clock_ratio_index)
-		return;
-	old_ratio = clock_ratio_index;
-
 	mult = clock_ratio[clock_ratio_index];
 	if (mult == -1)
 		return;
 
-	speed = calc_speed(mult);
-	if ((speed > highest_speed) || (speed < lowest_speed))
+	speed = calc_speed(mult, fsb);
+	if ( (speed == old_speed)
+		|| (speed > highest_speed)
+		|| (speed < lowest_speed) )
 		return;
 
-	freqs.old = calc_speed(longhaul_get_cpu_mult());
+	freqs.old = old_speed;
 	freqs.new = speed;
 	freqs.cpu = 0; /* longhaul.c is UP only driver */
 
@@ -275,46 +272,7 @@ static void longhaul_setstate(unsigned i
 	preempt_enable();
 
 	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;
+	old_speed = speed;
 }
 
 
@@ -327,8 +285,8 @@ static int __init longhaul_get_ranges(vo
 	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 };
+	unsigned int eblcr_fsb_table_v1[] = { 666, 1332, 999, -1 };
+	unsigned int eblcr_fsb_table_v2[] = { 1332, 999, 1998, 666 };
 
 	switch (longhaul_version) {
 	case TYPE_LONGHAUL_V1:
@@ -339,73 +297,52 @@ static int __init longhaul_get_ranges(vo
 		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();
+		fsb_min = fsb = eblcr_fsb_table_v1[invalue];
+		printk (KERN_INFO PFX "CPU don't have the min/max MSRs.\n");
 		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=multipliers[invalue];
-
-			invalue = longhaul.bits.MinMHzBR;
-			if (longhaul.bits.MinMHzBR4 == 1)
-				minmult = 30;
-			else
-				minmult = multipliers[invalue];
-			fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
-		}
+		rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
 
-		/* 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/1000) > 1200)
-				fsb = 200;
-			else
-				fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
-			break;
-		}
-	}
+		invalue = longhaul.bits.MaxMHzBR;
+		if (longhaul.bits.MaxMHzBR4)
+			invalue += 16;
+		maxmult = multipliers[invalue];
+
+		invalue = longhaul.bits.MinMHzBR;
+		if (longhaul.bits.MinMHzBR4 == 1)
+			minmult = 30;
+		else
+			minmult = multipliers[invalue];
 
-	dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
-		 minmult/10, minmult%10, maxmult/10, maxmult%10);
+		if (minmult <= 45) clock_ratio[6] = 45;
+		if (minmult <= 40) clock_ratio[2] = 40;
+		if (minmult <= 35) clock_ratio[5] = 35;
+		if (minmult == 30) clock_ratio[1] = 30;
+
+		fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
+		fsb_min = eblcr_fsb_table_v2[longhaul.bits.MinMHzFSB];
+		break;
+	}
 
 	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,
-		 print_speed(lowest_speed/1000), 
-		 print_speed(highest_speed/1000));
+	highest_speed = calc_speed(maxmult, fsb);
+	lowest_speed = calc_speed(minmult, fsb_min);
+ 	printk(KERN_INFO PFX "Maximum frequency = %dMHz (%d.%d x %dMHz)\n",
+		 highest_speed/1000,
+		 maxmult/10, maxmult%10,
+		 fsb/10);
+ 	printk(KERN_INFO PFX "Minimum frequency = %dMHz (%d.%d x %dMHz)\n",
+		 lowest_speed/1000,
+		 minmult/10, minmult%10,
+		 fsb_min/10);
 
 	if (lowest_speed == highest_speed) {
-		printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");
+		printk (KERN_INFO PFX "highest speed == lowest, aborting.\n");
 		return -EINVAL;
 	}
 	if (lowest_speed > highest_speed) {
@@ -418,14 +355,15 @@ static int __init longhaul_get_ranges(vo
 	if(!longhaul_table)
 		return -ENOMEM;
 
-	for (j=0; j < numscales; j++) {
-		unsigned int ratio;
+	for (j = 0; j < numscales; j++) {
+		unsigned int ratio, speed;
 		ratio = clock_ratio[j];
 		if (ratio == -1)
 			continue;
-		if (ratio > maxmult || ratio < minmult)
+		speed = calc_speed(ratio, fsb);
+		if (speed > highest_speed || speed < lowest_speed)
 			continue;
-		longhaul_table[k].frequency = calc_speed(ratio);
+		longhaul_table[k].frequency = speed;
 		longhaul_table[k].index	= j;
 		k++;
 	}
@@ -521,7 +459,7 @@ static unsigned int longhaul_get(unsigne
 {
 	if (cpu)
 		return 0;
-	return calc_speed(longhaul_get_cpu_mult());
+	return calc_speed(longhaul_get_cpu_mult(), fsb);
 }
 
 acpi_status longhaul_walk_callback(acpi_handle obj_handle,
@@ -652,7 +590,7 @@ static int __init longhaul_cpu_init(stru
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 200000;	/* nsec */
-	policy->cur = calc_speed(longhaul_get_cpu_mult());
+	policy->cur = old_speed = calc_speed(longhaul_get_cpu_mult(), fsb);
 
 	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
 	if (ret)

------------------------------------------------------------------------
Znajdz krotsza droge do pracy!
http://map24.interia.pl/ - interaktywny planer podrozy.

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

end of thread, other threads:[~2006-07-10 14:28 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-09  9:53 [PATCH] Longhaul - Use information from Longhaul Rafał Bilski
2006-07-09 19:00 ` Dave Jones
2006-07-09 19:47   ` Rafał Bilski
2006-07-09 20:08   ` Rafał Bilski
2006-07-09 21:00     ` Dave Jones
2006-07-09 21:45       ` Rafał Bilski
2006-07-10  5:45       ` Rafał Bilski
2006-07-10 14:28         ` Dave Jones

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.