diff options
author | Venki Pallipadi <venkatesh.pallipadi@intel.com> | 2007-10-12 17:04:23 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@inhelltoy.tec.linutronix.de> | 2007-10-12 17:04:23 -0400 |
commit | d54bd57d6580250e6551261f3b15c45a9d90c77b (patch) | |
tree | 12cb06b4adb9494e67cefdc691643e333fef3b91 /arch/x86/kernel/quirks.c | |
parent | 610bf2f143b9c5cda768a2d428d66d3a16769930 (diff) |
x86: HPET force enable o ICH7 and later
Force detect and/or enable HPET on ICH chipsets. This patch just handles the
detection part and following patches use this information. Adds a function to
repeat the force enabling during resume time.
Using HPET this way, instead of PIT increases the time CPUs can reside in
C-state when system is totally idle. On my test system with Core 2 Duo,
average C-state residency goes up from ~20mS to ~80mS.
[ Build fixed from Andrew Morton ]
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Cc: Andi Kleen <ak@suse.de>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/quirks.c')
-rw-r--r-- | arch/x86/kernel/quirks.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 6722469c2633..d3ac703867d6 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/pci.h> | 4 | #include <linux/pci.h> |
5 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
6 | 6 | ||
7 | #include <asm/hpet.h> | ||
8 | |||
7 | #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) | 9 | #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) |
8 | 10 | ||
9 | static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) | 11 | static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) |
@@ -47,3 +49,103 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quir | |||
47 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); | 49 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); |
48 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); | 50 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); |
49 | #endif | 51 | #endif |
52 | |||
53 | #if defined(CONFIG_HPET_TIMER) | ||
54 | unsigned long force_hpet_address; | ||
55 | |||
56 | static void __iomem *rcba_base; | ||
57 | |||
58 | void ich_force_hpet_resume(void) | ||
59 | { | ||
60 | u32 val; | ||
61 | |||
62 | if (!force_hpet_address) | ||
63 | return; | ||
64 | |||
65 | if (rcba_base == NULL) | ||
66 | BUG(); | ||
67 | |||
68 | /* read the Function Disable register, dword mode only */ | ||
69 | val = readl(rcba_base + 0x3404); | ||
70 | if (!(val & 0x80)) { | ||
71 | /* HPET disabled in HPTC. Trying to enable */ | ||
72 | writel(val | 0x80, rcba_base + 0x3404); | ||
73 | } | ||
74 | |||
75 | val = readl(rcba_base + 0x3404); | ||
76 | if (!(val & 0x80)) | ||
77 | BUG(); | ||
78 | else | ||
79 | printk(KERN_DEBUG "Force enabled HPET at resume\n"); | ||
80 | |||
81 | return; | ||
82 | } | ||
83 | |||
84 | static void ich_force_enable_hpet(struct pci_dev *dev) | ||
85 | { | ||
86 | u32 val; | ||
87 | u32 uninitialized_var(rcba); | ||
88 | int err = 0; | ||
89 | |||
90 | if (hpet_address || force_hpet_address) | ||
91 | return; | ||
92 | |||
93 | pci_read_config_dword(dev, 0xF0, &rcba); | ||
94 | rcba &= 0xFFFFC000; | ||
95 | if (rcba == 0) { | ||
96 | printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | /* use bits 31:14, 16 kB aligned */ | ||
101 | rcba_base = ioremap_nocache(rcba, 0x4000); | ||
102 | if (rcba_base == NULL) { | ||
103 | printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | /* read the Function Disable register, dword mode only */ | ||
108 | val = readl(rcba_base + 0x3404); | ||
109 | |||
110 | if (val & 0x80) { | ||
111 | /* HPET is enabled in HPTC. Just not reported by BIOS */ | ||
112 | val = val & 0x3; | ||
113 | force_hpet_address = 0xFED00000 | (val << 12); | ||
114 | printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", | ||
115 | force_hpet_address); | ||
116 | iounmap(rcba_base); | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | /* HPET disabled in HPTC. Trying to enable */ | ||
121 | writel(val | 0x80, rcba_base + 0x3404); | ||
122 | |||
123 | val = readl(rcba_base + 0x3404); | ||
124 | if (!(val & 0x80)) { | ||
125 | err = 1; | ||
126 | } else { | ||
127 | val = val & 0x3; | ||
128 | force_hpet_address = 0xFED00000 | (val << 12); | ||
129 | } | ||
130 | |||
131 | if (err) { | ||
132 | force_hpet_address = 0; | ||
133 | iounmap(rcba_base); | ||
134 | printk(KERN_DEBUG "Failed to force enable HPET\n"); | ||
135 | } else { | ||
136 | printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", | ||
137 | force_hpet_address); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, | ||
142 | ich_force_enable_hpet); | ||
143 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, | ||
144 | ich_force_enable_hpet); | ||
145 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, | ||
146 | ich_force_enable_hpet); | ||
147 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, | ||
148 | ich_force_enable_hpet); | ||
149 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, | ||
150 | ich_force_enable_hpet); | ||
151 | #endif | ||