.. | .. |
---|
1 | | -#include <linux/clocksource.h> |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
2 | 2 | #include <linux/clockchips.h> |
---|
3 | 3 | #include <linux/interrupt.h> |
---|
4 | | -#include <linux/irq.h> |
---|
5 | 4 | #include <linux/export.h> |
---|
6 | 5 | #include <linux/delay.h> |
---|
7 | | -#include <linux/errno.h> |
---|
8 | | -#include <linux/i8253.h> |
---|
9 | | -#include <linux/slab.h> |
---|
10 | 6 | #include <linux/hpet.h> |
---|
11 | | -#include <linux/init.h> |
---|
12 | 7 | #include <linux/cpu.h> |
---|
13 | | -#include <linux/pm.h> |
---|
14 | | -#include <linux/io.h> |
---|
| 8 | +#include <linux/irq.h> |
---|
15 | 9 | |
---|
16 | | -#include <asm/cpufeature.h> |
---|
17 | | -#include <asm/irqdomain.h> |
---|
18 | | -#include <asm/fixmap.h> |
---|
19 | 10 | #include <asm/hpet.h> |
---|
20 | 11 | #include <asm/time.h> |
---|
| 12 | +#include <asm/mwait.h> |
---|
| 13 | + |
---|
| 14 | +#undef pr_fmt |
---|
| 15 | +#define pr_fmt(fmt) "hpet: " fmt |
---|
| 16 | + |
---|
| 17 | +enum hpet_mode { |
---|
| 18 | + HPET_MODE_UNUSED, |
---|
| 19 | + HPET_MODE_LEGACY, |
---|
| 20 | + HPET_MODE_CLOCKEVT, |
---|
| 21 | + HPET_MODE_DEVICE, |
---|
| 22 | +}; |
---|
| 23 | + |
---|
| 24 | +struct hpet_channel { |
---|
| 25 | + struct clock_event_device evt; |
---|
| 26 | + unsigned int num; |
---|
| 27 | + unsigned int cpu; |
---|
| 28 | + unsigned int irq; |
---|
| 29 | + unsigned int in_use; |
---|
| 30 | + enum hpet_mode mode; |
---|
| 31 | + unsigned int boot_cfg; |
---|
| 32 | + char name[10]; |
---|
| 33 | +}; |
---|
| 34 | + |
---|
| 35 | +struct hpet_base { |
---|
| 36 | + unsigned int nr_channels; |
---|
| 37 | + unsigned int nr_clockevents; |
---|
| 38 | + unsigned int boot_cfg; |
---|
| 39 | + struct hpet_channel *channels; |
---|
| 40 | +}; |
---|
21 | 41 | |
---|
22 | 42 | #define HPET_MASK CLOCKSOURCE_MASK(32) |
---|
23 | | - |
---|
24 | | -/* FSEC = 10^-15 |
---|
25 | | - NSEC = 10^-9 */ |
---|
26 | | -#define FSEC_PER_NSEC 1000000L |
---|
27 | | - |
---|
28 | | -#define HPET_DEV_USED_BIT 2 |
---|
29 | | -#define HPET_DEV_USED (1 << HPET_DEV_USED_BIT) |
---|
30 | | -#define HPET_DEV_VALID 0x8 |
---|
31 | | -#define HPET_DEV_FSB_CAP 0x1000 |
---|
32 | | -#define HPET_DEV_PERI_CAP 0x2000 |
---|
33 | 43 | |
---|
34 | 44 | #define HPET_MIN_CYCLES 128 |
---|
35 | 45 | #define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1)) |
---|
.. | .. |
---|
42 | 52 | bool hpet_msi_disable; |
---|
43 | 53 | |
---|
44 | 54 | #ifdef CONFIG_PCI_MSI |
---|
45 | | -static unsigned int hpet_num_timers; |
---|
| 55 | +static DEFINE_PER_CPU(struct hpet_channel *, cpu_hpet_channel); |
---|
| 56 | +static struct irq_domain *hpet_domain; |
---|
46 | 57 | #endif |
---|
| 58 | + |
---|
47 | 59 | static void __iomem *hpet_virt_address; |
---|
48 | 60 | |
---|
49 | | -struct hpet_dev { |
---|
50 | | - struct clock_event_device evt; |
---|
51 | | - unsigned int num; |
---|
52 | | - int cpu; |
---|
53 | | - unsigned int irq; |
---|
54 | | - unsigned int flags; |
---|
55 | | - char name[10]; |
---|
56 | | -}; |
---|
| 61 | +static struct hpet_base hpet_base; |
---|
57 | 62 | |
---|
58 | | -static inline struct hpet_dev *EVT_TO_HPET_DEV(struct clock_event_device *evtdev) |
---|
| 63 | +static bool hpet_legacy_int_enabled; |
---|
| 64 | +static unsigned long hpet_freq; |
---|
| 65 | + |
---|
| 66 | +bool boot_hpet_disable; |
---|
| 67 | +bool hpet_force_user; |
---|
| 68 | +static bool hpet_verbose; |
---|
| 69 | + |
---|
| 70 | +static inline |
---|
| 71 | +struct hpet_channel *clockevent_to_channel(struct clock_event_device *evt) |
---|
59 | 72 | { |
---|
60 | | - return container_of(evtdev, struct hpet_dev, evt); |
---|
| 73 | + return container_of(evt, struct hpet_channel, evt); |
---|
61 | 74 | } |
---|
62 | 75 | |
---|
63 | 76 | inline unsigned int hpet_readl(unsigned int a) |
---|
.. | .. |
---|
70 | 83 | writel(d, hpet_virt_address + a); |
---|
71 | 84 | } |
---|
72 | 85 | |
---|
73 | | -#ifdef CONFIG_X86_64 |
---|
74 | | -#include <asm/pgtable.h> |
---|
75 | | -#endif |
---|
76 | | - |
---|
77 | 86 | static inline void hpet_set_mapping(void) |
---|
78 | 87 | { |
---|
79 | | - hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); |
---|
| 88 | + hpet_virt_address = ioremap(hpet_address, HPET_MMAP_SIZE); |
---|
80 | 89 | } |
---|
81 | 90 | |
---|
82 | 91 | static inline void hpet_clear_mapping(void) |
---|
.. | .. |
---|
88 | 97 | /* |
---|
89 | 98 | * HPET command line enable / disable |
---|
90 | 99 | */ |
---|
91 | | -bool boot_hpet_disable; |
---|
92 | | -bool hpet_force_user; |
---|
93 | | -static bool hpet_verbose; |
---|
94 | | - |
---|
95 | 100 | static int __init hpet_setup(char *str) |
---|
96 | 101 | { |
---|
97 | 102 | while (str) { |
---|
.. | .. |
---|
123 | 128 | return !boot_hpet_disable && hpet_address; |
---|
124 | 129 | } |
---|
125 | 130 | |
---|
126 | | -/* |
---|
127 | | - * HPET timer interrupt enable / disable |
---|
128 | | - */ |
---|
129 | | -static bool hpet_legacy_int_enabled; |
---|
130 | | - |
---|
131 | 131 | /** |
---|
132 | | - * is_hpet_enabled - check whether the hpet timer interrupt is enabled |
---|
| 132 | + * is_hpet_enabled - Check whether the legacy HPET timer interrupt is enabled |
---|
133 | 133 | */ |
---|
134 | 134 | int is_hpet_enabled(void) |
---|
135 | 135 | { |
---|
.. | .. |
---|
139 | 139 | |
---|
140 | 140 | static void _hpet_print_config(const char *function, int line) |
---|
141 | 141 | { |
---|
142 | | - u32 i, timers, l, h; |
---|
143 | | - printk(KERN_INFO "hpet: %s(%d):\n", function, line); |
---|
144 | | - l = hpet_readl(HPET_ID); |
---|
145 | | - h = hpet_readl(HPET_PERIOD); |
---|
146 | | - timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
---|
147 | | - printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h); |
---|
148 | | - l = hpet_readl(HPET_CFG); |
---|
149 | | - h = hpet_readl(HPET_STATUS); |
---|
150 | | - printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h); |
---|
| 142 | + u32 i, id, period, cfg, status, channels, l, h; |
---|
| 143 | + |
---|
| 144 | + pr_info("%s(%d):\n", function, line); |
---|
| 145 | + |
---|
| 146 | + id = hpet_readl(HPET_ID); |
---|
| 147 | + period = hpet_readl(HPET_PERIOD); |
---|
| 148 | + pr_info("ID: 0x%x, PERIOD: 0x%x\n", id, period); |
---|
| 149 | + |
---|
| 150 | + cfg = hpet_readl(HPET_CFG); |
---|
| 151 | + status = hpet_readl(HPET_STATUS); |
---|
| 152 | + pr_info("CFG: 0x%x, STATUS: 0x%x\n", cfg, status); |
---|
| 153 | + |
---|
151 | 154 | l = hpet_readl(HPET_COUNTER); |
---|
152 | 155 | h = hpet_readl(HPET_COUNTER+4); |
---|
153 | | - printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); |
---|
| 156 | + pr_info("COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); |
---|
154 | 157 | |
---|
155 | | - for (i = 0; i < timers; i++) { |
---|
| 158 | + channels = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
---|
| 159 | + |
---|
| 160 | + for (i = 0; i < channels; i++) { |
---|
156 | 161 | l = hpet_readl(HPET_Tn_CFG(i)); |
---|
157 | 162 | h = hpet_readl(HPET_Tn_CFG(i)+4); |
---|
158 | | - printk(KERN_INFO "hpet: T%d: CFG_l: 0x%x, CFG_h: 0x%x\n", |
---|
159 | | - i, l, h); |
---|
| 163 | + pr_info("T%d: CFG_l: 0x%x, CFG_h: 0x%x\n", i, l, h); |
---|
| 164 | + |
---|
160 | 165 | l = hpet_readl(HPET_Tn_CMP(i)); |
---|
161 | 166 | h = hpet_readl(HPET_Tn_CMP(i)+4); |
---|
162 | | - printk(KERN_INFO "hpet: T%d: CMP_l: 0x%x, CMP_h: 0x%x\n", |
---|
163 | | - i, l, h); |
---|
| 167 | + pr_info("T%d: CMP_l: 0x%x, CMP_h: 0x%x\n", i, l, h); |
---|
| 168 | + |
---|
164 | 169 | l = hpet_readl(HPET_Tn_ROUTE(i)); |
---|
165 | 170 | h = hpet_readl(HPET_Tn_ROUTE(i)+4); |
---|
166 | | - printk(KERN_INFO "hpet: T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n", |
---|
167 | | - i, l, h); |
---|
| 171 | + pr_info("T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n", i, l, h); |
---|
168 | 172 | } |
---|
169 | 173 | } |
---|
170 | 174 | |
---|
.. | .. |
---|
175 | 179 | } while (0) |
---|
176 | 180 | |
---|
177 | 181 | /* |
---|
178 | | - * When the hpet driver (/dev/hpet) is enabled, we need to reserve |
---|
| 182 | + * When the HPET driver (/dev/hpet) is enabled, we need to reserve |
---|
179 | 183 | * timer 0 and timer 1 in case of RTC emulation. |
---|
180 | 184 | */ |
---|
181 | 185 | #ifdef CONFIG_HPET |
---|
182 | 186 | |
---|
183 | | -static void hpet_reserve_msi_timers(struct hpet_data *hd); |
---|
184 | | - |
---|
185 | | -static void hpet_reserve_platform_timers(unsigned int id) |
---|
| 187 | +static void __init hpet_reserve_platform_timers(void) |
---|
186 | 188 | { |
---|
187 | | - struct hpet __iomem *hpet = hpet_virt_address; |
---|
188 | | - struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; |
---|
189 | | - unsigned int nrtimers, i; |
---|
190 | 189 | struct hpet_data hd; |
---|
191 | | - |
---|
192 | | - nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
---|
| 190 | + unsigned int i; |
---|
193 | 191 | |
---|
194 | 192 | memset(&hd, 0, sizeof(hd)); |
---|
195 | 193 | hd.hd_phys_address = hpet_address; |
---|
196 | | - hd.hd_address = hpet; |
---|
197 | | - hd.hd_nirqs = nrtimers; |
---|
198 | | - hpet_reserve_timer(&hd, 0); |
---|
199 | | - |
---|
200 | | -#ifdef CONFIG_HPET_EMULATE_RTC |
---|
201 | | - hpet_reserve_timer(&hd, 1); |
---|
202 | | -#endif |
---|
| 194 | + hd.hd_address = hpet_virt_address; |
---|
| 195 | + hd.hd_nirqs = hpet_base.nr_channels; |
---|
203 | 196 | |
---|
204 | 197 | /* |
---|
205 | 198 | * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254 |
---|
.. | .. |
---|
209 | 202 | hd.hd_irq[0] = HPET_LEGACY_8254; |
---|
210 | 203 | hd.hd_irq[1] = HPET_LEGACY_RTC; |
---|
211 | 204 | |
---|
212 | | - for (i = 2; i < nrtimers; timer++, i++) { |
---|
213 | | - hd.hd_irq[i] = (readl(&timer->hpet_config) & |
---|
214 | | - Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT; |
---|
| 205 | + for (i = 0; i < hpet_base.nr_channels; i++) { |
---|
| 206 | + struct hpet_channel *hc = hpet_base.channels + i; |
---|
| 207 | + |
---|
| 208 | + if (i >= 2) |
---|
| 209 | + hd.hd_irq[i] = hc->irq; |
---|
| 210 | + |
---|
| 211 | + switch (hc->mode) { |
---|
| 212 | + case HPET_MODE_UNUSED: |
---|
| 213 | + case HPET_MODE_DEVICE: |
---|
| 214 | + hc->mode = HPET_MODE_DEVICE; |
---|
| 215 | + break; |
---|
| 216 | + case HPET_MODE_CLOCKEVT: |
---|
| 217 | + case HPET_MODE_LEGACY: |
---|
| 218 | + hpet_reserve_timer(&hd, hc->num); |
---|
| 219 | + break; |
---|
| 220 | + } |
---|
215 | 221 | } |
---|
216 | 222 | |
---|
217 | | - hpet_reserve_msi_timers(&hd); |
---|
218 | | - |
---|
219 | 223 | hpet_alloc(&hd); |
---|
220 | | - |
---|
221 | 224 | } |
---|
| 225 | + |
---|
| 226 | +static void __init hpet_select_device_channel(void) |
---|
| 227 | +{ |
---|
| 228 | + int i; |
---|
| 229 | + |
---|
| 230 | + for (i = 0; i < hpet_base.nr_channels; i++) { |
---|
| 231 | + struct hpet_channel *hc = hpet_base.channels + i; |
---|
| 232 | + |
---|
| 233 | + /* Associate the first unused channel to /dev/hpet */ |
---|
| 234 | + if (hc->mode == HPET_MODE_UNUSED) { |
---|
| 235 | + hc->mode = HPET_MODE_DEVICE; |
---|
| 236 | + return; |
---|
| 237 | + } |
---|
| 238 | + } |
---|
| 239 | +} |
---|
| 240 | + |
---|
222 | 241 | #else |
---|
223 | | -static void hpet_reserve_platform_timers(unsigned int id) { } |
---|
| 242 | +static inline void hpet_reserve_platform_timers(void) { } |
---|
| 243 | +static inline void hpet_select_device_channel(void) {} |
---|
224 | 244 | #endif |
---|
225 | 245 | |
---|
226 | | -/* |
---|
227 | | - * Common hpet info |
---|
228 | | - */ |
---|
229 | | -static unsigned long hpet_freq; |
---|
230 | | - |
---|
231 | | -static struct clock_event_device hpet_clockevent; |
---|
232 | | - |
---|
| 246 | +/* Common HPET functions */ |
---|
233 | 247 | static void hpet_stop_counter(void) |
---|
234 | 248 | { |
---|
235 | 249 | u32 cfg = hpet_readl(HPET_CFG); |
---|
| 250 | + |
---|
236 | 251 | cfg &= ~HPET_CFG_ENABLE; |
---|
237 | 252 | hpet_writel(cfg, HPET_CFG); |
---|
238 | 253 | } |
---|
.. | .. |
---|
246 | 261 | static void hpet_start_counter(void) |
---|
247 | 262 | { |
---|
248 | 263 | unsigned int cfg = hpet_readl(HPET_CFG); |
---|
| 264 | + |
---|
249 | 265 | cfg |= HPET_CFG_ENABLE; |
---|
250 | 266 | hpet_writel(cfg, HPET_CFG); |
---|
251 | 267 | } |
---|
.. | .. |
---|
277 | 293 | hpet_legacy_int_enabled = true; |
---|
278 | 294 | } |
---|
279 | 295 | |
---|
280 | | -static void hpet_legacy_clockevent_register(void) |
---|
| 296 | +static int hpet_clkevt_set_state_periodic(struct clock_event_device *evt) |
---|
281 | 297 | { |
---|
282 | | - /* Start HPET legacy interrupts */ |
---|
283 | | - hpet_enable_legacy_int(); |
---|
284 | | - |
---|
285 | | - /* |
---|
286 | | - * Start hpet with the boot cpu mask and make it |
---|
287 | | - * global after the IO_APIC has been initialized. |
---|
288 | | - */ |
---|
289 | | - hpet_clockevent.cpumask = cpumask_of(boot_cpu_data.cpu_index); |
---|
290 | | - clockevents_config_and_register(&hpet_clockevent, hpet_freq, |
---|
291 | | - HPET_MIN_PROG_DELTA, 0x7FFFFFFF); |
---|
292 | | - global_clock_event = &hpet_clockevent; |
---|
293 | | - printk(KERN_DEBUG "hpet clockevent registered\n"); |
---|
294 | | -} |
---|
295 | | - |
---|
296 | | -static int hpet_set_periodic(struct clock_event_device *evt, int timer) |
---|
297 | | -{ |
---|
| 298 | + unsigned int channel = clockevent_to_channel(evt)->num; |
---|
298 | 299 | unsigned int cfg, cmp, now; |
---|
299 | 300 | uint64_t delta; |
---|
300 | 301 | |
---|
.. | .. |
---|
303 | 304 | delta >>= evt->shift; |
---|
304 | 305 | now = hpet_readl(HPET_COUNTER); |
---|
305 | 306 | cmp = now + (unsigned int)delta; |
---|
306 | | - cfg = hpet_readl(HPET_Tn_CFG(timer)); |
---|
| 307 | + cfg = hpet_readl(HPET_Tn_CFG(channel)); |
---|
307 | 308 | cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | |
---|
308 | 309 | HPET_TN_32BIT; |
---|
309 | | - hpet_writel(cfg, HPET_Tn_CFG(timer)); |
---|
310 | | - hpet_writel(cmp, HPET_Tn_CMP(timer)); |
---|
| 310 | + hpet_writel(cfg, HPET_Tn_CFG(channel)); |
---|
| 311 | + hpet_writel(cmp, HPET_Tn_CMP(channel)); |
---|
311 | 312 | udelay(1); |
---|
312 | 313 | /* |
---|
313 | 314 | * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL |
---|
.. | .. |
---|
316 | 317 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, |
---|
317 | 318 | * Publication # 24674) |
---|
318 | 319 | */ |
---|
319 | | - hpet_writel((unsigned int)delta, HPET_Tn_CMP(timer)); |
---|
| 320 | + hpet_writel((unsigned int)delta, HPET_Tn_CMP(channel)); |
---|
320 | 321 | hpet_start_counter(); |
---|
321 | 322 | hpet_print_config(); |
---|
322 | 323 | |
---|
323 | 324 | return 0; |
---|
324 | 325 | } |
---|
325 | 326 | |
---|
326 | | -static int hpet_set_oneshot(struct clock_event_device *evt, int timer) |
---|
| 327 | +static int hpet_clkevt_set_state_oneshot(struct clock_event_device *evt) |
---|
327 | 328 | { |
---|
| 329 | + unsigned int channel = clockevent_to_channel(evt)->num; |
---|
328 | 330 | unsigned int cfg; |
---|
329 | 331 | |
---|
330 | | - cfg = hpet_readl(HPET_Tn_CFG(timer)); |
---|
| 332 | + cfg = hpet_readl(HPET_Tn_CFG(channel)); |
---|
331 | 333 | cfg &= ~HPET_TN_PERIODIC; |
---|
332 | 334 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; |
---|
333 | | - hpet_writel(cfg, HPET_Tn_CFG(timer)); |
---|
| 335 | + hpet_writel(cfg, HPET_Tn_CFG(channel)); |
---|
334 | 336 | |
---|
335 | 337 | return 0; |
---|
336 | 338 | } |
---|
337 | 339 | |
---|
338 | | -static int hpet_shutdown(struct clock_event_device *evt, int timer) |
---|
| 340 | +static int hpet_clkevt_set_state_shutdown(struct clock_event_device *evt) |
---|
339 | 341 | { |
---|
| 342 | + unsigned int channel = clockevent_to_channel(evt)->num; |
---|
340 | 343 | unsigned int cfg; |
---|
341 | 344 | |
---|
342 | | - cfg = hpet_readl(HPET_Tn_CFG(timer)); |
---|
| 345 | + cfg = hpet_readl(HPET_Tn_CFG(channel)); |
---|
343 | 346 | cfg &= ~HPET_TN_ENABLE; |
---|
344 | | - hpet_writel(cfg, HPET_Tn_CFG(timer)); |
---|
| 347 | + hpet_writel(cfg, HPET_Tn_CFG(channel)); |
---|
345 | 348 | |
---|
346 | 349 | return 0; |
---|
347 | 350 | } |
---|
348 | 351 | |
---|
349 | | -static int hpet_resume(struct clock_event_device *evt) |
---|
| 352 | +static int hpet_clkevt_legacy_resume(struct clock_event_device *evt) |
---|
350 | 353 | { |
---|
351 | 354 | hpet_enable_legacy_int(); |
---|
352 | 355 | hpet_print_config(); |
---|
353 | 356 | return 0; |
---|
354 | 357 | } |
---|
355 | 358 | |
---|
356 | | -static int hpet_next_event(unsigned long delta, |
---|
357 | | - struct clock_event_device *evt, int timer) |
---|
| 359 | +static int |
---|
| 360 | +hpet_clkevt_set_next_event(unsigned long delta, struct clock_event_device *evt) |
---|
358 | 361 | { |
---|
| 362 | + unsigned int channel = clockevent_to_channel(evt)->num; |
---|
359 | 363 | u32 cnt; |
---|
360 | 364 | s32 res; |
---|
361 | 365 | |
---|
362 | 366 | cnt = hpet_readl(HPET_COUNTER); |
---|
363 | 367 | cnt += (u32) delta; |
---|
364 | | - hpet_writel(cnt, HPET_Tn_CMP(timer)); |
---|
| 368 | + hpet_writel(cnt, HPET_Tn_CMP(channel)); |
---|
365 | 369 | |
---|
366 | 370 | /* |
---|
367 | 371 | * HPETs are a complete disaster. The compare register is |
---|
.. | .. |
---|
390 | 394 | return res < HPET_MIN_CYCLES ? -ETIME : 0; |
---|
391 | 395 | } |
---|
392 | 396 | |
---|
393 | | -static int hpet_legacy_shutdown(struct clock_event_device *evt) |
---|
| 397 | +static void hpet_init_clockevent(struct hpet_channel *hc, unsigned int rating) |
---|
394 | 398 | { |
---|
395 | | - return hpet_shutdown(evt, 0); |
---|
| 399 | + struct clock_event_device *evt = &hc->evt; |
---|
| 400 | + |
---|
| 401 | + evt->rating = rating; |
---|
| 402 | + evt->irq = hc->irq; |
---|
| 403 | + evt->name = hc->name; |
---|
| 404 | + evt->cpumask = cpumask_of(hc->cpu); |
---|
| 405 | + evt->set_state_oneshot = hpet_clkevt_set_state_oneshot; |
---|
| 406 | + evt->set_next_event = hpet_clkevt_set_next_event; |
---|
| 407 | + evt->set_state_shutdown = hpet_clkevt_set_state_shutdown; |
---|
| 408 | + |
---|
| 409 | + evt->features = CLOCK_EVT_FEAT_ONESHOT; |
---|
| 410 | + if (hc->boot_cfg & HPET_TN_PERIODIC) { |
---|
| 411 | + evt->features |= CLOCK_EVT_FEAT_PERIODIC; |
---|
| 412 | + evt->set_state_periodic = hpet_clkevt_set_state_periodic; |
---|
| 413 | + } |
---|
396 | 414 | } |
---|
397 | 415 | |
---|
398 | | -static int hpet_legacy_set_oneshot(struct clock_event_device *evt) |
---|
| 416 | +static void __init hpet_legacy_clockevent_register(struct hpet_channel *hc) |
---|
399 | 417 | { |
---|
400 | | - return hpet_set_oneshot(evt, 0); |
---|
401 | | -} |
---|
| 418 | + /* |
---|
| 419 | + * Start HPET with the boot CPU's cpumask and make it global after |
---|
| 420 | + * the IO_APIC has been initialized. |
---|
| 421 | + */ |
---|
| 422 | + hc->cpu = boot_cpu_data.cpu_index; |
---|
| 423 | + strncpy(hc->name, "hpet", sizeof(hc->name)); |
---|
| 424 | + hpet_init_clockevent(hc, 50); |
---|
402 | 425 | |
---|
403 | | -static int hpet_legacy_set_periodic(struct clock_event_device *evt) |
---|
404 | | -{ |
---|
405 | | - return hpet_set_periodic(evt, 0); |
---|
406 | | -} |
---|
| 426 | + hc->evt.tick_resume = hpet_clkevt_legacy_resume; |
---|
407 | 427 | |
---|
408 | | -static int hpet_legacy_resume(struct clock_event_device *evt) |
---|
409 | | -{ |
---|
410 | | - return hpet_resume(evt); |
---|
411 | | -} |
---|
| 428 | + /* |
---|
| 429 | + * Legacy horrors and sins from the past. HPET used periodic mode |
---|
| 430 | + * unconditionally forever on the legacy channel 0. Removing the |
---|
| 431 | + * below hack and using the conditional in hpet_init_clockevent() |
---|
| 432 | + * makes at least Qemu and one hardware machine fail to boot. |
---|
| 433 | + * There are two issues which cause the boot failure: |
---|
| 434 | + * |
---|
| 435 | + * #1 After the timer delivery test in IOAPIC and the IOAPIC setup |
---|
| 436 | + * the next interrupt is not delivered despite the HPET channel |
---|
| 437 | + * being programmed correctly. Reprogramming the HPET after |
---|
| 438 | + * switching to IOAPIC makes it work again. After fixing this, |
---|
| 439 | + * the next issue surfaces: |
---|
| 440 | + * |
---|
| 441 | + * #2 Due to the unconditional periodic mode availability the Local |
---|
| 442 | + * APIC timer calibration can hijack the global clockevents |
---|
| 443 | + * event handler without causing damage. Using oneshot at this |
---|
| 444 | + * stage makes if hang because the HPET does not get |
---|
| 445 | + * reprogrammed due to the handler hijacking. Duh, stupid me! |
---|
| 446 | + * |
---|
| 447 | + * Both issues require major surgery and especially the kick HPET |
---|
| 448 | + * again after enabling IOAPIC results in really nasty hackery. |
---|
| 449 | + * This 'assume periodic works' magic has survived since HPET |
---|
| 450 | + * support got added, so it's questionable whether this should be |
---|
| 451 | + * fixed. Both Qemu and the failing hardware machine support |
---|
| 452 | + * periodic mode despite the fact that both don't advertise it in |
---|
| 453 | + * the configuration register and both need that extra kick after |
---|
| 454 | + * switching to IOAPIC. Seems to be a feature... |
---|
| 455 | + */ |
---|
| 456 | + hc->evt.features |= CLOCK_EVT_FEAT_PERIODIC; |
---|
| 457 | + hc->evt.set_state_periodic = hpet_clkevt_set_state_periodic; |
---|
412 | 458 | |
---|
413 | | -static int hpet_legacy_next_event(unsigned long delta, |
---|
414 | | - struct clock_event_device *evt) |
---|
415 | | -{ |
---|
416 | | - return hpet_next_event(delta, evt, 0); |
---|
417 | | -} |
---|
| 459 | + /* Start HPET legacy interrupts */ |
---|
| 460 | + hpet_enable_legacy_int(); |
---|
418 | 461 | |
---|
419 | | -/* |
---|
420 | | - * The hpet clock event device |
---|
421 | | - */ |
---|
422 | | -static struct clock_event_device hpet_clockevent = { |
---|
423 | | - .name = "hpet", |
---|
424 | | - .features = CLOCK_EVT_FEAT_PERIODIC | |
---|
425 | | - CLOCK_EVT_FEAT_ONESHOT, |
---|
426 | | - .set_state_periodic = hpet_legacy_set_periodic, |
---|
427 | | - .set_state_oneshot = hpet_legacy_set_oneshot, |
---|
428 | | - .set_state_shutdown = hpet_legacy_shutdown, |
---|
429 | | - .tick_resume = hpet_legacy_resume, |
---|
430 | | - .set_next_event = hpet_legacy_next_event, |
---|
431 | | - .irq = 0, |
---|
432 | | - .rating = 50, |
---|
433 | | -}; |
---|
| 462 | + clockevents_config_and_register(&hc->evt, hpet_freq, |
---|
| 463 | + HPET_MIN_PROG_DELTA, 0x7FFFFFFF); |
---|
| 464 | + global_clock_event = &hc->evt; |
---|
| 465 | + pr_debug("Clockevent registered\n"); |
---|
| 466 | +} |
---|
434 | 467 | |
---|
435 | 468 | /* |
---|
436 | 469 | * HPET MSI Support |
---|
437 | 470 | */ |
---|
438 | 471 | #ifdef CONFIG_PCI_MSI |
---|
439 | 472 | |
---|
440 | | -static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev); |
---|
441 | | -static struct hpet_dev *hpet_devs; |
---|
442 | | -static struct irq_domain *hpet_domain; |
---|
443 | | - |
---|
444 | 473 | void hpet_msi_unmask(struct irq_data *data) |
---|
445 | 474 | { |
---|
446 | | - struct hpet_dev *hdev = irq_data_get_irq_handler_data(data); |
---|
| 475 | + struct hpet_channel *hc = irq_data_get_irq_handler_data(data); |
---|
447 | 476 | unsigned int cfg; |
---|
448 | 477 | |
---|
449 | | - /* unmask it */ |
---|
450 | | - cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
---|
| 478 | + cfg = hpet_readl(HPET_Tn_CFG(hc->num)); |
---|
451 | 479 | cfg |= HPET_TN_ENABLE | HPET_TN_FSB; |
---|
452 | | - hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
---|
| 480 | + hpet_writel(cfg, HPET_Tn_CFG(hc->num)); |
---|
453 | 481 | } |
---|
454 | 482 | |
---|
455 | 483 | void hpet_msi_mask(struct irq_data *data) |
---|
456 | 484 | { |
---|
457 | | - struct hpet_dev *hdev = irq_data_get_irq_handler_data(data); |
---|
| 485 | + struct hpet_channel *hc = irq_data_get_irq_handler_data(data); |
---|
458 | 486 | unsigned int cfg; |
---|
459 | 487 | |
---|
460 | | - /* mask it */ |
---|
461 | | - cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
---|
| 488 | + cfg = hpet_readl(HPET_Tn_CFG(hc->num)); |
---|
462 | 489 | cfg &= ~(HPET_TN_ENABLE | HPET_TN_FSB); |
---|
463 | | - hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
---|
| 490 | + hpet_writel(cfg, HPET_Tn_CFG(hc->num)); |
---|
464 | 491 | } |
---|
465 | 492 | |
---|
466 | | -void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg) |
---|
| 493 | +void hpet_msi_write(struct hpet_channel *hc, struct msi_msg *msg) |
---|
467 | 494 | { |
---|
468 | | - hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num)); |
---|
469 | | - hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4); |
---|
| 495 | + hpet_writel(msg->data, HPET_Tn_ROUTE(hc->num)); |
---|
| 496 | + hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hc->num) + 4); |
---|
470 | 497 | } |
---|
471 | 498 | |
---|
472 | | -void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg) |
---|
| 499 | +static int hpet_clkevt_msi_resume(struct clock_event_device *evt) |
---|
473 | 500 | { |
---|
474 | | - msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num)); |
---|
475 | | - msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4); |
---|
476 | | - msg->address_hi = 0; |
---|
477 | | -} |
---|
478 | | - |
---|
479 | | -static int hpet_msi_shutdown(struct clock_event_device *evt) |
---|
480 | | -{ |
---|
481 | | - struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
---|
482 | | - |
---|
483 | | - return hpet_shutdown(evt, hdev->num); |
---|
484 | | -} |
---|
485 | | - |
---|
486 | | -static int hpet_msi_set_oneshot(struct clock_event_device *evt) |
---|
487 | | -{ |
---|
488 | | - struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
---|
489 | | - |
---|
490 | | - return hpet_set_oneshot(evt, hdev->num); |
---|
491 | | -} |
---|
492 | | - |
---|
493 | | -static int hpet_msi_set_periodic(struct clock_event_device *evt) |
---|
494 | | -{ |
---|
495 | | - struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
---|
496 | | - |
---|
497 | | - return hpet_set_periodic(evt, hdev->num); |
---|
498 | | -} |
---|
499 | | - |
---|
500 | | -static int hpet_msi_resume(struct clock_event_device *evt) |
---|
501 | | -{ |
---|
502 | | - struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
---|
503 | | - struct irq_data *data = irq_get_irq_data(hdev->irq); |
---|
| 501 | + struct hpet_channel *hc = clockevent_to_channel(evt); |
---|
| 502 | + struct irq_data *data = irq_get_irq_data(hc->irq); |
---|
504 | 503 | struct msi_msg msg; |
---|
505 | 504 | |
---|
506 | 505 | /* Restore the MSI msg and unmask the interrupt */ |
---|
507 | 506 | irq_chip_compose_msi_msg(data, &msg); |
---|
508 | | - hpet_msi_write(hdev, &msg); |
---|
| 507 | + hpet_msi_write(hc, &msg); |
---|
509 | 508 | hpet_msi_unmask(data); |
---|
510 | 509 | return 0; |
---|
511 | 510 | } |
---|
512 | 511 | |
---|
513 | | -static int hpet_msi_next_event(unsigned long delta, |
---|
514 | | - struct clock_event_device *evt) |
---|
| 512 | +static irqreturn_t hpet_msi_interrupt_handler(int irq, void *data) |
---|
515 | 513 | { |
---|
516 | | - struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
---|
517 | | - return hpet_next_event(delta, evt, hdev->num); |
---|
518 | | -} |
---|
| 514 | + struct hpet_channel *hc = data; |
---|
| 515 | + struct clock_event_device *evt = &hc->evt; |
---|
519 | 516 | |
---|
520 | | -static irqreturn_t hpet_interrupt_handler(int irq, void *data) |
---|
521 | | -{ |
---|
522 | | - struct hpet_dev *dev = (struct hpet_dev *)data; |
---|
523 | | - struct clock_event_device *hevt = &dev->evt; |
---|
524 | | - |
---|
525 | | - if (!hevt->event_handler) { |
---|
526 | | - printk(KERN_INFO "Spurious HPET timer interrupt on HPET timer %d\n", |
---|
527 | | - dev->num); |
---|
| 517 | + if (!evt->event_handler) { |
---|
| 518 | + pr_info("Spurious interrupt HPET channel %d\n", hc->num); |
---|
528 | 519 | return IRQ_HANDLED; |
---|
529 | 520 | } |
---|
530 | 521 | |
---|
531 | | - hevt->event_handler(hevt); |
---|
| 522 | + evt->event_handler(evt); |
---|
532 | 523 | return IRQ_HANDLED; |
---|
533 | 524 | } |
---|
534 | 525 | |
---|
535 | | -static int hpet_setup_irq(struct hpet_dev *dev) |
---|
| 526 | +static int hpet_setup_msi_irq(struct hpet_channel *hc) |
---|
536 | 527 | { |
---|
537 | | - |
---|
538 | | - if (request_irq(dev->irq, hpet_interrupt_handler, |
---|
| 528 | + if (request_irq(hc->irq, hpet_msi_interrupt_handler, |
---|
539 | 529 | IRQF_TIMER | IRQF_NOBALANCING, |
---|
540 | | - dev->name, dev)) |
---|
| 530 | + hc->name, hc)) |
---|
541 | 531 | return -1; |
---|
542 | 532 | |
---|
543 | | - disable_irq(dev->irq); |
---|
544 | | - irq_set_affinity(dev->irq, cpumask_of(dev->cpu)); |
---|
545 | | - enable_irq(dev->irq); |
---|
| 533 | + disable_irq(hc->irq); |
---|
| 534 | + irq_set_affinity(hc->irq, cpumask_of(hc->cpu)); |
---|
| 535 | + enable_irq(hc->irq); |
---|
546 | 536 | |
---|
547 | | - printk(KERN_DEBUG "hpet: %s irq %d for MSI\n", |
---|
548 | | - dev->name, dev->irq); |
---|
| 537 | + pr_debug("%s irq %u for MSI\n", hc->name, hc->irq); |
---|
549 | 538 | |
---|
550 | 539 | return 0; |
---|
551 | 540 | } |
---|
552 | 541 | |
---|
553 | | -/* This should be called in specific @cpu */ |
---|
554 | | -static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) |
---|
| 542 | +/* Invoked from the hotplug callback on @cpu */ |
---|
| 543 | +static void init_one_hpet_msi_clockevent(struct hpet_channel *hc, int cpu) |
---|
555 | 544 | { |
---|
556 | | - struct clock_event_device *evt = &hdev->evt; |
---|
| 545 | + struct clock_event_device *evt = &hc->evt; |
---|
557 | 546 | |
---|
558 | | - WARN_ON(cpu != smp_processor_id()); |
---|
559 | | - if (!(hdev->flags & HPET_DEV_VALID)) |
---|
560 | | - return; |
---|
| 547 | + hc->cpu = cpu; |
---|
| 548 | + per_cpu(cpu_hpet_channel, cpu) = hc; |
---|
| 549 | + hpet_setup_msi_irq(hc); |
---|
561 | 550 | |
---|
562 | | - hdev->cpu = cpu; |
---|
563 | | - per_cpu(cpu_hpet_dev, cpu) = hdev; |
---|
564 | | - evt->name = hdev->name; |
---|
565 | | - hpet_setup_irq(hdev); |
---|
566 | | - evt->irq = hdev->irq; |
---|
567 | | - |
---|
568 | | - evt->rating = 110; |
---|
569 | | - evt->features = CLOCK_EVT_FEAT_ONESHOT; |
---|
570 | | - if (hdev->flags & HPET_DEV_PERI_CAP) { |
---|
571 | | - evt->features |= CLOCK_EVT_FEAT_PERIODIC; |
---|
572 | | - evt->set_state_periodic = hpet_msi_set_periodic; |
---|
573 | | - } |
---|
574 | | - |
---|
575 | | - evt->set_state_shutdown = hpet_msi_shutdown; |
---|
576 | | - evt->set_state_oneshot = hpet_msi_set_oneshot; |
---|
577 | | - evt->tick_resume = hpet_msi_resume; |
---|
578 | | - evt->set_next_event = hpet_msi_next_event; |
---|
579 | | - evt->cpumask = cpumask_of(hdev->cpu); |
---|
| 551 | + hpet_init_clockevent(hc, 110); |
---|
| 552 | + evt->tick_resume = hpet_clkevt_msi_resume; |
---|
580 | 553 | |
---|
581 | 554 | clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA, |
---|
582 | 555 | 0x7FFFFFFF); |
---|
583 | 556 | } |
---|
584 | 557 | |
---|
585 | | -#ifdef CONFIG_HPET |
---|
586 | | -/* Reserve at least one timer for userspace (/dev/hpet) */ |
---|
587 | | -#define RESERVE_TIMERS 1 |
---|
588 | | -#else |
---|
589 | | -#define RESERVE_TIMERS 0 |
---|
590 | | -#endif |
---|
591 | | - |
---|
592 | | -static void hpet_msi_capability_lookup(unsigned int start_timer) |
---|
| 558 | +static struct hpet_channel *hpet_get_unused_clockevent(void) |
---|
593 | 559 | { |
---|
594 | | - unsigned int id; |
---|
595 | | - unsigned int num_timers; |
---|
596 | | - unsigned int num_timers_used = 0; |
---|
597 | | - int i, irq; |
---|
| 560 | + int i; |
---|
598 | 561 | |
---|
599 | | - if (hpet_msi_disable) |
---|
| 562 | + for (i = 0; i < hpet_base.nr_channels; i++) { |
---|
| 563 | + struct hpet_channel *hc = hpet_base.channels + i; |
---|
| 564 | + |
---|
| 565 | + if (hc->mode != HPET_MODE_CLOCKEVT || hc->in_use) |
---|
| 566 | + continue; |
---|
| 567 | + hc->in_use = 1; |
---|
| 568 | + return hc; |
---|
| 569 | + } |
---|
| 570 | + return NULL; |
---|
| 571 | +} |
---|
| 572 | + |
---|
| 573 | +static int hpet_cpuhp_online(unsigned int cpu) |
---|
| 574 | +{ |
---|
| 575 | + struct hpet_channel *hc = hpet_get_unused_clockevent(); |
---|
| 576 | + |
---|
| 577 | + if (hc) |
---|
| 578 | + init_one_hpet_msi_clockevent(hc, cpu); |
---|
| 579 | + return 0; |
---|
| 580 | +} |
---|
| 581 | + |
---|
| 582 | +static int hpet_cpuhp_dead(unsigned int cpu) |
---|
| 583 | +{ |
---|
| 584 | + struct hpet_channel *hc = per_cpu(cpu_hpet_channel, cpu); |
---|
| 585 | + |
---|
| 586 | + if (!hc) |
---|
| 587 | + return 0; |
---|
| 588 | + free_irq(hc->irq, hc); |
---|
| 589 | + hc->in_use = 0; |
---|
| 590 | + per_cpu(cpu_hpet_channel, cpu) = NULL; |
---|
| 591 | + return 0; |
---|
| 592 | +} |
---|
| 593 | + |
---|
| 594 | +static void __init hpet_select_clockevents(void) |
---|
| 595 | +{ |
---|
| 596 | + unsigned int i; |
---|
| 597 | + |
---|
| 598 | + hpet_base.nr_clockevents = 0; |
---|
| 599 | + |
---|
| 600 | + /* No point if MSI is disabled or CPU has an Always Runing APIC Timer */ |
---|
| 601 | + if (hpet_msi_disable || boot_cpu_has(X86_FEATURE_ARAT)) |
---|
600 | 602 | return; |
---|
601 | 603 | |
---|
602 | | - if (boot_cpu_has(X86_FEATURE_ARAT)) |
---|
603 | | - return; |
---|
604 | | - id = hpet_readl(HPET_ID); |
---|
605 | | - |
---|
606 | | - num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); |
---|
607 | | - num_timers++; /* Value read out starts from 0 */ |
---|
608 | 604 | hpet_print_config(); |
---|
609 | 605 | |
---|
610 | 606 | hpet_domain = hpet_create_irq_domain(hpet_blockid); |
---|
611 | 607 | if (!hpet_domain) |
---|
612 | 608 | return; |
---|
613 | 609 | |
---|
614 | | - hpet_devs = kcalloc(num_timers, sizeof(struct hpet_dev), GFP_KERNEL); |
---|
615 | | - if (!hpet_devs) |
---|
616 | | - return; |
---|
| 610 | + for (i = 0; i < hpet_base.nr_channels; i++) { |
---|
| 611 | + struct hpet_channel *hc = hpet_base.channels + i; |
---|
| 612 | + int irq; |
---|
617 | 613 | |
---|
618 | | - hpet_num_timers = num_timers; |
---|
619 | | - |
---|
620 | | - for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { |
---|
621 | | - struct hpet_dev *hdev = &hpet_devs[num_timers_used]; |
---|
622 | | - unsigned int cfg = hpet_readl(HPET_Tn_CFG(i)); |
---|
623 | | - |
---|
624 | | - /* Only consider HPET timer with MSI support */ |
---|
625 | | - if (!(cfg & HPET_TN_FSB_CAP)) |
---|
| 614 | + if (hc->mode != HPET_MODE_UNUSED) |
---|
626 | 615 | continue; |
---|
627 | 616 | |
---|
628 | | - hdev->flags = 0; |
---|
629 | | - if (cfg & HPET_TN_PERIODIC_CAP) |
---|
630 | | - hdev->flags |= HPET_DEV_PERI_CAP; |
---|
631 | | - sprintf(hdev->name, "hpet%d", i); |
---|
632 | | - hdev->num = i; |
---|
| 617 | + /* Only consider HPET channel with MSI support */ |
---|
| 618 | + if (!(hc->boot_cfg & HPET_TN_FSB_CAP)) |
---|
| 619 | + continue; |
---|
633 | 620 | |
---|
634 | | - irq = hpet_assign_irq(hpet_domain, hdev, hdev->num); |
---|
| 621 | + sprintf(hc->name, "hpet%d", i); |
---|
| 622 | + |
---|
| 623 | + irq = hpet_assign_irq(hpet_domain, hc, hc->num); |
---|
635 | 624 | if (irq <= 0) |
---|
636 | 625 | continue; |
---|
637 | 626 | |
---|
638 | | - hdev->irq = irq; |
---|
639 | | - hdev->flags |= HPET_DEV_FSB_CAP; |
---|
640 | | - hdev->flags |= HPET_DEV_VALID; |
---|
641 | | - num_timers_used++; |
---|
642 | | - if (num_timers_used == num_possible_cpus()) |
---|
| 627 | + hc->irq = irq; |
---|
| 628 | + hc->mode = HPET_MODE_CLOCKEVT; |
---|
| 629 | + |
---|
| 630 | + if (++hpet_base.nr_clockevents == num_possible_cpus()) |
---|
643 | 631 | break; |
---|
644 | 632 | } |
---|
645 | 633 | |
---|
646 | | - printk(KERN_INFO "HPET: %d timers in total, %d timers will be used for per-cpu timer\n", |
---|
647 | | - num_timers, num_timers_used); |
---|
| 634 | + pr_info("%d channels of %d reserved for per-cpu timers\n", |
---|
| 635 | + hpet_base.nr_channels, hpet_base.nr_clockevents); |
---|
648 | 636 | } |
---|
649 | 637 | |
---|
650 | | -#ifdef CONFIG_HPET |
---|
651 | | -static void hpet_reserve_msi_timers(struct hpet_data *hd) |
---|
652 | | -{ |
---|
653 | | - int i; |
---|
654 | | - |
---|
655 | | - if (!hpet_devs) |
---|
656 | | - return; |
---|
657 | | - |
---|
658 | | - for (i = 0; i < hpet_num_timers; i++) { |
---|
659 | | - struct hpet_dev *hdev = &hpet_devs[i]; |
---|
660 | | - |
---|
661 | | - if (!(hdev->flags & HPET_DEV_VALID)) |
---|
662 | | - continue; |
---|
663 | | - |
---|
664 | | - hd->hd_irq[hdev->num] = hdev->irq; |
---|
665 | | - hpet_reserve_timer(hd, hdev->num); |
---|
666 | | - } |
---|
667 | | -} |
---|
668 | | -#endif |
---|
669 | | - |
---|
670 | | -static struct hpet_dev *hpet_get_unused_timer(void) |
---|
671 | | -{ |
---|
672 | | - int i; |
---|
673 | | - |
---|
674 | | - if (!hpet_devs) |
---|
675 | | - return NULL; |
---|
676 | | - |
---|
677 | | - for (i = 0; i < hpet_num_timers; i++) { |
---|
678 | | - struct hpet_dev *hdev = &hpet_devs[i]; |
---|
679 | | - |
---|
680 | | - if (!(hdev->flags & HPET_DEV_VALID)) |
---|
681 | | - continue; |
---|
682 | | - if (test_and_set_bit(HPET_DEV_USED_BIT, |
---|
683 | | - (unsigned long *)&hdev->flags)) |
---|
684 | | - continue; |
---|
685 | | - return hdev; |
---|
686 | | - } |
---|
687 | | - return NULL; |
---|
688 | | -} |
---|
689 | | - |
---|
690 | | -struct hpet_work_struct { |
---|
691 | | - struct delayed_work work; |
---|
692 | | - struct completion complete; |
---|
693 | | -}; |
---|
694 | | - |
---|
695 | | -static void hpet_work(struct work_struct *w) |
---|
696 | | -{ |
---|
697 | | - struct hpet_dev *hdev; |
---|
698 | | - int cpu = smp_processor_id(); |
---|
699 | | - struct hpet_work_struct *hpet_work; |
---|
700 | | - |
---|
701 | | - hpet_work = container_of(w, struct hpet_work_struct, work.work); |
---|
702 | | - |
---|
703 | | - hdev = hpet_get_unused_timer(); |
---|
704 | | - if (hdev) |
---|
705 | | - init_one_hpet_msi_clockevent(hdev, cpu); |
---|
706 | | - |
---|
707 | | - complete(&hpet_work->complete); |
---|
708 | | -} |
---|
709 | | - |
---|
710 | | -static int hpet_cpuhp_online(unsigned int cpu) |
---|
711 | | -{ |
---|
712 | | - struct hpet_work_struct work; |
---|
713 | | - |
---|
714 | | - INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work); |
---|
715 | | - init_completion(&work.complete); |
---|
716 | | - /* FIXME: add schedule_work_on() */ |
---|
717 | | - schedule_delayed_work_on(cpu, &work.work, 0); |
---|
718 | | - wait_for_completion(&work.complete); |
---|
719 | | - destroy_delayed_work_on_stack(&work.work); |
---|
720 | | - return 0; |
---|
721 | | -} |
---|
722 | | - |
---|
723 | | -static int hpet_cpuhp_dead(unsigned int cpu) |
---|
724 | | -{ |
---|
725 | | - struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu); |
---|
726 | | - |
---|
727 | | - if (!hdev) |
---|
728 | | - return 0; |
---|
729 | | - free_irq(hdev->irq, hdev); |
---|
730 | | - hdev->flags &= ~HPET_DEV_USED; |
---|
731 | | - per_cpu(cpu_hpet_dev, cpu) = NULL; |
---|
732 | | - return 0; |
---|
733 | | -} |
---|
734 | 638 | #else |
---|
735 | 639 | |
---|
736 | | -static void hpet_msi_capability_lookup(unsigned int start_timer) |
---|
737 | | -{ |
---|
738 | | - return; |
---|
739 | | -} |
---|
740 | | - |
---|
741 | | -#ifdef CONFIG_HPET |
---|
742 | | -static void hpet_reserve_msi_timers(struct hpet_data *hd) |
---|
743 | | -{ |
---|
744 | | - return; |
---|
745 | | -} |
---|
746 | | -#endif |
---|
| 640 | +static inline void hpet_select_clockevents(void) { } |
---|
747 | 641 | |
---|
748 | 642 | #define hpet_cpuhp_online NULL |
---|
749 | 643 | #define hpet_cpuhp_dead NULL |
---|
.. | .. |
---|
757 | 651 | /* |
---|
758 | 652 | * Reading the HPET counter is a very slow operation. If a large number of |
---|
759 | 653 | * CPUs are trying to access the HPET counter simultaneously, it can cause |
---|
760 | | - * massive delay and slow down system performance dramatically. This may |
---|
| 654 | + * massive delays and slow down system performance dramatically. This may |
---|
761 | 655 | * happen when HPET is the default clock source instead of TSC. For a |
---|
762 | 656 | * really large system with hundreds of CPUs, the slowdown may be so |
---|
763 | | - * severe that it may actually crash the system because of a NMI watchdog |
---|
| 657 | + * severe, that it can actually crash the system because of a NMI watchdog |
---|
764 | 658 | * soft lockup, for example. |
---|
765 | 659 | * |
---|
766 | 660 | * If multiple CPUs are trying to access the HPET counter at the same time, |
---|
.. | .. |
---|
769 | 663 | * |
---|
770 | 664 | * This special feature is only enabled on x86-64 systems. It is unlikely |
---|
771 | 665 | * that 32-bit x86 systems will have enough CPUs to require this feature |
---|
772 | | - * with its associated locking overhead. And we also need 64-bit atomic |
---|
773 | | - * read. |
---|
| 666 | + * with its associated locking overhead. We also need 64-bit atomic read. |
---|
774 | 667 | * |
---|
775 | | - * The lock and the hpet value are stored together and can be read in a |
---|
| 668 | + * The lock and the HPET value are stored together and can be read in a |
---|
776 | 669 | * single atomic 64-bit read. It is explicitly assumed that arch_spinlock_t |
---|
777 | 670 | * is 32 bits in size. |
---|
778 | 671 | */ |
---|
.. | .. |
---|
861 | 754 | .resume = hpet_resume_counter, |
---|
862 | 755 | }; |
---|
863 | 756 | |
---|
864 | | -static int hpet_clocksource_register(void) |
---|
| 757 | +/* |
---|
| 758 | + * AMD SB700 based systems with spread spectrum enabled use a SMM based |
---|
| 759 | + * HPET emulation to provide proper frequency setting. |
---|
| 760 | + * |
---|
| 761 | + * On such systems the SMM code is initialized with the first HPET register |
---|
| 762 | + * access and takes some time to complete. During this time the config |
---|
| 763 | + * register reads 0xffffffff. We check for max 1000 loops whether the |
---|
| 764 | + * config register reads a non-0xffffffff value to make sure that the |
---|
| 765 | + * HPET is up and running before we proceed any further. |
---|
| 766 | + * |
---|
| 767 | + * A counting loop is safe, as the HPET access takes thousands of CPU cycles. |
---|
| 768 | + * |
---|
| 769 | + * On non-SB700 based machines this check is only done once and has no |
---|
| 770 | + * side effects. |
---|
| 771 | + */ |
---|
| 772 | +static bool __init hpet_cfg_working(void) |
---|
865 | 773 | { |
---|
866 | | - u64 start, now; |
---|
867 | | - u64 t1; |
---|
| 774 | + int i; |
---|
868 | 775 | |
---|
869 | | - /* Start the counter */ |
---|
| 776 | + for (i = 0; i < 1000; i++) { |
---|
| 777 | + if (hpet_readl(HPET_CFG) != 0xFFFFFFFF) |
---|
| 778 | + return true; |
---|
| 779 | + } |
---|
| 780 | + |
---|
| 781 | + pr_warn("Config register invalid. Disabling HPET\n"); |
---|
| 782 | + return false; |
---|
| 783 | +} |
---|
| 784 | + |
---|
| 785 | +static bool __init hpet_counting(void) |
---|
| 786 | +{ |
---|
| 787 | + u64 start, now, t1; |
---|
| 788 | + |
---|
870 | 789 | hpet_restart_counter(); |
---|
871 | 790 | |
---|
872 | | - /* Verify whether hpet counter works */ |
---|
873 | 791 | t1 = hpet_readl(HPET_COUNTER); |
---|
874 | 792 | start = rdtsc(); |
---|
875 | 793 | |
---|
.. | .. |
---|
880 | 798 | * 1 GHz == 200us |
---|
881 | 799 | */ |
---|
882 | 800 | do { |
---|
883 | | - rep_nop(); |
---|
| 801 | + if (t1 != hpet_readl(HPET_COUNTER)) |
---|
| 802 | + return true; |
---|
884 | 803 | now = rdtsc(); |
---|
885 | 804 | } while ((now - start) < 200000UL); |
---|
886 | 805 | |
---|
887 | | - if (t1 == hpet_readl(HPET_COUNTER)) { |
---|
888 | | - printk(KERN_WARNING |
---|
889 | | - "HPET counter not counting. HPET disabled\n"); |
---|
890 | | - return -ENODEV; |
---|
891 | | - } |
---|
892 | | - |
---|
893 | | - clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); |
---|
894 | | - return 0; |
---|
| 806 | + pr_warn("Counter not counting. HPET disabled\n"); |
---|
| 807 | + return false; |
---|
895 | 808 | } |
---|
896 | 809 | |
---|
897 | | -static u32 *hpet_boot_cfg; |
---|
| 810 | +static bool __init mwait_pc10_supported(void) |
---|
| 811 | +{ |
---|
| 812 | + unsigned int eax, ebx, ecx, mwait_substates; |
---|
| 813 | + |
---|
| 814 | + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) |
---|
| 815 | + return false; |
---|
| 816 | + |
---|
| 817 | + if (!cpu_feature_enabled(X86_FEATURE_MWAIT)) |
---|
| 818 | + return false; |
---|
| 819 | + |
---|
| 820 | + if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) |
---|
| 821 | + return false; |
---|
| 822 | + |
---|
| 823 | + cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates); |
---|
| 824 | + |
---|
| 825 | + return (ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) && |
---|
| 826 | + (ecx & CPUID5_ECX_INTERRUPT_BREAK) && |
---|
| 827 | + (mwait_substates & (0xF << 28)); |
---|
| 828 | +} |
---|
| 829 | + |
---|
| 830 | +/* |
---|
| 831 | + * Check whether the system supports PC10. If so force disable HPET as that |
---|
| 832 | + * stops counting in PC10. This check is overbroad as it does not take any |
---|
| 833 | + * of the following into account: |
---|
| 834 | + * |
---|
| 835 | + * - ACPI tables |
---|
| 836 | + * - Enablement of intel_idle |
---|
| 837 | + * - Command line arguments which limit intel_idle C-state support |
---|
| 838 | + * |
---|
| 839 | + * That's perfectly fine. HPET is a piece of hardware designed by committee |
---|
| 840 | + * and the only reasons why it is still in use on modern systems is the |
---|
| 841 | + * fact that it is impossible to reliably query TSC and CPU frequency via |
---|
| 842 | + * CPUID or firmware. |
---|
| 843 | + * |
---|
| 844 | + * If HPET is functional it is useful for calibrating TSC, but this can be |
---|
| 845 | + * done via PMTIMER as well which seems to be the last remaining timer on |
---|
| 846 | + * X86/INTEL platforms that has not been completely wreckaged by feature |
---|
| 847 | + * creep. |
---|
| 848 | + * |
---|
| 849 | + * In theory HPET support should be removed altogether, but there are older |
---|
| 850 | + * systems out there which depend on it because TSC and APIC timer are |
---|
| 851 | + * dysfunctional in deeper C-states. |
---|
| 852 | + * |
---|
| 853 | + * It's only 20 years now that hardware people have been asked to provide |
---|
| 854 | + * reliable and discoverable facilities which can be used for timekeeping |
---|
| 855 | + * and per CPU timer interrupts. |
---|
| 856 | + * |
---|
| 857 | + * The probability that this problem is going to be solved in the |
---|
| 858 | + * forseeable future is close to zero, so the kernel has to be cluttered |
---|
| 859 | + * with heuristics to keep up with the ever growing amount of hardware and |
---|
| 860 | + * firmware trainwrecks. Hopefully some day hardware people will understand |
---|
| 861 | + * that the approach of "This can be fixed in software" is not sustainable. |
---|
| 862 | + * Hope dies last... |
---|
| 863 | + */ |
---|
| 864 | +static bool __init hpet_is_pc10_damaged(void) |
---|
| 865 | +{ |
---|
| 866 | + unsigned long long pcfg; |
---|
| 867 | + |
---|
| 868 | + /* Check whether PC10 substates are supported */ |
---|
| 869 | + if (!mwait_pc10_supported()) |
---|
| 870 | + return false; |
---|
| 871 | + |
---|
| 872 | + /* Check whether PC10 is enabled in PKG C-state limit */ |
---|
| 873 | + rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, pcfg); |
---|
| 874 | + if ((pcfg & 0xF) < 8) |
---|
| 875 | + return false; |
---|
| 876 | + |
---|
| 877 | + if (hpet_force_user) { |
---|
| 878 | + pr_warn("HPET force enabled via command line, but dysfunctional in PC10.\n"); |
---|
| 879 | + return false; |
---|
| 880 | + } |
---|
| 881 | + |
---|
| 882 | + pr_info("HPET dysfunctional in PC10. Force disabled.\n"); |
---|
| 883 | + boot_hpet_disable = true; |
---|
| 884 | + return true; |
---|
| 885 | +} |
---|
898 | 886 | |
---|
899 | 887 | /** |
---|
900 | 888 | * hpet_enable - Try to setup the HPET timer. Returns 1 on success. |
---|
901 | 889 | */ |
---|
902 | 890 | int __init hpet_enable(void) |
---|
903 | 891 | { |
---|
904 | | - u32 hpet_period, cfg, id; |
---|
| 892 | + u32 hpet_period, cfg, id, irq; |
---|
| 893 | + unsigned int i, channels; |
---|
| 894 | + struct hpet_channel *hc; |
---|
905 | 895 | u64 freq; |
---|
906 | | - unsigned int i, last; |
---|
907 | 896 | |
---|
908 | 897 | if (!is_hpet_capable()) |
---|
| 898 | + return 0; |
---|
| 899 | + |
---|
| 900 | + if (hpet_is_pc10_damaged()) |
---|
909 | 901 | return 0; |
---|
910 | 902 | |
---|
911 | 903 | hpet_set_mapping(); |
---|
912 | 904 | if (!hpet_virt_address) |
---|
913 | 905 | return 0; |
---|
914 | 906 | |
---|
| 907 | + /* Validate that the config register is working */ |
---|
| 908 | + if (!hpet_cfg_working()) |
---|
| 909 | + goto out_nohpet; |
---|
| 910 | + |
---|
915 | 911 | /* |
---|
916 | 912 | * Read the period and check for a sane value: |
---|
917 | 913 | */ |
---|
918 | 914 | hpet_period = hpet_readl(HPET_PERIOD); |
---|
919 | | - |
---|
920 | | - /* |
---|
921 | | - * AMD SB700 based systems with spread spectrum enabled use a |
---|
922 | | - * SMM based HPET emulation to provide proper frequency |
---|
923 | | - * setting. The SMM code is initialized with the first HPET |
---|
924 | | - * register access and takes some time to complete. During |
---|
925 | | - * this time the config register reads 0xffffffff. We check |
---|
926 | | - * for max. 1000 loops whether the config register reads a non |
---|
927 | | - * 0xffffffff value to make sure that HPET is up and running |
---|
928 | | - * before we go further. A counting loop is safe, as the HPET |
---|
929 | | - * access takes thousands of CPU cycles. On non SB700 based |
---|
930 | | - * machines this check is only done once and has no side |
---|
931 | | - * effects. |
---|
932 | | - */ |
---|
933 | | - for (i = 0; hpet_readl(HPET_CFG) == 0xFFFFFFFF; i++) { |
---|
934 | | - if (i == 1000) { |
---|
935 | | - printk(KERN_WARNING |
---|
936 | | - "HPET config register value = 0xFFFFFFFF. " |
---|
937 | | - "Disabling HPET\n"); |
---|
938 | | - goto out_nohpet; |
---|
939 | | - } |
---|
940 | | - } |
---|
941 | | - |
---|
942 | 915 | if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) |
---|
943 | 916 | goto out_nohpet; |
---|
944 | 917 | |
---|
945 | | - /* |
---|
946 | | - * The period is a femto seconds value. Convert it to a |
---|
947 | | - * frequency. |
---|
948 | | - */ |
---|
| 918 | + /* The period is a femtoseconds value. Convert it to a frequency. */ |
---|
949 | 919 | freq = FSEC_PER_SEC; |
---|
950 | 920 | do_div(freq, hpet_period); |
---|
951 | 921 | hpet_freq = freq; |
---|
.. | .. |
---|
957 | 927 | id = hpet_readl(HPET_ID); |
---|
958 | 928 | hpet_print_config(); |
---|
959 | 929 | |
---|
960 | | - last = (id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; |
---|
| 930 | + /* This is the HPET channel number which is zero based */ |
---|
| 931 | + channels = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
---|
961 | 932 | |
---|
962 | | -#ifdef CONFIG_HPET_EMULATE_RTC |
---|
963 | 933 | /* |
---|
964 | 934 | * The legacy routing mode needs at least two channels, tick timer |
---|
965 | 935 | * and the rtc emulation channel. |
---|
966 | 936 | */ |
---|
967 | | - if (!last) |
---|
| 937 | + if (IS_ENABLED(CONFIG_HPET_EMULATE_RTC) && channels < 2) |
---|
968 | 938 | goto out_nohpet; |
---|
969 | | -#endif |
---|
970 | 939 | |
---|
| 940 | + hc = kcalloc(channels, sizeof(*hc), GFP_KERNEL); |
---|
| 941 | + if (!hc) { |
---|
| 942 | + pr_warn("Disabling HPET.\n"); |
---|
| 943 | + goto out_nohpet; |
---|
| 944 | + } |
---|
| 945 | + hpet_base.channels = hc; |
---|
| 946 | + hpet_base.nr_channels = channels; |
---|
| 947 | + |
---|
| 948 | + /* Read, store and sanitize the global configuration */ |
---|
971 | 949 | cfg = hpet_readl(HPET_CFG); |
---|
972 | | - hpet_boot_cfg = kmalloc_array(last + 2, sizeof(*hpet_boot_cfg), |
---|
973 | | - GFP_KERNEL); |
---|
974 | | - if (hpet_boot_cfg) |
---|
975 | | - *hpet_boot_cfg = cfg; |
---|
976 | | - else |
---|
977 | | - pr_warn("HPET initial state will not be saved\n"); |
---|
| 950 | + hpet_base.boot_cfg = cfg; |
---|
978 | 951 | cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); |
---|
979 | 952 | hpet_writel(cfg, HPET_CFG); |
---|
980 | 953 | if (cfg) |
---|
981 | | - pr_warn("Unrecognized bits %#x set in global cfg\n", cfg); |
---|
| 954 | + pr_warn("Global config: Unknown bits %#x\n", cfg); |
---|
982 | 955 | |
---|
983 | | - for (i = 0; i <= last; ++i) { |
---|
| 956 | + /* Read, store and sanitize the per channel configuration */ |
---|
| 957 | + for (i = 0; i < channels; i++, hc++) { |
---|
| 958 | + hc->num = i; |
---|
| 959 | + |
---|
984 | 960 | cfg = hpet_readl(HPET_Tn_CFG(i)); |
---|
985 | | - if (hpet_boot_cfg) |
---|
986 | | - hpet_boot_cfg[i + 1] = cfg; |
---|
| 961 | + hc->boot_cfg = cfg; |
---|
| 962 | + irq = (cfg & Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT; |
---|
| 963 | + hc->irq = irq; |
---|
| 964 | + |
---|
987 | 965 | cfg &= ~(HPET_TN_ENABLE | HPET_TN_LEVEL | HPET_TN_FSB); |
---|
988 | 966 | hpet_writel(cfg, HPET_Tn_CFG(i)); |
---|
| 967 | + |
---|
989 | 968 | cfg &= ~(HPET_TN_PERIODIC | HPET_TN_PERIODIC_CAP |
---|
990 | 969 | | HPET_TN_64BIT_CAP | HPET_TN_32BIT | HPET_TN_ROUTE |
---|
991 | 970 | | HPET_TN_FSB | HPET_TN_FSB_CAP); |
---|
992 | 971 | if (cfg) |
---|
993 | | - pr_warn("Unrecognized bits %#x set in cfg#%u\n", |
---|
994 | | - cfg, i); |
---|
| 972 | + pr_warn("Channel #%u config: Unknown bits %#x\n", i, cfg); |
---|
995 | 973 | } |
---|
996 | 974 | hpet_print_config(); |
---|
997 | 975 | |
---|
998 | | - if (hpet_clocksource_register()) |
---|
| 976 | + /* |
---|
| 977 | + * Validate that the counter is counting. This needs to be done |
---|
| 978 | + * after sanitizing the config registers to properly deal with |
---|
| 979 | + * force enabled HPETs. |
---|
| 980 | + */ |
---|
| 981 | + if (!hpet_counting()) |
---|
999 | 982 | goto out_nohpet; |
---|
1000 | 983 | |
---|
| 984 | + clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); |
---|
| 985 | + |
---|
1001 | 986 | if (id & HPET_ID_LEGSUP) { |
---|
1002 | | - hpet_legacy_clockevent_register(); |
---|
| 987 | + hpet_legacy_clockevent_register(&hpet_base.channels[0]); |
---|
| 988 | + hpet_base.channels[0].mode = HPET_MODE_LEGACY; |
---|
| 989 | + if (IS_ENABLED(CONFIG_HPET_EMULATE_RTC)) |
---|
| 990 | + hpet_base.channels[1].mode = HPET_MODE_LEGACY; |
---|
1003 | 991 | return 1; |
---|
1004 | 992 | } |
---|
1005 | 993 | return 0; |
---|
1006 | 994 | |
---|
1007 | 995 | out_nohpet: |
---|
| 996 | + kfree(hpet_base.channels); |
---|
| 997 | + hpet_base.channels = NULL; |
---|
| 998 | + hpet_base.nr_channels = 0; |
---|
1008 | 999 | hpet_clear_mapping(); |
---|
1009 | 1000 | hpet_address = 0; |
---|
1010 | 1001 | return 0; |
---|
1011 | 1002 | } |
---|
1012 | 1003 | |
---|
1013 | 1004 | /* |
---|
1014 | | - * Needs to be late, as the reserve_timer code calls kalloc ! |
---|
| 1005 | + * The late initialization runs after the PCI quirks have been invoked |
---|
| 1006 | + * which might have detected a system on which the HPET can be enforced. |
---|
1015 | 1007 | * |
---|
1016 | | - * Not a problem on i386 as hpet_enable is called from late_time_init, |
---|
1017 | | - * but on x86_64 it is necessary ! |
---|
| 1008 | + * Also, the MSI machinery is not working yet when the HPET is initialized |
---|
| 1009 | + * early. |
---|
| 1010 | + * |
---|
| 1011 | + * If the HPET is enabled, then: |
---|
| 1012 | + * |
---|
| 1013 | + * 1) Reserve one channel for /dev/hpet if CONFIG_HPET=y |
---|
| 1014 | + * 2) Reserve up to num_possible_cpus() channels as per CPU clockevents |
---|
| 1015 | + * 3) Setup /dev/hpet if CONFIG_HPET=y |
---|
| 1016 | + * 4) Register hotplug callbacks when clockevents are available |
---|
1018 | 1017 | */ |
---|
1019 | 1018 | static __init int hpet_late_init(void) |
---|
1020 | 1019 | { |
---|
1021 | 1020 | int ret; |
---|
1022 | | - |
---|
1023 | | - if (boot_hpet_disable) |
---|
1024 | | - return -ENODEV; |
---|
1025 | 1021 | |
---|
1026 | 1022 | if (!hpet_address) { |
---|
1027 | 1023 | if (!force_hpet_address) |
---|
.. | .. |
---|
1034 | 1030 | if (!hpet_virt_address) |
---|
1035 | 1031 | return -ENODEV; |
---|
1036 | 1032 | |
---|
1037 | | - if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP) |
---|
1038 | | - hpet_msi_capability_lookup(2); |
---|
1039 | | - else |
---|
1040 | | - hpet_msi_capability_lookup(0); |
---|
1041 | | - |
---|
1042 | | - hpet_reserve_platform_timers(hpet_readl(HPET_ID)); |
---|
| 1033 | + hpet_select_device_channel(); |
---|
| 1034 | + hpet_select_clockevents(); |
---|
| 1035 | + hpet_reserve_platform_timers(); |
---|
1043 | 1036 | hpet_print_config(); |
---|
1044 | 1037 | |
---|
1045 | | - if (hpet_msi_disable) |
---|
| 1038 | + if (!hpet_base.nr_clockevents) |
---|
1046 | 1039 | return 0; |
---|
1047 | 1040 | |
---|
1048 | | - if (boot_cpu_has(X86_FEATURE_ARAT)) |
---|
1049 | | - return 0; |
---|
1050 | | - |
---|
1051 | | - /* This notifier should be called after workqueue is ready */ |
---|
1052 | 1041 | ret = cpuhp_setup_state(CPUHP_AP_X86_HPET_ONLINE, "x86/hpet:online", |
---|
1053 | 1042 | hpet_cpuhp_online, NULL); |
---|
1054 | 1043 | if (ret) |
---|
.. | .. |
---|
1067 | 1056 | |
---|
1068 | 1057 | void hpet_disable(void) |
---|
1069 | 1058 | { |
---|
1070 | | - if (is_hpet_capable() && hpet_virt_address) { |
---|
1071 | | - unsigned int cfg = hpet_readl(HPET_CFG), id, last; |
---|
| 1059 | + unsigned int i; |
---|
| 1060 | + u32 cfg; |
---|
1072 | 1061 | |
---|
1073 | | - if (hpet_boot_cfg) |
---|
1074 | | - cfg = *hpet_boot_cfg; |
---|
1075 | | - else if (hpet_legacy_int_enabled) { |
---|
1076 | | - cfg &= ~HPET_CFG_LEGACY; |
---|
1077 | | - hpet_legacy_int_enabled = false; |
---|
1078 | | - } |
---|
1079 | | - cfg &= ~HPET_CFG_ENABLE; |
---|
1080 | | - hpet_writel(cfg, HPET_CFG); |
---|
| 1062 | + if (!is_hpet_capable() || !hpet_virt_address) |
---|
| 1063 | + return; |
---|
1081 | 1064 | |
---|
1082 | | - if (!hpet_boot_cfg) |
---|
1083 | | - return; |
---|
| 1065 | + /* Restore boot configuration with the enable bit cleared */ |
---|
| 1066 | + cfg = hpet_base.boot_cfg; |
---|
| 1067 | + cfg &= ~HPET_CFG_ENABLE; |
---|
| 1068 | + hpet_writel(cfg, HPET_CFG); |
---|
1084 | 1069 | |
---|
1085 | | - id = hpet_readl(HPET_ID); |
---|
1086 | | - last = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); |
---|
| 1070 | + /* Restore the channel boot configuration */ |
---|
| 1071 | + for (i = 0; i < hpet_base.nr_channels; i++) |
---|
| 1072 | + hpet_writel(hpet_base.channels[i].boot_cfg, HPET_Tn_CFG(i)); |
---|
1087 | 1073 | |
---|
1088 | | - for (id = 0; id <= last; ++id) |
---|
1089 | | - hpet_writel(hpet_boot_cfg[id + 1], HPET_Tn_CFG(id)); |
---|
1090 | | - |
---|
1091 | | - if (*hpet_boot_cfg & HPET_CFG_ENABLE) |
---|
1092 | | - hpet_writel(*hpet_boot_cfg, HPET_CFG); |
---|
1093 | | - } |
---|
| 1074 | + /* If the HPET was enabled at boot time, reenable it */ |
---|
| 1075 | + if (hpet_base.boot_cfg & HPET_CFG_ENABLE) |
---|
| 1076 | + hpet_writel(hpet_base.boot_cfg, HPET_CFG); |
---|
1094 | 1077 | } |
---|
1095 | 1078 | |
---|
1096 | 1079 | #ifdef CONFIG_HPET_EMULATE_RTC |
---|
1097 | 1080 | |
---|
1098 | | -/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET |
---|
| 1081 | +/* |
---|
| 1082 | + * HPET in LegacyReplacement mode eats up the RTC interrupt line. When HPET |
---|
1099 | 1083 | * is enabled, we support RTC interrupt functionality in software. |
---|
| 1084 | + * |
---|
1100 | 1085 | * RTC has 3 kinds of interrupts: |
---|
1101 | | - * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock |
---|
1102 | | - * is updated |
---|
1103 | | - * 2) Alarm Interrupt - generate an interrupt at a specific time of day |
---|
1104 | | - * 3) Periodic Interrupt - generate periodic interrupt, with frequencies |
---|
1105 | | - * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) |
---|
1106 | | - * (1) and (2) above are implemented using polling at a frequency of |
---|
1107 | | - * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt |
---|
1108 | | - * overhead. (DEFAULT_RTC_INT_FREQ) |
---|
1109 | | - * For (3), we use interrupts at 64Hz or user specified periodic |
---|
1110 | | - * frequency, whichever is higher. |
---|
| 1086 | + * |
---|
| 1087 | + * 1) Update Interrupt - generate an interrupt, every second, when the |
---|
| 1088 | + * RTC clock is updated |
---|
| 1089 | + * 2) Alarm Interrupt - generate an interrupt at a specific time of day |
---|
| 1090 | + * 3) Periodic Interrupt - generate periodic interrupt, with frequencies |
---|
| 1091 | + * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all frequencies in powers of 2) |
---|
| 1092 | + * |
---|
| 1093 | + * (1) and (2) above are implemented using polling at a frequency of 64 Hz: |
---|
| 1094 | + * DEFAULT_RTC_INT_FREQ. |
---|
| 1095 | + * |
---|
| 1096 | + * The exact frequency is a tradeoff between accuracy and interrupt overhead. |
---|
| 1097 | + * |
---|
| 1098 | + * For (3), we use interrupts at 64 Hz, or the user specified periodic frequency, |
---|
| 1099 | + * if it's higher. |
---|
1111 | 1100 | */ |
---|
1112 | 1101 | #include <linux/mc146818rtc.h> |
---|
1113 | 1102 | #include <linux/rtc.h> |
---|
.. | .. |
---|
1128 | 1117 | static rtc_irq_handler irq_handler; |
---|
1129 | 1118 | |
---|
1130 | 1119 | /* |
---|
1131 | | - * Check that the hpet counter c1 is ahead of the c2 |
---|
| 1120 | + * Check that the HPET counter c1 is ahead of c2 |
---|
1132 | 1121 | */ |
---|
1133 | 1122 | static inline int hpet_cnt_ahead(u32 c1, u32 c2) |
---|
1134 | 1123 | { |
---|
.. | .. |
---|
1166 | 1155 | EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler); |
---|
1167 | 1156 | |
---|
1168 | 1157 | /* |
---|
1169 | | - * Timer 1 for RTC emulation. We use one shot mode, as periodic mode |
---|
1170 | | - * is not supported by all HPET implementations for timer 1. |
---|
| 1158 | + * Channel 1 for RTC emulation. We use one shot mode, as periodic mode |
---|
| 1159 | + * is not supported by all HPET implementations for channel 1. |
---|
1171 | 1160 | * |
---|
1172 | 1161 | * hpet_rtc_timer_init() is called when the rtc is initialized. |
---|
1173 | 1162 | */ |
---|
.. | .. |
---|
1180 | 1169 | return 0; |
---|
1181 | 1170 | |
---|
1182 | 1171 | if (!hpet_default_delta) { |
---|
| 1172 | + struct clock_event_device *evt = &hpet_base.channels[0].evt; |
---|
1183 | 1173 | uint64_t clc; |
---|
1184 | 1174 | |
---|
1185 | | - clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
---|
1186 | | - clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; |
---|
| 1175 | + clc = (uint64_t) evt->mult * NSEC_PER_SEC; |
---|
| 1176 | + clc >>= evt->shift + DEFAULT_RTC_SHIFT; |
---|
1187 | 1177 | hpet_default_delta = clc; |
---|
1188 | 1178 | } |
---|
1189 | 1179 | |
---|
.. | .. |
---|
1212 | 1202 | static void hpet_disable_rtc_channel(void) |
---|
1213 | 1203 | { |
---|
1214 | 1204 | u32 cfg = hpet_readl(HPET_T1_CFG); |
---|
| 1205 | + |
---|
1215 | 1206 | cfg &= ~HPET_TN_ENABLE; |
---|
1216 | 1207 | hpet_writel(cfg, HPET_T1_CFG); |
---|
1217 | 1208 | } |
---|
.. | .. |
---|
1253 | 1244 | } |
---|
1254 | 1245 | EXPORT_SYMBOL_GPL(hpet_set_rtc_irq_bit); |
---|
1255 | 1246 | |
---|
1256 | | -int hpet_set_alarm_time(unsigned char hrs, unsigned char min, |
---|
1257 | | - unsigned char sec) |
---|
| 1247 | +int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) |
---|
1258 | 1248 | { |
---|
1259 | 1249 | if (!is_hpet_enabled()) |
---|
1260 | 1250 | return 0; |
---|
.. | .. |
---|
1274 | 1264 | if (!is_hpet_enabled()) |
---|
1275 | 1265 | return 0; |
---|
1276 | 1266 | |
---|
1277 | | - if (freq <= DEFAULT_RTC_INT_FREQ) |
---|
| 1267 | + if (freq <= DEFAULT_RTC_INT_FREQ) { |
---|
1278 | 1268 | hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq; |
---|
1279 | | - else { |
---|
1280 | | - clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
---|
| 1269 | + } else { |
---|
| 1270 | + struct clock_event_device *evt = &hpet_base.channels[0].evt; |
---|
| 1271 | + |
---|
| 1272 | + clc = (uint64_t) evt->mult * NSEC_PER_SEC; |
---|
1281 | 1273 | do_div(clc, freq); |
---|
1282 | | - clc >>= hpet_clockevent.shift; |
---|
| 1274 | + clc >>= evt->shift; |
---|
1283 | 1275 | hpet_pie_delta = clc; |
---|
1284 | 1276 | hpet_pie_limit = 0; |
---|
1285 | 1277 | } |
---|
| 1278 | + |
---|
1286 | 1279 | return 1; |
---|
1287 | 1280 | } |
---|
1288 | 1281 | EXPORT_SYMBOL_GPL(hpet_set_periodic_freq); |
---|
.. | .. |
---|
1320 | 1313 | if (hpet_rtc_flags & RTC_PIE) |
---|
1321 | 1314 | hpet_pie_count += lost_ints; |
---|
1322 | 1315 | if (printk_ratelimit()) |
---|
1323 | | - printk(KERN_WARNING "hpet1: lost %d rtc interrupts\n", |
---|
1324 | | - lost_ints); |
---|
| 1316 | + pr_warn("Lost %d RTC interrupts\n", lost_ints); |
---|
1325 | 1317 | } |
---|
1326 | 1318 | } |
---|
1327 | 1319 | |
---|
.. | .. |
---|
1333 | 1325 | hpet_rtc_timer_reinit(); |
---|
1334 | 1326 | memset(&curr_time, 0, sizeof(struct rtc_time)); |
---|
1335 | 1327 | |
---|
1336 | | - if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) |
---|
1337 | | - mc146818_get_time(&curr_time); |
---|
| 1328 | + if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) { |
---|
| 1329 | + if (unlikely(mc146818_get_time(&curr_time) < 0)) { |
---|
| 1330 | + pr_err_ratelimited("unable to read current time from RTC\n"); |
---|
| 1331 | + return IRQ_HANDLED; |
---|
| 1332 | + } |
---|
| 1333 | + } |
---|
1338 | 1334 | |
---|
1339 | 1335 | if (hpet_rtc_flags & RTC_UIE && |
---|
1340 | 1336 | curr_time.tm_sec != hpet_prev_update_sec) { |
---|
.. | .. |
---|
1343 | 1339 | hpet_prev_update_sec = curr_time.tm_sec; |
---|
1344 | 1340 | } |
---|
1345 | 1341 | |
---|
1346 | | - if (hpet_rtc_flags & RTC_PIE && |
---|
1347 | | - ++hpet_pie_count >= hpet_pie_limit) { |
---|
| 1342 | + if (hpet_rtc_flags & RTC_PIE && ++hpet_pie_count >= hpet_pie_limit) { |
---|
1348 | 1343 | rtc_int_flag |= RTC_PF; |
---|
1349 | 1344 | hpet_pie_count = 0; |
---|
1350 | 1345 | } |
---|
.. | .. |
---|
1353 | 1348 | (curr_time.tm_sec == hpet_alarm_time.tm_sec) && |
---|
1354 | 1349 | (curr_time.tm_min == hpet_alarm_time.tm_min) && |
---|
1355 | 1350 | (curr_time.tm_hour == hpet_alarm_time.tm_hour)) |
---|
1356 | | - rtc_int_flag |= RTC_AF; |
---|
| 1351 | + rtc_int_flag |= RTC_AF; |
---|
1357 | 1352 | |
---|
1358 | 1353 | if (rtc_int_flag) { |
---|
1359 | 1354 | rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); |
---|