linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test
@ 2003-11-10  0:33 Tony Lindgren
  2003-11-10  6:01 ` Peter Gantner
  0 siblings, 1 reply; 3+ messages in thread
From: Tony Lindgren @ 2003-11-10  0:33 UTC (permalink / raw)
  To: linux-kernel; +Cc: pasi.savolainen, Charles Lepple, f.maibaum, peter.gantner

[-- Attachment #1: Type: text/plain, Size: 1431 bytes --]

Hi all,

I've done some more cleanup on the amd76x_pm module. Looks like Pasi and
I both did pretty much the same changes last time independently, but Pasi
chopped off even more unnecessary code. So I've continued the cleanup based
on Pasi's code.

I've done some cleanup to remove my old comments and to get rid of all 
the ifdefs. This makes the code more readable and makes it easier to
develop. I've also changed the functions around a bit to group them
better, and changed variable naming to be more standard. I've only edited
the amd76x_pm.c file, and did not do any functional changes. Just cleanup.

On the clock skew problem, it's still there, and to figure out how bad the
problem is, I've done a little shell script based on the earlier thread on
adjtimex on this mailing list. You can get the skewtest.sh from:

http://www.muru.com/linux/amd-smp-idle/skewtest.sh

On my S2460 system with a pair of Athlon 1400's I get the following results:

                            suggested tick
Without amd76x_pm module:   10002
With amd76x_pm module:      between 9952 - 9977

I guess some people see much worse skew on some systems? Can you please 
run the skewtest.sh and post some results, thanks.

Following is the current patch, you can also get it from:

http://www.muru.com/linux/amd-smp-idle/

I may not have access to my Athlon box for next few weeks, but hopefully 
Pasi keeps maintaining the module as needed.

Tony


[-- Attachment #2: linux-2.6-amd76x_pm-20031109.patch --]
[-- Type: text/plain, Size: 22539 bytes --]

diff -Nru linux-2.6.0-test9/drivers/acpi/Kconfig kt9/drivers/acpi/Kconfig
diff -Nru linux-2.6.0-test9/drivers/acpi/Kconfig kt9/drivers/acpi/Kconfig
--- linux-2.6.0-test9/drivers/acpi/Kconfig	2003-10-11 12:36:19.000000000 +0300
+++ kt9/drivers/acpi/Kconfig	2003-10-26 13:06:00.000000000 +0200
@@ -269,5 +269,21 @@
 	  particular, many Toshiba laptops require this for correct operation
 	  of the AC module.
 
-endmenu
+config AMD76X_PM
+        tristate "AMD76x Native Power Management support"
+	default n
+        depends on X86 && PCI
+        ---help---
+          This driver enables Power Management on AMD760MP & AMD760MPX chipsets.
+	  This is about same as ACPI C2, except that ACPI folks don't do SMP ATM.
+	  In /sys/devices/pci0/0000:00:00.0/ is a statistics C2_cnt
+	  (RO) and lazy_idle (RW) file.
+
+	  To compile this driver as a module ( = code which can be inserted in
+	  and removed from the running kernel whenever you want), say M here
+	  and read <file:Documentation/modules.txt>. The module will be called
+	  amd76x_pm.
 
+	  If unsure, say N.
+
+endmenu
diff -Nru linux-2.6.0-test9/drivers/acpi/Makefile kt9/drivers/acpi/Makefile
diff -Nru linux-2.6.0-test9/drivers/acpi/Makefile kt9/drivers/acpi/Makefile
--- linux-2.6.0-test9/drivers/acpi/Makefile	2003-10-11 12:36:19.000000000 +0300
+++ kt9/drivers/acpi/Makefile	2003-10-26 13:06:00.000000000 +0200
@@ -48,3 +48,8 @@
 obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 obj-$(CONFIG_ACPI_BUS)		+= scan.o 
+
+#
+# not really ACPI thing, until they handle SMP.
+#
+obj-$(CONFIG_AMD76X_PM)		+= amd76x_pm.o
--- /dev/null	1969-12-31 16:00:00.000000000 -0800
+++ linux/include/linux/amd76x_pm.h	2003-11-04 12:43:25.000000000 -0800
@@ -0,0 +1,59 @@
+/* 
+ * Begin 765/766
+ */
+/* C2/C3/POS options in C3A50, page 63 in AMD-766 doc */
+#define ZZ_CACHE_EN	1
+#define DCSTOP_EN	(1 << 1)
+#define STPCLK_EN	(1 << 2)
+#define CPUSTP_EN	(1 << 3)
+#define PCISTP_EN	(1 << 4)
+#define CPUSLP_EN	(1 << 5)
+#define SUSPND_EN	(1 << 6)
+#define CPURST_EN	(1 << 7)
+
+#define C2_REGS		0
+#define C3_REGS		8
+#define POS_REGS	16	
+/*
+ * End 765/766
+ */
+
+
+/*
+ * Begin 768
+ */
+/* C2/C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+#define C2EN		1
+#define C3EN		(1 << 1)
+#define ZZ_C3EN		(1 << 2)
+#define CSLP_C3EN	(1 << 3)
+#define CSTP_C3EN	(1 << 4)
+
+/* POS options in DevB:3x50, page 101 in AMD-768 doc */
+#define POSEN	1
+#define CSTP	(1 << 2)
+#define PSTP	(1 << 3)
+#define ASTP	(1 << 4)
+#define DCSTP	(1 << 5)
+#define CSLP	(1 << 6)
+#define SUSP	(1 << 8)
+#define MSRSM	(1 << 14)
+#define PITRSM	(1 << 15)
+
+/* NTH options DevB:3x40, pg 93 of 768 doc */
+#define NTPER(x) (x << 3)
+#define THMINEN(x) (x << 4)
+
+/*
+ * End 768
+ */
+
+/* NTH activate. PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+#define NTH_RATIO(x) (x << 1)
+#define NTH_EN (1 << 4)
+
+/* Sleep state. PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+#define SLP_EN (1 << 13)
+#define SLP_TYP(x) (x << 10)
+
+#define LAZY_IDLE_DELAY	800	/* 0: Best savings,  3000: More responsive */
--- /dev/null	1969-12-31 16:00:00.000000000 -0800
+++ linux/drivers/acpi/amd76x_pm.c	2003-11-09 14:30:53.000000000 -0800
@@ -0,0 +1,672 @@
+/*
+ * ACPI style PM for SMP AMD-760MP(X) based systems.
+ * For use until the ACPI project catches up. :-)
+ *
+ * Copyright (C) 2002 Tony Lindgren <tony@atomide.com>
+ * Copyright (C) 2002 Johnathan Hicks <thetech@folkwolf.net>
+ * Copyright (C) 2003 Pasi Savolainen
+ *
+ * HISTORY
+ * 
+ *   20020702 - amd-smp-idle: Tony Lindgren <tony@atomide.com>
+ *	Influenced by Vcool, and LVCool. Rewrote everything from scratch to
+ *	use the PCI features in Linux, and to support SMP systems. Provides
+ *	C2 idling on SMP AMD-760MP systems.
+ *	
+ *   20020722: JH
+ *   	I adapted Tony's code for the AMD-765/766 southbridge and adapted it
+ *   	according to the AMD-768 data sheet to provide the same capability for
+ *   	SMP AMD-760MPX systems. Posted to acpi-devel list.
+ *   	
+ *   20020722: Alan Cox
+ *   	Replaces non-functional amd76x_pm code in -ac tree.
+ *   	
+ *   20020730: JH
+ *   	Added ability to do normal throttling (the non-thermal kind), C3 idling
+ *   	and Power On Suspend (S1 sleep). It would be very easy to tie swsusp
+ *   	into activate_amd76x_slp(). C3 idling doesn't happen yet; see my note
+ *   	in amd76x_smp_idle(). I've noticed that when NTH and idling are both
+ *   	enabled, my hardware locks and requires a hard reset, so I have
+ *   	#ifndefed around the idle loop setting to prevent this. POS locks it up
+ *   	too, both ought to be fixable. I've also noticed that idling and NTH
+ *   	make some interference that is picked up by the onboard sound chip on
+ *   	my ASUS A7M266-D motherboard.
+ *
+ *   20030601: Pasi Savolainen
+ *      Simple port to 2.5
+ *      Added sysfs interface for making nice graphs with mrtg.
+ *      Look for /sys/devices/pci0/00:00.0/c2_cnt & lazy_idle (latter writable)
+ *
+ *   20031026: Pasi Savolainen
+ *      Removed unnecessary PCI code that caused problems with other modules
+ *
+ *   20031109: Tony Lindgren
+ *      Got rid of the ifdefs, reorganized the code to make it more readable
+ *      for further changes. Cleaned my old comments away, added comments on 
+ *      known problems. No functional changes done.
+ * 
+ * TODO 
+ *
+ * - Thermal throttling (TTH).
+ * - /sys interface for normal throttling level.
+ * - /sys interface for POS.
+ *
+ * NOTES
+ *
+ * Using this module saves about 70 - 90W of energy in the idle mode compared
+ * to the default idle mode. Waking up from the idle mode is fast to keep the
+ * system response time good. Currently no CPU load calculation is done, the
+ * system exits the idle mode if the idle function runs twice on the same
+ * processor in a row. This only works on SMP systems, but maybe the idle mode
+ * enabling can be integrated to ACPI to provide C2 mode at some point.
+ *
+ * At least the following systems are known to work: TYAN S2460, ASUS A7M266-D.
+ *
+ * KNOWN PROBLEMS
+ *
+ * - System goes into sleep mode on S2460 when the driver is compiled in and
+ *   loaded before other ACPI initializations. The system wakes up from an
+ *   ACPI interrupt at this point, such as pressing the power button once.
+ *   Current workaround is to load amd76x_pm as module.
+ *
+ * - System clock skew on certain systems. This seems to be fixed on
+ *   2.6.0-test9 for most part, but still appears on some systems. This may 
+ *   be caused by out of sync TSCs. This problem may also be related to
+ *   spurious interrupts on line 9 (ACPI). Dropping HZ to 100 is the current
+ *   workaround for this problem.
+ *
+ * This software is licensed under GNU General Public License Version 2 
+ * as specified in file COPYING in the Linux kernel source tree main 
+ * directory.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+
+#include <linux/amd76x_pm.h>
+
+#define VERSION	"20031109"
+
+/* Experimental code for future ACPI throttling */
+//#define AMD76X_C3
+//#define AMD76X_NTH
+//#define AMD76X_POS
+
+/* Have the compiler optimize away these functions if not used */
+#ifdef AMD76X_C3
+#define use_amd76x_c3()		1
+#else
+#define use_amd76x_c3()		0
+#endif
+
+#ifdef AMD76X_NTH
+#define use_amd76x_nth()	1
+#else
+#define use_amd76x_nth()	0
+#endif
+
+#ifdef AMD76X_POS
+#define use_amd76x_pos()	1
+#else
+#define use_amd76x_pos()	0
+#endif
+
+extern void default_idle(void);
+static void amd76x_smp_idle(void);
+static int amd76x_pm_main(void);
+
+unsigned long lazy_idle = 0;
+MODULE_PARM(lazy_idle, "l");
+
+static struct pci_dev *pdev_nb;
+static struct pci_dev *pdev_sb;
+
+struct PM_cfg {
+	unsigned int status_reg;
+	unsigned int c2_reg;
+	unsigned int c3_reg;
+	unsigned int nth_reg;
+	unsigned int slp_reg;
+	unsigned int resume_reg;
+	void (*orig_idle) (void);
+	void (*curr_idle) (void);
+	unsigned long c2_cnt, c3_cnt, idle_cnt;
+	int last_pr;
+};
+
+static struct PM_cfg amd76x_pm_cfg;
+
+struct cpu_idle_state {
+	int idle;
+	int count;
+};
+static struct cpu_idle_state prs[2];
+
+static struct pci_device_id  __devinitdata amd_nb_tbl[] = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+static struct pci_device_id  __devinitdata amd_sb_tbl[] = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+/*
+ * Get the base PMIO address and set the pm registers in amd76x_pm_cfg.
+ */
+static void
+amd76x_get_pm(void)
+{
+	unsigned int regdword;
+
+	/* Get the address for pm status, P_LVL2, etc */
+	pci_read_config_dword(pdev_sb, 0x58, &regdword);
+	regdword &= 0xff80;
+	amd76x_pm_cfg.status_reg = (regdword + 0x00);
+	amd76x_pm_cfg.slp_reg =    (regdword + 0x04);
+	amd76x_pm_cfg.nth_reg =    (regdword + 0x10);
+	amd76x_pm_cfg.c2_reg =     (regdword + 0x14);
+	amd76x_pm_cfg.c3_reg =     (regdword + 0x15);
+	amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */
+}
+
+/*
+ * En/Disable PMIO and configure W4SG & STPGNT.
+ */
+static int
+config_pmio_amd76x(int is_766, int enable)
+{
+	unsigned char regbyte;
+
+	/* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well.
+	 * AMD-766: C3A41; page 59 in AMD-766 doc
+	 * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x41, &regbyte);
+	if (enable) {
+		regbyte |= ((is_766 << 1) | (1 << 7));
+	}
+	pci_write_config_byte(pdev_sb, 0x41, regbyte);
+	return 0;
+}
+
+/*
+ * C2 idle support for AMD-766.
+ */
+static void
+config_amd766_c2(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C2 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if (enable) {
+		regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
+					CPURST_EN) << C2_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN)	/* Additional ~ 70 Watts max! */
+			 << C2_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+/*
+ * C2 idling support for AMD-768.
+ */
+static void
+config_amd768_c2(int enable)
+{
+	unsigned char regbyte;
+
+	/* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if (enable)
+		regbyte |= C2EN;
+	else
+		regbyte ^= C2EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+
+/*
+ * Untested C3 idle support for AMD-766.
+ */
+static void
+config_amd766_c3(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if (enable) {
+		regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
+				<< C3_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN	/* Additional ~ 70 Watts max! */
+			 |  CPUSTP_EN)	/* yet more savings! */
+			 << C3_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+/*
+ * C3 idle support for AMD-768. The idle loop would need some extra
+ * handling for C3, but it would make more sense for ACPI to handle CX level
+ * transitions like it is supposed to. Unfortunately ACPI doesn't do CX
+ * levels on SMP systems yet.
+ */
+static void
+config_amd768_c3(int enable)
+{
+	unsigned char regbyte;
+
+	/* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if (enable)
+		regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */);
+	else
+		regbyte ^= C3EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+
+static void
+config_amd766_pos(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if (enable) {
+		regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
+		regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
+					CPUSLP_EN | SUSPND_EN) << POS_REGS);
+	}
+	else
+		regdword ^= (0xff << POS_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+/*
+ * Untested Power On Suspend support for AMD-768. This should also be handled
+ * by ACPI.
+ */
+static void
+config_amd768_pos(int enable)
+{
+	unsigned int regdword;
+
+	/* Set POS options in DevB:3x50, page 101 in AMD-768 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if (enable) 
+		regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
+	else
+		regdword ^= POSEN;
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+/*
+ * Normal Throttling support for AMD-768. There are several settings
+ * that can be set depending on how long you want some of the delays to be.
+ * I'm not sure if this is even neccessary at all as the 766 doesn't need this.
+ */
+static void
+config_amd768_nth(int enable, int ntper, int thminen)
+{
+	unsigned char regbyte;
+
+	/* DevB:3x40, pg 93 of 768 doc */
+	pci_read_config_byte(pdev_sb, 0x40, &regbyte);
+	/* Is it neccessary to use THMINEN at ANY time? */
+	regbyte |= (NTPER(ntper) | THMINEN(thminen));
+	pci_write_config_byte(pdev_sb, 0x40, regbyte);
+}
+
+/*
+ * Activate normal throttling via its ACPI register (P_CNT).
+ */
+static void
+activate_amd76x_nth(int enable, int ratio)
+{
+	unsigned int regdword;
+
+	/* PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+	regdword=inl(amd76x_pm_cfg.nth_reg);
+	if (enable)
+		regdword |= (NTH_EN | NTH_RATIO(ratio));
+	else
+		regdword ^= NTH_EN;
+	outl(regdword, amd76x_pm_cfg.nth_reg);
+}
+
+/*
+ * Activate sleep state via its ACPI register (PM1_CNT).
+ */
+static void
+activate_amd76x_slp(int type)
+{
+	unsigned short regshort;
+
+	/* PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+	regshort=inw(amd76x_pm_cfg.slp_reg);
+	regshort |= (SLP_EN | SLP_TYP(type)) ;
+	outw(regshort, amd76x_pm_cfg.slp_reg);
+}
+
+/*
+ * Wrapper function to activate POS sleep state.
+ */
+static void
+activate_amd76x_pos(void)
+{
+	activate_amd76x_slp(1);
+}
+
+/*
+ * Idle loop for single processor systems
+ */
+void
+amd76x_up_idle(void)
+{
+	/* ACPI knows how to do C2 on SMP when cpu_count < 2
+	 * we really shouldn't end up here anyway. 
+	 */
+	amd76x_pm_cfg.orig_idle();
+}
+
+/*
+ * Idle loop for SMP systems, supports currently only 2 processors.
+ *
+ * Note; for 2.5 folks - not pre-empt safe
+ */
+static void
+amd76x_smp_idle(void)
+{
+	/*
+	 * Exit idle mode immediately if the CPU does not change.
+	 * Usually that means that we have some load on another CPU.
+	 */
+	amd76x_pm_cfg.idle_cnt++;
+	if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
+		prs[0].idle = 0;
+		prs[1].idle = 0;
+		return;
+	}
+
+	prs[smp_processor_id()].count++;
+
+	/* Don't start the idle mode immediately */
+	if (prs[smp_processor_id()].count >= lazy_idle) {
+
+		/* Put the current processor into idle mode */
+		prs[smp_processor_id()].idle =
+			(prs[smp_processor_id()].idle ? 2 : 1);
+
+		/* Only idle if both processors are idle */
+		if ((prs[0].idle==1) && (prs[1].idle==1)) {
+			amd76x_pm_cfg.c2_cnt++;
+			inb(amd76x_pm_cfg.c2_reg);
+		} else if (use_amd76x_c3() && (prs[0].idle==2) && (prs[1].idle==2)) {
+			/*
+			 * JH: I've not been able to get into here. Could this have
+			 * something to do with the way the kernel handles the idle
+			 * loop, or and error that I've made?
+			 */
+			amd76x_pm_cfg.c3_cnt++;
+			inb(amd76x_pm_cfg.c3_reg);
+		}
+
+		prs[smp_processor_id()].count = 0;
+
+	}
+	amd76x_pm_cfg.last_pr = smp_processor_id();
+}
+
+/*
+ * Sysfs support, RW
+ */
+static ssize_t 
+show_lazy_idle (struct device *dev, char *buf)
+{
+    return sprintf(buf,"%lu\n", lazy_idle);  
+}
+
+static ssize_t         
+set_lazy_idle (struct device *dev, const char *buf, size_t count)
+{
+    lazy_idle = simple_strtoul(buf, NULL, 10);
+    return count;
+}
+
+static ssize_t 
+show_c2_cnt (struct device *dev, char *buf)
+{
+    return sprintf(buf,"%lu\n", amd76x_pm_cfg.c2_cnt);  
+}
+
+static ssize_t 
+show_idle_cnt (struct device *dev, char *buf)
+{
+    return sprintf(buf,"%lu\n", amd76x_pm_cfg.idle_cnt);  
+}
+
+static DEVICE_ATTR(lazy_idle, S_IRUGO | S_IWUSR,
+		   show_lazy_idle, set_lazy_idle);
+static DEVICE_ATTR(c2_cnt, S_IRUGO,
+		   show_c2_cnt, NULL);
+static DEVICE_ATTR(idle_cnt, S_IRUGO,
+		   show_idle_cnt, NULL);
+
+/*
+ * Configures the 765 & 766 southbridges.
+ */
+static int
+config_sb_amd766(int enable)
+{
+	amd76x_get_pm();
+	config_pmio_amd76x(1, 1);
+	config_amd766_c2(enable);
+
+	if (use_amd76x_c3())
+		config_amd766_c3(enable);
+
+	if (use_amd76x_pos())
+		config_amd766_pos(enable);
+
+	return 0;
+}
+
+/*
+ * Configures the 768 southbridge to support idle calls, and gets
+ * the processor idle call register location.
+ */
+static int
+config_sb_amd768(int enable)
+{
+	amd76x_get_pm();
+	config_pmio_amd76x(0, 1);
+	config_amd768_c2(enable);
+
+	if (use_amd76x_c3())
+		config_amd768_c3(enable);
+
+	if (use_amd76x_pos())
+		config_amd768_pos(enable);
+
+	if (use_amd76x_nth())
+		config_amd768_nth(enable, 1, 2);
+
+	return 0;
+}
+
+/*
+ * Configures the AMD-762 northbridge to support PM calls
+ */
+static int
+config_nb_amd762(int enable)
+{
+	unsigned int regdword;
+
+	/* Enable STPGNT in BIU Status/Control for cpu0 */
+	pci_read_config_dword(pdev_nb, 0x60, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x60, regdword);
+
+	/* Enable STPGNT in BIU Status/Control for cpu1 */
+	pci_read_config_dword(pdev_nb, 0x68, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x68, regdword);
+
+	/* DRAM refresh enable */
+	pci_read_config_dword(pdev_nb, 0x58, &regdword);
+	regdword &= ~(1 << 19);
+	pci_write_config_dword(pdev_nb, 0x58, regdword);
+
+	/* Self refresh enable */
+	pci_read_config_dword(pdev_nb, 0x70, &regdword);
+	regdword |= (1 << 18);
+	pci_write_config_dword(pdev_nb, 0x70, regdword);
+
+	return 0;
+}
+
+/*
+ * Finds and initializes the bridges, and then sets the idle function
+ */
+static int
+amd76x_pm_main(void)
+{
+	amd76x_pm_cfg.orig_idle = 0;
+	if (lazy_idle == 0)
+	    lazy_idle = LAZY_IDLE_DELAY;
+
+	/* Find southbridge */
+	pdev_sb = NULL;
+	while((pdev_sb = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev_sb)) != NULL) {
+		if (pci_match_device(amd_sb_tbl, pdev_sb) != NULL)
+			goto found_sb;
+	}
+	printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
+	return -ENODEV;
+
+ found_sb:
+
+	/* Find northbridge */
+	pdev_nb = NULL;
+	while((pdev_nb = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev_nb)) != NULL) {
+		if (pci_match_device(amd_nb_tbl, pdev_nb) != NULL)
+			goto found_nb;
+	}
+	printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
+	return -ENODEV;
+
+ found_nb:	
+	
+	/* Init southbridge */
+	switch (pdev_sb->device) {
+	case PCI_DEVICE_ID_AMD_VIPER_7413:	/* AMD-765 or 766 */
+		config_sb_amd766(1);
+		break;
+	case PCI_DEVICE_ID_AMD_VIPER_7443:	/* AMD-768 */
+		config_sb_amd768(1);
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n");		
+		break;
+	}
+
+	/* Init northbridge and queue the new idle function */
+	if (!pdev_nb) {
+		printk("amd76x_pm: No northbridge found.\n");
+		return -ENODEV;
+	}
+	switch (pdev_nb->device) {
+	case PCI_DEVICE_ID_AMD_FE_GATE_700C:	/* AMD-762 */
+		config_nb_amd762(1);
+
+		if (!use_amd76x_nth())
+			amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
+
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n");
+		break;
+	}
+
+	if (!use_amd76x_nth()) {
+		if (num_online_cpus() == 1) {
+			amd76x_pm_cfg.curr_idle = amd76x_up_idle;
+			printk(KERN_ERR "amd76x_pm: UP machine detected. Use ACPI\n");
+		}
+
+		if (!amd76x_pm_cfg.curr_idle) {
+			printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
+			return 1;
+		}
+
+		amd76x_pm_cfg.orig_idle = pm_idle;
+		pm_idle = amd76x_pm_cfg.curr_idle;
+		wmb();
+	
+		/* sysfs */
+		device_create_file(&pdev_nb->dev, &dev_attr_lazy_idle);
+		device_create_file(&pdev_nb->dev, &dev_attr_c2_cnt);
+		device_create_file(&pdev_nb->dev, &dev_attr_idle_cnt);
+	}
+
+	/* Turn NTH on with maxium throttling for testing. */
+	if (use_amd76x_nth())
+		activate_amd76x_nth(1, 1);
+
+	/* Testing here only. */
+	if (use_amd76x_pos())
+		activate_amd76x_pos();
+
+	return 0;
+}
+
+static int __init
+amd76x_pm_init(void)
+{
+	printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION);
+	return amd76x_pm_main();
+}
+
+static void __exit
+amd76x_pm_cleanup(void)
+{
+	if (!use_amd76x_nth()) {
+		pm_idle = amd76x_pm_cfg.orig_idle;
+		synchronize_kernel();
+
+		/* This isn't really needed. */
+		printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.c2_cnt);
+
+		if (use_amd76x_c3())
+			printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", 
+			       amd76x_pm_cfg.c3_cnt);
+
+		/* Remove sysfs */
+		device_remove_file(&pdev_nb->dev, &dev_attr_lazy_idle);
+		device_remove_file(&pdev_nb->dev, &dev_attr_c2_cnt);
+		device_remove_file(&pdev_nb->dev, &dev_attr_idle_cnt);
+	}
+
+	/* Turn NTH off*/
+	if (use_amd76x_nth())
+		activate_amd76x_nth(0, 0);
+}
+
+MODULE_LICENSE("GPL");
+module_init(amd76x_pm_init);
+module_exit(amd76x_pm_cleanup);
/* 
 * Begin 765/766
 */
/* C2/C3/POS options in C3A50, page 63 in AMD-766 doc */
#define ZZ_CACHE_EN	1
#define DCSTOP_EN	(1 << 1)
#define STPCLK_EN	(1 << 2)
#define CPUSTP_EN	(1 << 3)
#define PCISTP_EN	(1 << 4)
#define CPUSLP_EN	(1 << 5)
#define SUSPND_EN	(1 << 6)
#define CPURST_EN	(1 << 7)

#define C2_REGS		0
#define C3_REGS		8
#define POS_REGS	16	
/*
 * End 765/766
 */


/*
 * Begin 768
 */
/* C2/C3 options in DevB:3x4F, page 100 in AMD-768 doc */
#define C2EN		1
#define C3EN		(1 << 1)
#define ZZ_C3EN		(1 << 2)
#define CSLP_C3EN	(1 << 3)
#define CSTP_C3EN	(1 << 4)

/* POS options in DevB:3x50, page 101 in AMD-768 doc */
#define POSEN	1
#define CSTP	(1 << 2)
#define PSTP	(1 << 3)
#define ASTP	(1 << 4)
#define DCSTP	(1 << 5)
#define CSLP	(1 << 6)
#define SUSP	(1 << 8)
#define MSRSM	(1 << 14)
#define PITRSM	(1 << 15)

/* NTH options DevB:3x40, pg 93 of 768 doc */
#define NTPER(x) (x << 3)
#define THMINEN(x) (x << 4)

/*
 * End 768
 */

/* NTH activate. PM10, pg 110 of 768 doc, pg 70 of 766 doc */
#define NTH_RATIO(x) (x << 1)
#define NTH_EN (1 << 4)

/* Sleep state. PM04, pg 109 of 768 doc, pg 69 of 766 doc */
#define SLP_EN (1 << 13)
#define SLP_TYP(x) (x << 10)

#define LAZY_IDLE_DELAY	800	/* 0: Best savings,  3000: More responsive */

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

* Re: [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test
  2003-11-10  0:33 [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test Tony Lindgren
@ 2003-11-10  6:01 ` Peter Gantner
  2003-11-10 18:04   ` Tony Lindgren
  0 siblings, 1 reply; 3+ messages in thread
From: Peter Gantner @ 2003-11-10  6:01 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-kernel, pasi.savolainen, Charles Lepple, f.maibaum

Quoting Tony Lindgren from Nov 9

> On the clock skew problem, it's still there, and to figure out how bad the
> problem is, I've done a little shell script based on the earlier thread on
> adjtimex on this mailing list.

Here are my results from your script.

Tested two kernels, vanilla -test9 and test-9-love2, the latter is a 
patchset based off -mm2, including the nick scheduler and 
other stuff like reiser4 and bootsplash. More information about this 
here: http://bssteph.irtonline.org/linux/patches/2.6/2.6.0-test9/2.6.0-test9-love2/2.6.0-test9-love2_notes.txt
(amd76x_pm-031027 patch backed out, new one put in )

I did three runs each, first run idle, two runs under load, i.e. two
burnK7 processes and a make -j5 kernel compile just to make sure.
loadavg goes up to ~6.5 during those.
ntpd was not running during the tests.

System is an A7M266-d w/ two AthlonXPs 1800+ (model 6 stepping 2),
L5-modded(!) for the MP setup. (I know this is considered tainting,
if you can tell me the timing issues are related to the modding I
will shut up immediately, but so far nobody seems to have pinpointed 
it to this.)
The two CPUs show different bogomips (3014, 3063).


-------------------------------------------------
test9-love2:
-------------------------------------------------
idle:
-------------------------------------------------
Running test for kernel version 2.6.0-test9-love2
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439150       -0.014522      -0.014522   10000         0
1068439160       -0.015270      -0.000748   10000         0
1068439170       -0.016013      -0.000743   10000         0    10000   4869626
1068439180       -0.016753      -0.000740   10000         0    10000   4850095
1068439190       -0.017498      -0.000744   10000         0    10000   4876657
1068439200       -0.008564       0.008934   10000   4876657     9992  -1243667
1068439210       -0.008547       0.000017   10000   4876657    10000   4765814
1068439220       -0.008529       0.000018   10000   4876657    10000   4758783

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439230        0.009470       0.009470   10000         0
1068439240        0.008725      -0.000745   10000         0
1068439250        0.008987       0.000262   10000         0    10000  -1716312
1068439260        0.009249       0.000262   10000         0    10000  -1716311
1068439270        0.008507      -0.000742   10000         0    10000   4863376
1068439280        0.017441       0.008934   10000   4863375     9992  -1256949
1068439290        0.017461       0.000020   10000   4863375    10000   4732220
1068439300        0.017482       0.000021   10000   4863375    10000   4726751

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi

-------------------------------------------------
load - run 1
-------------------------------------------------

Running test for kernel version 2.6.0-test9-love2
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439375        0.035483       0.035483   10000         0
1068439385        0.034744      -0.000739   10000         0
1068439395        0.034002      -0.000742   10000         0    10000   4863376
1068439405        0.033272      -0.000730   10000         0    10000   4784470
1068439440        0.030695      -0.002577   10000         0    10003  -2773359
1068439450        0.041556       0.010861   10003  -2773359     9992  -1861789
1068439464        0.044119       0.002563   10003  -2773359    10000     92261
1068439475        0.046135       0.002016   10003  -2773359    10001  -2875039

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439488        0.063667       0.063667   10000         0
1068439498        0.062917      -0.000750   10000         0
1068439509        0.062106      -0.000810   10000         0    10000   5310651
1068439519        0.061371      -0.000735   10000         0    10000   4818064
1068439533        0.060339      -0.001032   10000         0    10001    211376
1068439548        0.069771       0.009432   10001    211376     9992  -2622097
1068439560        0.070127       0.000356   10001    211376    10001  -2123667
1068439571        0.070456       0.000329   10001    211376    10001  -1942035

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi
-------------------------------------------------
load - run 2
-------------------------------------------------
 
Running test for kernel version 2.6.0-test9-love2
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439753        0.103258       0.103258   10000         0
1068439763        0.102513      -0.000745   10000         0
1068439777        0.101485      -0.001028   10000         0    10001    185595
1068439787        0.100754      -0.000731   10000         0    10000   4790720
1068439799        0.099872      -0.000882   10000         0    10000   5779020
1068439809        0.108959       0.009087   10000   5779019     9992  -1344430
1068439819        0.109129       0.000170   10000   5779019    10000   4665051
1068439829        0.109299       0.000170   10000   5779019    10000   4665833

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068439843        0.127032       0.127032   10000         0
1068439854        0.126197      -0.000835   10000         0
1068439867        0.218674       0.092477   10000         0     9908  -3126099
1068439882        0.124147      -0.094527   10000         0    10095  -3102405
1068439898        0.122977      -0.001170   10000         0    10001   1113739
1068439909        0.132439       0.009462   10001   1113738     9992  -1911961
1068439924        0.133104       0.000665   10001   1113738    10001  -3246667
1068439935        0.133593       0.000489   10001   1113738    10001  -2088111

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi
-------------------------------------------------
vanilla 
-------------------------------------------------
idle
-------------------------------------------------
Running test for kernel version 2.6.0-test9
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068441482       -0.004717      -0.004717   10000         0
1068441492       -0.005453      -0.000736   10000         0
1068441502       -0.006187      -0.000734   10000         0    10000   4810251
1068441512       -0.006916      -0.000729   10000         0    10000   4778220
1068441522       -0.007656      -0.000740   10000         0    10000   4850095
1068441532       -0.007642       0.000014   10000   4850094    10000   4758782
1068441542       -0.007617       0.000025   10000   4850094    10000   4686907
1068441552       -0.007595       0.000022   10000   4850094    10000   4706439

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068441562       -0.007592      -0.007592   10000         0
1068441572       -0.007321       0.000271   10000         0
1068441582       -0.008068      -0.000747   10000         0    10000   4895407
1068441592       -0.008798      -0.000730   10000         0    10000   4785251
1068441602       -0.009534      -0.000736   10000         0    10000   4823532
1068441612       -0.009595      -0.000061   10000   4823532    10000   5223627
1068441622       -0.008579       0.001016   10000   4823532    10000  -1834186
1068441632       -0.007561       0.001018   10000   4823532    10000  -1847467

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi
-------------------------------------------------
load - run 1
-------------------------------------------------
Running test for kernel version 2.6.0-test9
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068441806       -0.023066      -0.023066   10000         0
1068441817       -0.023886      -0.000820   10000         0
1068441827       -0.024622      -0.000736   10000         0    10000   4824313
1068441838       -0.025433      -0.000810   10000         0    10000   5310651
1068441856       -0.026762      -0.001330   10000         0    10001   2159852
1068441868       -0.026087       0.000675   10001   2159851    10001  -2265817
1068441881       -0.025307       0.000780   10001   2159851    10001  -2952136
1068441892       -0.024650       0.000657   10001   2159851    10001  -2142779

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068441902       -0.024727      -0.024727   10000         0
1068441913       -0.025560      -0.000832   10000         0
1068441927       -0.026594      -0.001034   10000         0    10001    224658
1068441940       -0.027553      -0.000959   10000         0    10000   6284889
1068441950       -0.028289      -0.000736   10000         0    10000   4824313
1068441960       -0.028363      -0.000074   10000   4824313    10000   5309564
1068441971       -0.028348       0.000016   10000   4824313    10000   4722464
1068441982       -0.028328       0.000020   10000   4824313    10000   4695902

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi
-------------------------------------------------
load - run 2
-------------------------------------------------
Running test for kernel version 2.6.0-test9
This test will take about 140 seconds to run

ACPI interrupts before the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test without amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068442024       -0.028550      -0.028550   10000         0
1068442034       -0.029312      -0.000762   10000         0
1068442044       -0.030048      -0.000736   10000         0    10000   4823532
1068442060       -0.031229      -0.001181   10000         0    10001   1185614
1068442075       -0.032338      -0.001109   10000         0    10001    711776
1068442085       -0.031986       0.000352   10001    711776    10001  -1594379
1068442095       -0.031610       0.000376   10001    711776    10001  -1751411
1068442112       -0.030975       0.000635   10001    711776    10001  -3448610

ACPI interrupts after the first test: 
  9:          0          0   IO-APIC-level  acpi

Running test with amd76x_pm module
                                           --- current ---    -- suggested --
cmos time     system-cmos       2nd diff    tick      freq     tick      freq
1068442127       -0.031614      -0.031614   10000         0
1068442141       -0.032668      -0.001054   10000         0
1068442159       -0.033992      -0.001324   10000         0    10001   2126258
1068442169       -0.034728      -0.000735   10000         0    10000   4818063
1068442181       -0.035613      -0.000886   10000         0    10000   5804020
1068442191       -0.035545       0.000068   10000   5804019    10000   5358801
1068442203       -0.035345       0.000200   10000   5804019    10000   4491633
1068442217       -0.035103       0.000242   10000   5804019    10000   4219777

ACPI interrupts after the second test: 
  9:          0          0   IO-APIC-level  acpi
-------------------------------------------------

Hope this helps a bit, and thanks for cc-ing me
	Peter G.

-- 
I object to intellect without discipline;  I object to power without
constructive purpose.
                -- Spock, "The Squire of Gothos", stardate 2124.5


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

* Re: [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test
  2003-11-10  6:01 ` Peter Gantner
