2003-11-10 00:33:37

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test

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 <[email protected]>
+ * Copyright (C) 2002 Johnathan Hicks <[email protected]>
+ * Copyright (C) 2003 Pasi Savolainen
+ *
+ * HISTORY
+ *
+ * 20020702 - amd-smp-idle: Tony Lindgren <[email protected]>
+ * 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 */


Attachments:
(No filename) (1.40 kB)
linux-2.6-amd76x_pm-20031109.patch (22.01 kB)
Download all attachments

2003-11-10 06:01:46

by Peter Gantner

[permalink] [raw]
Subject: Re: [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test

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

2003-11-10 18:04:44

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test

* Peter Gantner <[email protected]> [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

2003-11-10 20:33:08

by Olivier Nicolas

[permalink] [raw]
Subject: Re:[PATCH] amd76x_pm on 2.6.0-test9 more cleanup and clock skew test

skewtest.sh results for MSI K7D Master MB (2 Athlon MP 1500)

Olivier

----------------
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
1068494427 462.635489 462.635489 10000 0
1068494437 462.640807 0.005319 10000 0
1068494447 462.643195 0.002388 10000 0 9998
-2540954
1068494457 462.648540 0.005346 10000 0 9995
-2264529
1068494467 462.650932 0.002392 10000 0 9998
-2566735
1068494477 462.652406 0.001474 9998 -2566735 9996
882936
1068494487 462.655349 0.002944 9998 -2566735 9995
-2197058
1068494497 462.656817 0.001468 9998 -2566735 9996
922780

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
1068494507 462.655675 462.655675 10000 0
1068494517 462.662003 0.006329 10000 0
1068494527 462.665392 0.003389 10000 0 9997
-2546729
1068494537 462.670736 0.005345 10000 0 9995
-2259060
1068494547 462.673123 0.002387 10000 0 9998
-2533142
1068494557 462.678602 0.005479 9998 -2533141 9992
883274
1068494567 462.681072 0.002471 9998 -2533141 9995
936536
1068494577 462.682542 0.001470 9998 -2533141 9996
943092

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

------------------------
processor : 0
vendor_id : AuthenticAMD
cpu family : 6
model : 6
model name : AMD Athlon(tm) MP 1800+
stepping : 2
cpu MHz : 1533.698
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge
mca cmov pat pse36 mmx fxsr sse syscall mp mmxext 3dnowext 3dnow
bogomips : 3014.65



processor : 1
vendor_id : AuthenticAMD
cpu family : 6
model : 6
model name : AMD Athlon(tm) MP
stepping : 2
cpu MHz : 1533.698
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge
mca cmov pat pse36 mmx fxsr sse syscall mp mmxext 3dnowext 3dnow
bogomips : 3063.80


---------------------------
00:00.0 Host bridge: Advanced Micro Devices [AMD] AMD-760 MP [IGD4-2P]
System Controller (rev 11)
00:01.0 PCI bridge: Advanced Micro Devices [AMD] AMD-760 MP [IGD4-2P]
AGP Bridge
00:07.0 ISA bridge: Advanced Micro Devices [AMD] AMD-768 [Opus] ISA (rev 05)
00:07.1 IDE interface: Advanced Micro Devices [AMD] AMD-768 [Opus] IDE
(rev 04)
00:07.3 Bridge: Advanced Micro Devices [AMD] AMD-768 [Opus] ACPI (rev 03)
00:07.5 Multimedia audio controller: Advanced Micro Devices [AMD]
AMD-768 [Opus] Audio (rev 03)
00:10.0 PCI bridge: Advanced Micro Devices [AMD] AMD-768 [Opus] PCI (rev 05)
01:05.0 VGA compatible controller: nVidia Corporation NV25 [GeForce4 Ti
4200] (rev a2)
02:00.0 USB Controller: Advanced Micro Devices [AMD] AMD-768 [Opus] USB
(rev 07)
02:06.0 USB Controller: NEC Corporation USB (rev 41)
02:06.1 USB Controller: NEC Corporation USB (rev 41)
02:06.2 USB Controller: NEC Corporation USB 2.0 (rev 02)
02:09.0 Ethernet controller: Intel Corp. 82557/8/9 [Ethernet Pro 100]
(rev 10)