]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.arch/x86_64-hpet-64bit-timer.patch
Updated xen patches taken from suse.
[people/teissler/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.arch / x86_64-hpet-64bit-timer.patch
1
2 From: Jiri Bohac <jbohac@suse.cz>
3 Subject: allow 64-bit mode for HPET Timer0
4 References: bnc#456700
5
6 The kernel uses the HPET timers in 32-bit mode for clock-events.
7 While 32 bits, with a wrap-around time of >4 minutes, is probably
8 good enough for the clock-event purposes, on some chipsets this
9 has a negative side-effect on the HPET main counter.
10
11 Unlike the original HPET specification 1.0 from 2004, which does not
12 mention any side-effects of setting TN_32MODE_CNF on the
13 individual timers, the ICH9 documentation, for example, says:
14
15 NOTE: When this bit is set to ‘1’, the hardware counter will
16 do a 32-bit operation on comparator match and rollovers, thus
17 the upper 32-bit of the Timer 0 Comparator Value register is
18 ignored. The upper 32-bit of the main counter is not involved
19 in any rollover from lower 32-bit of the main counter and
20 becomes all zeros.
21
22 (see http://www.intel.com/assets/pdf/datasheet/316972.pdf, page
23 819, section 21.1.5, Bit 8). I've seen this behaviour also on
24 ICH8. I have no idea what other chipsets are affected. But I have
25 seen AMD chipsets that Do The Right Thing.
26
27 This means, that when the kernel configures the Timer 0 to 32-bit
28 mode, on these chipsets it also cripples the 64-bit main counter
29 to 32 bits.
30
31 The HPET may be mmapped in userspace and the main counter
32 accessed directly by applications, expecting a 64-bit main
33 counter.
34
35 This patch allows the Timer0 to be configured in 64-bit mode
36 on x86_64 when a hpet64 command-line option is specified.
37
38 Signed-off-by: Jiri Bohac <jbohac@suse.cz>
39
40 ---
41 arch/x86/kernel/hpet.c | 89 +++++++++++++++++++++++++++++++++++++++++++------
42 1 file changed, 79 insertions(+), 10 deletions(-)
43
44 --- a/arch/x86/kernel/hpet.c 2009-01-24 16:39:47.000000000 +0100
45 +++ b/arch/x86/kernel/hpet.c 2009-01-24 16:56:04.000000000 +0100
46 @@ -24,6 +24,7 @@
47 */
48 unsigned long hpet_address;
49 static void __iomem *hpet_virt_address;
50 +static int hpet_legacy_use_64_bits;
51
52 unsigned long hpet_readl(unsigned long a)
53 {
54 @@ -37,6 +38,33 @@ static inline void hpet_writel(unsigned
55
56 #ifdef CONFIG_X86_64
57 #include <asm/pgtable.h>
58 +static inline unsigned long hpet_read_value(unsigned long a)
59 +{
60 + if (hpet_legacy_use_64_bits)
61 + return readq(hpet_virt_address + a);
62 + else
63 + return readl(hpet_virt_address + a);
64 +}
65 +
66 +static void hpet_write_value(unsigned long d, unsigned long a)
67 +{
68 + if (hpet_legacy_use_64_bits)
69 + writeq(d, hpet_virt_address + a);
70 + else
71 + writel(d, hpet_virt_address + a);
72 +}
73 +
74 +#else
75 +
76 +static inline unsigned long hpet_read_value(unsigned long a)
77 +{
78 + return readl(hpet_virt_address + a);
79 +}
80 +
81 +static void hpet_write_value(unsigned long d, unsigned long a)
82 +{
83 + writel(d, hpet_virt_address + a);
84 +}
85 #endif
86
87 static inline void hpet_set_mapping(void)
88 @@ -78,6 +106,17 @@ static int __init disable_hpet(char *str
89 }
90 __setup("nohpet", disable_hpet);
91
92 +#ifdef CONFIG_X86_64
93 +static int hpet64 = 0;
94 +static int __init hpet64_setup(char *str)
95 +{
96 + hpet64 = 1;
97 + return 1;
98 +}
99 +__setup("hpet64", hpet64_setup);
100 +#endif
101 +
102 +
103 static inline int is_hpet_capable(void)
104 {
105 return (!boot_hpet_disable && hpet_address);
106 @@ -141,6 +180,7 @@ static void hpet_reserve_platform_timers
107 * Common hpet info
108 */
109 static unsigned long hpet_period;
110 +static int hpet_legacy_use_64_bits; /* configure T0 in 64-bit mode? */
111
112 static void hpet_legacy_set_mode(enum clock_event_mode mode,
113 struct clock_event_device *evt);
114 @@ -192,10 +232,38 @@ static void hpet_enable_legacy_int(void)
115 hpet_legacy_int_enabled = 1;
116 }
117
118 +static int timer0_use_64_bits(void)
119 +{
120 +#ifndef CONFIG_X86_64
121 + /* using the HPET in 64-bit mode without atomic 64-bit
122 + * accesses is too inefficient
123 + */
124 + return 0;
125 +#else
126 +
127 + if (unlikely(hpet64)) {
128 + u32 id, t0_cfg;
129 + id = hpet_readl(HPET_ID);
130 + t0_cfg = hpet_readl(HPET_T0_CFG);
131 +
132 + if ((id & HPET_ID_64BIT) && (t0_cfg & HPET_TN_64BIT_CAP)) {
133 + printk(KERN_DEBUG "hpet timer0 configured in 64-bit mode\n");
134 + return 1;
135 + }
136 + else {
137 + printk(KERN_DEBUG "hpet timer0 does not support 64-bit mode\n");
138 + return 0;
139 + }
140 + }
141 + else return 0;
142 +#endif
143 +}
144 +
145 static void hpet_legacy_clockevent_register(void)
146 {
147 /* Start HPET legacy interrupts */
148 hpet_enable_legacy_int();
149 + hpet_legacy_use_64_bits = timer0_use_64_bits();
150
151 /*
152 * The mult factor is defined as (include/linux/clockchips.h)
153 @@ -233,26 +301,28 @@ static void hpet_legacy_set_mode(enum cl
154 case CLOCK_EVT_MODE_PERIODIC:
155 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
156 delta >>= hpet_clockevent.shift;
157 - now = hpet_readl(HPET_COUNTER);
158 + now = hpet_read_value(HPET_COUNTER);
159 cmp = now + (unsigned long) delta;
160 cfg = hpet_readl(HPET_T0_CFG);
161 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
162 - HPET_TN_SETVAL | HPET_TN_32BIT;
163 + HPET_TN_SETVAL |
164 + (hpet_legacy_use_64_bits ? 0 : HPET_TN_32BIT);
165 hpet_writel(cfg, HPET_T0_CFG);
166 /*
167 * The first write after writing TN_SETVAL to the
168 * config register sets the counter value, the second
169 * write sets the period.
170 */
171 - hpet_writel(cmp, HPET_T0_CMP);
172 + hpet_write_value(cmp, HPET_T0_CMP);
173 udelay(1);
174 - hpet_writel((unsigned long) delta, HPET_T0_CMP);
175 + hpet_write_value((unsigned long) delta, HPET_T0_CMP);
176 break;
177
178 case CLOCK_EVT_MODE_ONESHOT:
179 cfg = hpet_readl(HPET_T0_CFG);
180 cfg &= ~HPET_TN_PERIODIC;
181 - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
182 + cfg |= HPET_TN_ENABLE |
183 + (hpet_legacy_use_64_bits ? 0 : HPET_TN_32BIT);
184 hpet_writel(cfg, HPET_T0_CFG);
185 break;
186
187 @@ -272,11 +342,11 @@ static void hpet_legacy_set_mode(enum cl
188 static int hpet_legacy_next_event(unsigned long delta,
189 struct clock_event_device *evt)
190 {
191 - u32 cnt;
192 + unsigned long cnt;
193
194 - cnt = hpet_readl(HPET_COUNTER);
195 + cnt = hpet_read_value(HPET_COUNTER);
196 cnt += (u32) delta;
197 - hpet_writel(cnt, HPET_T0_CMP);
198 + hpet_write_value(cnt, HPET_T0_CMP);
199
200 hpet_readl(HPET_T0_CMP); /* pre-read for bnc#433746 */
201 /*
202 @@ -284,9 +354,9 @@ static int hpet_legacy_next_event(unsign
203 * what we wrote hit the chip before we compare it to the
204 * counter.
205 */
206 - WARN_ON_ONCE((u32)hpet_readl(HPET_T0_CMP) != cnt);
207 + WARN_ON_ONCE((u32)hpet_readl(HPET_T0_CMP) != (u32)cnt);
208
209 - return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
210 + return (s32)((u32)hpet_readl(HPET_COUNTER) - (u32)cnt) >= 0 ? -ETIME : 0;
211 }
212
213 /*
214 --- a/Documentation/kernel-parameters.txt 2009-01-24 16:39:47.000000000 +0100
215 +++ b/Documentation/kernel-parameters.txt 2009-01-24 16:46:51.000000000 +0100
216 @@ -475,6 +475,8 @@ and is between 256 and 4096 characters.
217 force: allow force enabled of undocumented chips (ICH4,
218 VIA, nVidia)
219
220 + hpet64 [X86-64,HPET] enable 64-bit mode of the HPET timer (bnc#456700)
221 +
222 com20020= [HW,NET] ARCnet - COM20020 chipset
223 Format:
224 <io>[,<irq>[,<nodeID>[,<backplane>[,<ckp>[,<timeout>]]]]]