@ 2003-11-10 18:04   ` Tony Lindgren
  0 siblings, 0 replies; 3+ messages in thread
From: Tony Lindgren @ 2003-11-10 18:04 UTC (permalink / raw)
  To: Peter Gantner; +Cc: linux-kernel, pasi.savolainen, Charles Lepple, f.maibaum

* Peter Gantner <peter.gantner@stud.uni-graz.at> [031109 22:02]:
> Quoting Tony Lindgren from Nov 9
> 
> > On the clock skew problem, it's still there, and to figure out how bad the
> > problem is, I've done a little shell script based on the earlier thread on
> > adjtimex on this mailing list.
> 
> Here are my results from your script.

Thanks!

> I did three runs each, first run idle, two runs under load, i.e. two
> burnK7 processes and a make -j5 kernel compile just to make sure.
> loadavg goes up to ~6.5 during those.
> ntpd was not running during the tests.

Great, I was only expecting results from idle mode, but seeing what happens
under load is interesting to see too.

> System is an A7M266-d w/ two AthlonXPs 1800+ (model 6 stepping 2),
> L5-modded(!) for the MP setup. (I know this is considered tainting,
> if you can tell me the timing issues are related to the modding I
> will shut up immediately, but so far nobody seems to have pinpointed 
> it to this.)

That should not make a difference. I think I'm getting pretty much similar
results with missed ticks. I'll try to take a look at it in early December
when I have access to my Athlon box again.

Tony

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

end of thread, other threads:[~2003-11-10 18:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-10  0:33 [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test Tony Lindgren
2003-11-10  6:01 ` Peter Gantner
2003-11-10 18:04   ` Tony Lindgren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).