diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/apb_timer.c | 784 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 86 | ||||
-rw-r--r-- | arch/x86/kernel/apic/nmi.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/numaq_32.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/i8259.c | 64 | ||||
-rw-r--r-- | arch/x86/kernel/irqinit.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/mrst.c | 216 | ||||
-rw-r--r-- | arch/x86/kernel/olpc.c | 10 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/visws_quirks.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/x86_init.c | 8 |
14 files changed, 1157 insertions, 66 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index d87f09bc5a52..4c58352209e0 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -87,6 +87,7 @@ obj-$(CONFIG_VM86) += vm86_32.o | |||
87 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 87 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
88 | 88 | ||
89 | obj-$(CONFIG_HPET_TIMER) += hpet.o | 89 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
90 | obj-$(CONFIG_APB_TIMER) += apb_timer.o | ||
90 | 91 | ||
91 | obj-$(CONFIG_K8_NB) += k8.o | 92 | obj-$(CONFIG_K8_NB) += k8.o |
92 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o | 93 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 738fcb60e708..a54d714545ff 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/ioport.h> | 35 | #include <linux/ioport.h> |
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | 37 | ||
38 | #include <asm/pci_x86.h> | ||
38 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
39 | #include <asm/io_apic.h> | 40 | #include <asm/io_apic.h> |
40 | #include <asm/apic.h> | 41 | #include <asm/apic.h> |
@@ -1624,6 +1625,9 @@ int __init acpi_boot_init(void) | |||
1624 | 1625 | ||
1625 | acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); | 1626 | acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); |
1626 | 1627 | ||
1628 | if (!acpi_noirq) | ||
1629 | x86_init.pci.init = pci_acpi_init; | ||
1630 | |||
1627 | return 0; | 1631 | return 0; |
1628 | } | 1632 | } |
1629 | 1633 | ||
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c new file mode 100644 index 000000000000..4b7099526d2c --- /dev/null +++ b/arch/x86/kernel/apb_timer.c | |||
@@ -0,0 +1,784 @@ | |||
1 | /* | ||
2 | * apb_timer.c: Driver for Langwell APB timers | ||
3 | * | ||
4 | * (C) Copyright 2009 Intel Corporation | ||
5 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; version 2 | ||
10 | * of the License. | ||
11 | * | ||
12 | * Note: | ||
13 | * Langwell is the south complex of Intel Moorestown MID platform. There are | ||
14 | * eight external timers in total that can be used by the operating system. | ||
15 | * The timer information, such as frequency and addresses, is provided to the | ||
16 | * OS via SFI tables. | ||
17 | * Timer interrupts are routed via FW/HW emulated IOAPIC independently via | ||
18 | * individual redirection table entries (RTE). | ||
19 | * Unlike HPET, there is no master counter, therefore one of the timers are | ||
20 | * used as clocksource. The overall allocation looks like: | ||
21 | * - timer 0 - NR_CPUs for per cpu timer | ||
22 | * - one timer for clocksource | ||
23 | * - one timer for watchdog driver. | ||
24 | * It is also worth notice that APB timer does not support true one-shot mode, | ||
25 | * free-running mode will be used here to emulate one-shot mode. | ||
26 | * APB timer can also be used as broadcast timer along with per cpu local APIC | ||
27 | * timer, but by default APB timer has higher rating than local APIC timers. | ||
28 | */ | ||
29 | |||
30 | #include <linux/clocksource.h> | ||
31 | #include <linux/clockchips.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/sysdev.h> | ||
36 | #include <linux/pm.h> | ||
37 | #include <linux/pci.h> | ||
38 | #include <linux/sfi.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/cpu.h> | ||
41 | #include <linux/irq.h> | ||
42 | |||
43 | #include <asm/fixmap.h> | ||
44 | #include <asm/apb_timer.h> | ||
45 | |||
46 | #define APBT_MASK CLOCKSOURCE_MASK(32) | ||
47 | #define APBT_SHIFT 22 | ||
48 | #define APBT_CLOCKEVENT_RATING 150 | ||
49 | #define APBT_CLOCKSOURCE_RATING 250 | ||
50 | #define APBT_MIN_DELTA_USEC 200 | ||
51 | |||
52 | #define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) | ||
53 | #define APBT_CLOCKEVENT0_NUM (0) | ||
54 | #define APBT_CLOCKEVENT1_NUM (1) | ||
55 | #define APBT_CLOCKSOURCE_NUM (2) | ||
56 | |||
57 | static unsigned long apbt_address; | ||
58 | static int apb_timer_block_enabled; | ||
59 | static void __iomem *apbt_virt_address; | ||
60 | static int phy_cs_timer_id; | ||
61 | |||
62 | /* | ||
63 | * Common DW APB timer info | ||
64 | */ | ||
65 | static uint64_t apbt_freq; | ||
66 | |||
67 | static void apbt_set_mode(enum clock_event_mode mode, | ||
68 | struct clock_event_device *evt); | ||
69 | static int apbt_next_event(unsigned long delta, | ||
70 | struct clock_event_device *evt); | ||
71 | static cycle_t apbt_read_clocksource(struct clocksource *cs); | ||
72 | static void apbt_restart_clocksource(struct clocksource *cs); | ||
73 | |||
74 | struct apbt_dev { | ||
75 | struct clock_event_device evt; | ||
76 | unsigned int num; | ||
77 | int cpu; | ||
78 | unsigned int irq; | ||
79 | unsigned int tick; | ||
80 | unsigned int count; | ||
81 | unsigned int flags; | ||
82 | char name[10]; | ||
83 | }; | ||
84 | |||
85 | int disable_apbt_percpu __cpuinitdata; | ||
86 | |||
87 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); | ||
88 | |||
89 | #ifdef CONFIG_SMP | ||
90 | static unsigned int apbt_num_timers_used; | ||
91 | static struct apbt_dev *apbt_devs; | ||
92 | #endif | ||
93 | |||
94 | static inline unsigned long apbt_readl_reg(unsigned long a) | ||
95 | { | ||
96 | return readl(apbt_virt_address + a); | ||
97 | } | ||
98 | |||
99 | static inline void apbt_writel_reg(unsigned long d, unsigned long a) | ||
100 | { | ||
101 | writel(d, apbt_virt_address + a); | ||
102 | } | ||
103 | |||
104 | static inline unsigned long apbt_readl(int n, unsigned long a) | ||
105 | { | ||
106 | return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
107 | } | ||
108 | |||
109 | static inline void apbt_writel(int n, unsigned long d, unsigned long a) | ||
110 | { | ||
111 | writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
112 | } | ||
113 | |||
114 | static inline void apbt_set_mapping(void) | ||
115 | { | ||
116 | struct sfi_timer_table_entry *mtmr; | ||
117 | |||
118 | if (apbt_virt_address) { | ||
119 | pr_debug("APBT base already mapped\n"); | ||
120 | return; | ||
121 | } | ||
122 | mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM); | ||
123 | if (mtmr == NULL) { | ||
124 | printk(KERN_ERR "Failed to get MTMR %d from SFI\n", | ||
125 | APBT_CLOCKEVENT0_NUM); | ||
126 | return; | ||
127 | } | ||
128 | apbt_address = (unsigned long)mtmr->phys_addr; | ||
129 | if (!apbt_address) { | ||
130 | printk(KERN_WARNING "No timer base from SFI, use default\n"); | ||
131 | apbt_address = APBT_DEFAULT_BASE; | ||
132 | } | ||
133 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); | ||
134 | if (apbt_virt_address) { | ||
135 | pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ | ||
136 | (void *)apbt_address, (void *)apbt_virt_address); | ||
137 | } else { | ||
138 | pr_debug("Failed mapping APBT phy address at %p\n",\ | ||
139 | (void *)apbt_address); | ||
140 | goto panic_noapbt; | ||
141 | } | ||
142 | apbt_freq = mtmr->freq_hz / USEC_PER_SEC; | ||
143 | sfi_free_mtmr(mtmr); | ||
144 | |||
145 | /* Now figure out the physical timer id for clocksource device */ | ||
146 | mtmr = sfi_get_mtmr(APBT_CLOCKSOURCE_NUM); | ||
147 | if (mtmr == NULL) | ||
148 | goto panic_noapbt; | ||
149 | |||
150 | /* Now figure out the physical timer id */ | ||
151 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) | ||
152 | / APBTMRS_REG_SIZE; | ||
153 | pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); | ||
154 | return; | ||
155 | |||
156 | panic_noapbt: | ||
157 | panic("Failed to setup APB system timer\n"); | ||
158 | |||
159 | } | ||
160 | |||
161 | static inline void apbt_clear_mapping(void) | ||
162 | { | ||
163 | iounmap(apbt_virt_address); | ||
164 | apbt_virt_address = NULL; | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * APBT timer interrupt enable / disable | ||
169 | */ | ||
170 | static inline int is_apbt_capable(void) | ||
171 | { | ||
172 | return apbt_virt_address ? 1 : 0; | ||
173 | } | ||
174 | |||
175 | static struct clocksource clocksource_apbt = { | ||
176 | .name = "apbt", | ||
177 | .rating = APBT_CLOCKSOURCE_RATING, | ||
178 | .read = apbt_read_clocksource, | ||
179 | .mask = APBT_MASK, | ||
180 | .shift = APBT_SHIFT, | ||
181 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
182 | .resume = apbt_restart_clocksource, | ||
183 | }; | ||
184 | |||
185 | /* boot APB clock event device */ | ||
186 | static struct clock_event_device apbt_clockevent = { | ||
187 | .name = "apbt0", | ||
188 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
189 | .set_mode = apbt_set_mode, | ||
190 | .set_next_event = apbt_next_event, | ||
191 | .shift = APBT_SHIFT, | ||
192 | .irq = 0, | ||
193 | .rating = APBT_CLOCKEVENT_RATING, | ||
194 | }; | ||
195 | |||
196 | /* | ||
197 | * if user does not want to use per CPU apb timer, just give it a lower rating | ||
198 | * than local apic timer and skip the late per cpu timer init. | ||
199 | */ | ||
200 | static inline int __init setup_x86_mrst_timer(char *arg) | ||
201 | { | ||
202 | if (!arg) | ||
203 | return -EINVAL; | ||
204 | |||
205 | if (strcmp("apbt_only", arg) == 0) | ||
206 | disable_apbt_percpu = 0; | ||
207 | else if (strcmp("lapic_and_apbt", arg) == 0) | ||
208 | disable_apbt_percpu = 1; | ||
209 | else { | ||
210 | pr_warning("X86 MRST timer option %s not recognised" | ||
211 | " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | ||
212 | arg); | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | return 0; | ||
216 | } | ||
217 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); | ||
218 | |||
219 | /* | ||
220 | * start count down from 0xffff_ffff. this is done by toggling the enable bit | ||
221 | * then load initial load count to ~0. | ||
222 | */ | ||
223 | static void apbt_start_counter(int n) | ||
224 | { | ||
225 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
226 | |||
227 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
228 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
229 | apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); | ||
230 | /* enable, mask interrupt */ | ||
231 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
232 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
233 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
234 | /* read it once to get cached counter value initialized */ | ||
235 | apbt_read_clocksource(&clocksource_apbt); | ||
236 | } | ||
237 | |||
238 | static irqreturn_t apbt_interrupt_handler(int irq, void *data) | ||
239 | { | ||
240 | struct apbt_dev *dev = (struct apbt_dev *)data; | ||
241 | struct clock_event_device *aevt = &dev->evt; | ||
242 | |||
243 | if (!aevt->event_handler) { | ||
244 | printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", | ||
245 | dev->num); | ||
246 | return IRQ_NONE; | ||
247 | } | ||
248 | aevt->event_handler(aevt); | ||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
253 | { | ||
254 | apbt_start_counter(phy_cs_timer_id); | ||
255 | } | ||
256 | |||
257 | /* Setup IRQ routing via IOAPIC */ | ||
258 | #ifdef CONFIG_SMP | ||
259 | static void apbt_setup_irq(struct apbt_dev *adev) | ||
260 | { | ||
261 | struct irq_chip *chip; | ||
262 | struct irq_desc *desc; | ||
263 | |||
264 | /* timer0 irq has been setup early */ | ||
265 | if (adev->irq == 0) | ||
266 | return; | ||
267 | desc = irq_to_desc(adev->irq); | ||
268 | chip = get_irq_chip(adev->irq); | ||
269 | disable_irq(adev->irq); | ||
270 | desc->status |= IRQ_MOVE_PCNTXT; | ||
271 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); | ||
272 | /* APB timer irqs are set up as mp_irqs, timer is edge triggerred */ | ||
273 | set_irq_chip_and_handler_name(adev->irq, chip, handle_edge_irq, "edge"); | ||
274 | enable_irq(adev->irq); | ||
275 | if (system_state == SYSTEM_BOOTING) | ||
276 | if (request_irq(adev->irq, apbt_interrupt_handler, | ||
277 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
278 | adev->name, adev)) { | ||
279 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
280 | adev->num); | ||
281 | } | ||
282 | } | ||
283 | #endif | ||
284 | |||
285 | static void apbt_enable_int(int n) | ||
286 | { | ||
287 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
288 | /* clear pending intr */ | ||
289 | apbt_readl(n, APBTMR_N_EOI); | ||
290 | ctrl &= ~APBTMR_CONTROL_INT; | ||
291 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
292 | } | ||
293 | |||
294 | static void apbt_disable_int(int n) | ||
295 | { | ||
296 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
297 | |||
298 | ctrl |= APBTMR_CONTROL_INT; | ||
299 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
300 | } | ||
301 | |||
302 | |||
303 | static int __init apbt_clockevent_register(void) | ||
304 | { | ||
305 | struct sfi_timer_table_entry *mtmr; | ||
306 | struct apbt_dev *adev = &__get_cpu_var(cpu_apbt_dev); | ||
307 | |||
308 | mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM); | ||
309 | if (mtmr == NULL) { | ||
310 | printk(KERN_ERR "Failed to get MTMR %d from SFI\n", | ||
311 | APBT_CLOCKEVENT0_NUM); | ||
312 | return -ENODEV; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * We need to calculate the scaled math multiplication factor for | ||
317 | * nanosecond to apbt tick conversion. | ||
318 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
319 | */ | ||
320 | apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz | ||
321 | , NSEC_PER_SEC, APBT_SHIFT); | ||
322 | |||
323 | /* Calculate the min / max delta */ | ||
324 | apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
325 | &apbt_clockevent); | ||
326 | apbt_clockevent.min_delta_ns = clockevent_delta2ns( | ||
327 | APBT_MIN_DELTA_USEC*apbt_freq, | ||
328 | &apbt_clockevent); | ||
329 | /* | ||
330 | * Start apbt with the boot cpu mask and make it | ||
331 | * global if not used for per cpu timer. | ||
332 | */ | ||
333 | apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); | ||
334 | adev->num = smp_processor_id(); | ||
335 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); | ||
336 | |||
337 | if (disable_apbt_percpu) { | ||
338 | apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100; | ||
339 | global_clock_event = &adev->evt; | ||
340 | printk(KERN_DEBUG "%s clockevent registered as global\n", | ||
341 | global_clock_event->name); | ||
342 | } | ||
343 | |||
344 | if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, | ||
345 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
346 | apbt_clockevent.name, adev)) { | ||
347 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
348 | apbt_clockevent.irq); | ||
349 | } | ||
350 | |||
351 | clockevents_register_device(&adev->evt); | ||
352 | /* Start APBT 0 interrupts */ | ||
353 | apbt_enable_int(APBT_CLOCKEVENT0_NUM); | ||
354 | |||
355 | sfi_free_mtmr(mtmr); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | #ifdef CONFIG_SMP | ||
360 | /* Should be called with per cpu */ | ||
361 | void apbt_setup_secondary_clock(void) | ||
362 | { | ||
363 | struct apbt_dev *adev; | ||
364 | struct clock_event_device *aevt; | ||
365 | int cpu; | ||
366 | |||
367 | /* Don't register boot CPU clockevent */ | ||
368 | cpu = smp_processor_id(); | ||
369 | if (cpu == boot_cpu_id) | ||
370 | return; | ||
371 | /* | ||
372 | * We need to calculate the scaled math multiplication factor for | ||
373 | * nanosecond to apbt tick conversion. | ||
374 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
375 | */ | ||
376 | printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); | ||
377 | adev = &per_cpu(cpu_apbt_dev, cpu); | ||
378 | aevt = &adev->evt; | ||
379 | |||
380 | memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); | ||
381 | aevt->cpumask = cpumask_of(cpu); | ||
382 | aevt->name = adev->name; | ||
383 | aevt->mode = CLOCK_EVT_MODE_UNUSED; | ||
384 | |||
385 | printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", | ||
386 | cpu, aevt->name, *(u32 *)aevt->cpumask); | ||
387 | |||
388 | apbt_setup_irq(adev); | ||
389 | |||
390 | clockevents_register_device(aevt); | ||
391 | |||
392 | apbt_enable_int(cpu); | ||
393 | |||
394 | return; | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * this notify handler process CPU hotplug events. in case of S0i3, nonboot | ||
399 | * cpus are disabled/enabled frequently, for performance reasons, we keep the | ||
400 | * per cpu timer irq registered so that we do need to do free_irq/request_irq. | ||
401 | * | ||
402 | * TODO: it might be more reliable to directly disable percpu clockevent device | ||
403 | * without the notifier chain. currently, cpu 0 may get interrupts from other | ||
404 | * cpu timers during the offline process due to the ordering of notification. | ||
405 | * the extra interrupt is harmless. | ||
406 | */ | ||
407 | static int apbt_cpuhp_notify(struct notifier_block *n, | ||
408 | unsigned long action, void *hcpu) | ||
409 | { | ||
410 | unsigned long cpu = (unsigned long)hcpu; | ||
411 | struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu); | ||
412 | |||
413 | switch (action & 0xf) { | ||
414 | case CPU_DEAD: | ||
415 | apbt_disable_int(cpu); | ||
416 | if (system_state == SYSTEM_RUNNING) | ||
417 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | ||
418 | else if (adev) { | ||
419 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | ||
420 | free_irq(adev->irq, adev); | ||
421 | } | ||
422 | break; | ||
423 | default: | ||
424 | pr_debug(KERN_INFO "APBT notified %lu, no action\n", action); | ||
425 | } | ||
426 | return NOTIFY_OK; | ||
427 | } | ||
428 | |||
429 | static __init int apbt_late_init(void) | ||
430 | { | ||
431 | if (disable_apbt_percpu) | ||
432 | return 0; | ||
433 | /* This notifier should be called after workqueue is ready */ | ||
434 | hotcpu_notifier(apbt_cpuhp_notify, -20); | ||
435 | return 0; | ||
436 | } | ||
437 | fs_initcall(apbt_late_init); | ||
438 | #else | ||
439 | |||
440 | void apbt_setup_secondary_clock(void) {} | ||
441 | |||
442 | #endif /* CONFIG_SMP */ | ||
443 | |||
444 | static void apbt_set_mode(enum clock_event_mode mode, | ||
445 | struct clock_event_device *evt) | ||
446 | { | ||
447 | unsigned long ctrl; | ||
448 | uint64_t delta; | ||
449 | int timer_num; | ||
450 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
451 | |||
452 | timer_num = adev->num; | ||
453 | pr_debug("%s CPU %d timer %d mode=%d\n", | ||
454 | __func__, first_cpu(*evt->cpumask), timer_num, mode); | ||
455 | |||
456 | switch (mode) { | ||
457 | case CLOCK_EVT_MODE_PERIODIC: | ||
458 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; | ||
459 | delta >>= apbt_clockevent.shift; | ||
460 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
461 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
462 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
463 | /* | ||
464 | * DW APB p. 46, have to disable timer before load counter, | ||
465 | * may cause sync problem. | ||
466 | */ | ||
467 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
468 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
469 | udelay(1); | ||
470 | pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); | ||
471 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
472 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
473 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
474 | break; | ||
475 | /* APB timer does not have one-shot mode, use free running mode */ | ||
476 | case CLOCK_EVT_MODE_ONESHOT: | ||
477 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
478 | /* | ||
479 | * set free running mode, this mode will let timer reload max | ||
480 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
481 | * the next event, therefore emulate the one-shot mode. | ||
482 | */ | ||
483 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
484 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
485 | |||
486 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
487 | /* write again to set free running mode */ | ||
488 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
489 | |||
490 | /* | ||
491 | * DW APB p. 46, load counter with all 1s before starting free | ||
492 | * running mode. | ||
493 | */ | ||
494 | apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); | ||
495 | ctrl &= ~APBTMR_CONTROL_INT; | ||
496 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
497 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
498 | break; | ||
499 | |||
500 | case CLOCK_EVT_MODE_UNUSED: | ||
501 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
502 | apbt_disable_int(timer_num); | ||
503 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
504 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
505 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
506 | break; | ||
507 | |||
508 | case CLOCK_EVT_MODE_RESUME: | ||
509 | apbt_enable_int(timer_num); | ||
510 | break; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | static int apbt_next_event(unsigned long delta, | ||
515 | struct clock_event_device *evt) | ||
516 | { | ||
517 | unsigned long ctrl; | ||
518 | int timer_num; | ||
519 | |||
520 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
521 | |||
522 | timer_num = adev->num; | ||
523 | /* Disable timer */ | ||
524 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
525 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
526 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
527 | /* write new count */ | ||
528 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
529 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
530 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * APB timer clock is not in sync with pclk on Langwell, which translates to | ||
536 | * unreliable read value caused by sampling error. the error does not add up | ||
537 | * overtime and only happens when sampling a 0 as a 1 by mistake. so the time | ||
538 | * would go backwards. the following code is trying to prevent time traveling | ||
539 | * backwards. little bit paranoid. | ||
540 | */ | ||
541 | static cycle_t apbt_read_clocksource(struct clocksource *cs) | ||
542 | { | ||
543 | unsigned long t0, t1, t2; | ||
544 | static unsigned long last_read; | ||
545 | |||
546 | bad_count: | ||
547 | t1 = apbt_readl(phy_cs_timer_id, | ||
548 | APBTMR_N_CURRENT_VALUE); | ||
549 | t2 = apbt_readl(phy_cs_timer_id, | ||
550 | APBTMR_N_CURRENT_VALUE); | ||
551 | if (unlikely(t1 < t2)) { | ||
552 | pr_debug("APBT: read current count error %lx:%lx:%lx\n", | ||
553 | t1, t2, t2 - t1); | ||
554 | goto bad_count; | ||
555 | } | ||
556 | /* | ||
557 | * check against cached last read, makes sure time does not go back. | ||
558 | * it could be a normal rollover but we will do tripple check anyway | ||
559 | */ | ||
560 | if (unlikely(t2 > last_read)) { | ||
561 | /* check if we have a normal rollover */ | ||
562 | unsigned long raw_intr_status = | ||
563 | apbt_readl_reg(APBTMRS_RAW_INT_STATUS); | ||
564 | /* | ||
565 | * cs timer interrupt is masked but raw intr bit is set if | ||
566 | * rollover occurs. then we read EOI reg to clear it. | ||
567 | */ | ||
568 | if (raw_intr_status & (1 << phy_cs_timer_id)) { | ||
569 | apbt_readl(phy_cs_timer_id, APBTMR_N_EOI); | ||
570 | goto out; | ||
571 | } | ||
572 | pr_debug("APB CS going back %lx:%lx:%lx ", | ||
573 | t2, last_read, t2 - last_read); | ||
574 | bad_count_x3: | ||
575 | pr_debug(KERN_INFO "tripple check enforced\n"); | ||
576 | t0 = apbt_readl(phy_cs_timer_id, | ||
577 | APBTMR_N_CURRENT_VALUE); | ||
578 | udelay(1); | ||
579 | t1 = apbt_readl(phy_cs_timer_id, | ||
580 | APBTMR_N_CURRENT_VALUE); | ||
581 | udelay(1); | ||
582 | t2 = apbt_readl(phy_cs_timer_id, | ||
583 | APBTMR_N_CURRENT_VALUE); | ||
584 | if ((t2 > t1) || (t1 > t0)) { | ||
585 | printk(KERN_ERR "Error: APB CS tripple check failed\n"); | ||
586 | goto bad_count_x3; | ||
587 | } | ||
588 | } | ||
589 | out: | ||
590 | last_read = t2; | ||
591 | return (cycle_t)~t2; | ||
592 | } | ||
593 | |||
594 | static int apbt_clocksource_register(void) | ||
595 | { | ||
596 | u64 start, now; | ||
597 | cycle_t t1; | ||
598 | |||
599 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ | ||
600 | apbt_start_counter(phy_cs_timer_id); | ||
601 | |||
602 | /* Verify whether apbt counter works */ | ||
603 | t1 = apbt_read_clocksource(&clocksource_apbt); | ||
604 | rdtscll(start); | ||
605 | |||
606 | /* | ||
607 | * We don't know the TSC frequency yet, but waiting for | ||
608 | * 200000 TSC cycles is safe: | ||
609 | * 4 GHz == 50us | ||
610 | * 1 GHz == 200us | ||
611 | */ | ||
612 | do { | ||
613 | rep_nop(); | ||
614 | rdtscll(now); | ||
615 | } while ((now - start) < 200000UL); | ||
616 | |||
617 | /* APBT is the only always on clocksource, it has to work! */ | ||
618 | if (t1 == apbt_read_clocksource(&clocksource_apbt)) | ||
619 | panic("APBT counter not counting. APBT disabled\n"); | ||
620 | |||
621 | /* | ||
622 | * initialize and register APBT clocksource | ||
623 | * convert that to ns/clock cycle | ||
624 | * mult = (ns/c) * 2^APBT_SHIFT | ||
625 | */ | ||
626 | clocksource_apbt.mult = div_sc(MSEC_PER_SEC, | ||
627 | (unsigned long) apbt_freq, APBT_SHIFT); | ||
628 | clocksource_register(&clocksource_apbt); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * Early setup the APBT timer, only use timer 0 for booting then switch to | ||
635 | * per CPU timer if possible. | ||
636 | * returns 1 if per cpu apbt is setup | ||
637 | * returns 0 if no per cpu apbt is chosen | ||
638 | * panic if set up failed, this is the only platform timer on Moorestown. | ||
639 | */ | ||
640 | void __init apbt_time_init(void) | ||
641 | { | ||
642 | #ifdef CONFIG_SMP | ||
643 | int i; | ||
644 | struct sfi_timer_table_entry *p_mtmr; | ||
645 | unsigned int percpu_timer; | ||
646 | struct apbt_dev *adev; | ||
647 | #endif | ||
648 | |||
649 | if (apb_timer_block_enabled) | ||
650 | return; | ||
651 | apbt_set_mapping(); | ||
652 | if (apbt_virt_address) { | ||
653 | pr_debug("Found APBT version 0x%lx\n",\ | ||
654 | apbt_readl_reg(APBTMRS_COMP_VERSION)); | ||
655 | } else | ||
656 | goto out_noapbt; | ||
657 | /* | ||
658 | * Read the frequency and check for a sane value, for ESL model | ||
659 | * we extend the possible clock range to allow time scaling. | ||
660 | */ | ||
661 | |||
662 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { | ||
663 | pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); | ||
664 | goto out_noapbt; | ||
665 | } | ||
666 | if (apbt_clocksource_register()) { | ||
667 | pr_debug("APBT has failed to register clocksource\n"); | ||
668 | goto out_noapbt; | ||
669 | } | ||
670 | if (!apbt_clockevent_register()) | ||
671 | apb_timer_block_enabled = 1; | ||
672 | else { | ||
673 | pr_debug("APBT has failed to register clockevent\n"); | ||
674 | goto out_noapbt; | ||
675 | } | ||
676 | #ifdef CONFIG_SMP | ||
677 | /* kernel cmdline disable apb timer, so we will use lapic timers */ | ||
678 | if (disable_apbt_percpu) { | ||
679 | printk(KERN_INFO "apbt: disabled per cpu timer\n"); | ||
680 | return; | ||
681 | } | ||
682 | pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus()); | ||
683 | if (num_possible_cpus() <= sfi_mtimer_num) { | ||
684 | percpu_timer = 1; | ||
685 | apbt_num_timers_used = num_possible_cpus(); | ||
686 | } else { | ||
687 | percpu_timer = 0; | ||
688 | apbt_num_timers_used = 1; | ||
689 | adev = &per_cpu(cpu_apbt_dev, 0); | ||
690 | adev->flags &= ~APBT_DEV_USED; | ||
691 | } | ||
692 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); | ||
693 | |||
694 | /* here we set up per CPU timer data structure */ | ||
695 | apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, | ||
696 | GFP_KERNEL); | ||
697 | if (!apbt_devs) { | ||
698 | printk(KERN_ERR "Failed to allocate APB timer devices\n"); | ||
699 | return; | ||
700 | } | ||
701 | for (i = 0; i < apbt_num_timers_used; i++) { | ||
702 | adev = &per_cpu(cpu_apbt_dev, i); | ||
703 | adev->num = i; | ||
704 | adev->cpu = i; | ||
705 | p_mtmr = sfi_get_mtmr(i); | ||
706 | if (p_mtmr) { | ||
707 | adev->tick = p_mtmr->freq_hz; | ||
708 | adev->irq = p_mtmr->irq; | ||
709 | } else | ||
710 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); | ||
711 | adev->count = 0; | ||
712 | sprintf(adev->name, "apbt%d", i); | ||
713 | } | ||
714 | #endif | ||
715 | |||
716 | return; | ||
717 | |||
718 | out_noapbt: | ||
719 | apbt_clear_mapping(); | ||
720 | apb_timer_block_enabled = 0; | ||
721 | panic("failed to enable APB timer\n"); | ||
722 | } | ||
723 | |||
724 | static inline void apbt_disable(int n) | ||
725 | { | ||
726 | if (is_apbt_capable()) { | ||
727 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
728 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
729 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | /* called before apb_timer_enable, use early map */ | ||
734 | unsigned long apbt_quick_calibrate() | ||
735 | { | ||
736 | int i, scale; | ||
737 | u64 old, new; | ||
738 | cycle_t t1, t2; | ||
739 | unsigned long khz = 0; | ||
740 | u32 loop, shift; | ||
741 | |||
742 | apbt_set_mapping(); | ||
743 | apbt_start_counter(phy_cs_timer_id); | ||
744 | |||
745 | /* check if the timer can count down, otherwise return */ | ||
746 | old = apbt_read_clocksource(&clocksource_apbt); | ||
747 | i = 10000; | ||
748 | while (--i) { | ||
749 | if (old != apbt_read_clocksource(&clocksource_apbt)) | ||
750 | break; | ||
751 | } | ||
752 | if (!i) | ||
753 | goto failed; | ||
754 | |||
755 | /* count 16 ms */ | ||
756 | loop = (apbt_freq * 1000) << 4; | ||
757 | |||
758 | /* restart the timer to ensure it won't get to 0 in the calibration */ | ||
759 | apbt_start_counter(phy_cs_timer_id); | ||
760 | |||
761 | old = apbt_read_clocksource(&clocksource_apbt); | ||
762 | old += loop; | ||
763 | |||
764 | t1 = __native_read_tsc(); | ||
765 | |||
766 | do { | ||
767 | new = apbt_read_clocksource(&clocksource_apbt); | ||
768 | } while (new < old); | ||
769 | |||
770 | t2 = __native_read_tsc(); | ||
771 | |||
772 | shift = 5; | ||
773 | if (unlikely(loop >> shift == 0)) { | ||
774 | printk(KERN_INFO | ||
775 | "APBT TSC calibration failed, not enough resolution\n"); | ||
776 | return 0; | ||
777 | } | ||
778 | scale = (int)div_u64((t2 - t1), loop >> shift); | ||
779 | khz = (scale * apbt_freq * 1000) >> shift; | ||
780 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); | ||
781 | return khz; | ||
782 | failed: | ||
783 | return 0; | ||
784 | } | ||
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 6e29b2a77aa8..00187f1fcfb7 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -1390,7 +1390,7 @@ void __init enable_IR_x2apic(void) | |||
1390 | } | 1390 | } |
1391 | 1391 | ||
1392 | local_irq_save(flags); | 1392 | local_irq_save(flags); |
1393 | mask_8259A(); | 1393 | legacy_pic->mask_all(); |
1394 | mask_IO_APIC_setup(ioapic_entries); | 1394 | mask_IO_APIC_setup(ioapic_entries); |
1395 | 1395 | ||
1396 | if (dmar_table_init_ret) | 1396 | if (dmar_table_init_ret) |
@@ -1422,7 +1422,7 @@ void __init enable_IR_x2apic(void) | |||
1422 | nox2apic: | 1422 | nox2apic: |
1423 | if (!ret) /* IR enabling failed */ | 1423 | if (!ret) /* IR enabling failed */ |
1424 | restore_IO_APIC_setup(ioapic_entries); | 1424 | restore_IO_APIC_setup(ioapic_entries); |
1425 | unmask_8259A(); | 1425 | legacy_pic->restore_mask(); |
1426 | local_irq_restore(flags); | 1426 | local_irq_restore(flags); |
1427 | 1427 | ||
1428 | out: | 1428 | out: |
@@ -2018,7 +2018,7 @@ static int lapic_resume(struct sys_device *dev) | |||
2018 | } | 2018 | } |
2019 | 2019 | ||
2020 | mask_IO_APIC_setup(ioapic_entries); | 2020 | mask_IO_APIC_setup(ioapic_entries); |
2021 | mask_8259A(); | 2021 | legacy_pic->mask_all(); |
2022 | } | 2022 | } |
2023 | 2023 | ||
2024 | if (x2apic_mode) | 2024 | if (x2apic_mode) |
@@ -2062,7 +2062,7 @@ static int lapic_resume(struct sys_device *dev) | |||
2062 | 2062 | ||
2063 | if (intr_remapping_enabled) { | 2063 | if (intr_remapping_enabled) { |
2064 | reenable_intr_remapping(x2apic_mode); | 2064 | reenable_intr_remapping(x2apic_mode); |
2065 | unmask_8259A(); | 2065 | legacy_pic->restore_mask(); |
2066 | restore_IO_APIC_setup(ioapic_entries); | 2066 | restore_IO_APIC_setup(ioapic_entries); |
2067 | free_ioapic_entries(ioapic_entries); | 2067 | free_ioapic_entries(ioapic_entries); |
2068 | } | 2068 | } |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 14862f11cc4a..e4e0ddcb1546 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -143,12 +143,6 @@ static struct irq_cfg irq_cfgx[NR_IRQS_LEGACY]; | |||
143 | static struct irq_cfg irq_cfgx[NR_IRQS]; | 143 | static struct irq_cfg irq_cfgx[NR_IRQS]; |
144 | #endif | 144 | #endif |
145 | 145 | ||
146 | void __init io_apic_disable_legacy(void) | ||
147 | { | ||
148 | nr_legacy_irqs = 0; | ||
149 | nr_irqs_gsi = 0; | ||
150 | } | ||
151 | |||
152 | int __init arch_early_irq_init(void) | 146 | int __init arch_early_irq_init(void) |
153 | { | 147 | { |
154 | struct irq_cfg *cfg; | 148 | struct irq_cfg *cfg; |
@@ -157,6 +151,11 @@ int __init arch_early_irq_init(void) | |||
157 | int node; | 151 | int node; |
158 | int i; | 152 | int i; |
159 | 153 | ||
154 | if (!legacy_pic->nr_legacy_irqs) { | ||
155 | nr_irqs_gsi = 0; | ||
156 | io_apic_irqs = ~0UL; | ||
157 | } | ||
158 | |||
160 | cfg = irq_cfgx; | 159 | cfg = irq_cfgx; |
161 | count = ARRAY_SIZE(irq_cfgx); | 160 | count = ARRAY_SIZE(irq_cfgx); |
162 | node= cpu_to_node(boot_cpu_id); | 161 | node= cpu_to_node(boot_cpu_id); |
@@ -170,7 +169,7 @@ int __init arch_early_irq_init(void) | |||
170 | * For legacy IRQ's, start with assigning irq0 to irq15 to | 169 | * For legacy IRQ's, start with assigning irq0 to irq15 to |
171 | * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0. | 170 | * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0. |
172 | */ | 171 | */ |
173 | if (i < nr_legacy_irqs) { | 172 | if (i < legacy_pic->nr_legacy_irqs) { |
174 | cfg[i].vector = IRQ0_VECTOR + i; | 173 | cfg[i].vector = IRQ0_VECTOR + i; |
175 | cpumask_set_cpu(0, cfg[i].domain); | 174 | cpumask_set_cpu(0, cfg[i].domain); |
176 | } | 175 | } |
@@ -852,7 +851,7 @@ static int __init find_isa_irq_apic(int irq, int type) | |||
852 | */ | 851 | */ |
853 | static int EISA_ELCR(unsigned int irq) | 852 | static int EISA_ELCR(unsigned int irq) |
854 | { | 853 | { |
855 | if (irq < nr_legacy_irqs) { | 854 | if (irq < legacy_pic->nr_legacy_irqs) { |
856 | unsigned int port = 0x4d0 + (irq >> 3); | 855 | unsigned int port = 0x4d0 + (irq >> 3); |
857 | return (inb(port) >> (irq & 7)) & 1; | 856 | return (inb(port) >> (irq & 7)) & 1; |
858 | } | 857 | } |
@@ -1439,7 +1438,7 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq | |||
1439 | * controllers like 8259. Now that IO-APIC can handle this irq, update | 1438 | * controllers like 8259. Now that IO-APIC can handle this irq, update |
1440 | * the cfg->domain. | 1439 | * the cfg->domain. |
1441 | */ | 1440 | */ |
1442 | if (irq < nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain)) | 1441 | if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain)) |
1443 | apic->vector_allocation_domain(0, cfg->domain); | 1442 | apic->vector_allocation_domain(0, cfg->domain); |
1444 | 1443 | ||
1445 | if (assign_irq_vector(irq, cfg, apic->target_cpus())) | 1444 | if (assign_irq_vector(irq, cfg, apic->target_cpus())) |
@@ -1463,8 +1462,8 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq | |||
1463 | } | 1462 | } |
1464 | 1463 | ||
1465 | ioapic_register_intr(irq, desc, trigger); | 1464 | ioapic_register_intr(irq, desc, trigger); |
1466 | if (irq < nr_legacy_irqs) | 1465 | if (irq < legacy_pic->nr_legacy_irqs) |
1467 | disable_8259A_irq(irq); | 1466 | legacy_pic->chip->mask(irq); |
1468 | 1467 | ||
1469 | ioapic_write_entry(apic_id, pin, entry); | 1468 | ioapic_write_entry(apic_id, pin, entry); |
1470 | } | 1469 | } |
@@ -1873,7 +1872,7 @@ __apicdebuginit(void) print_PIC(void) | |||
1873 | unsigned int v; | 1872 | unsigned int v; |
1874 | unsigned long flags; | 1873 | unsigned long flags; |
1875 | 1874 | ||
1876 | if (!nr_legacy_irqs) | 1875 | if (!legacy_pic->nr_legacy_irqs) |
1877 | return; | 1876 | return; |
1878 | 1877 | ||
1879 | printk(KERN_DEBUG "\nprinting PIC contents\n"); | 1878 | printk(KERN_DEBUG "\nprinting PIC contents\n"); |
@@ -1957,7 +1956,7 @@ void __init enable_IO_APIC(void) | |||
1957 | nr_ioapic_registers[apic] = reg_01.bits.entries+1; | 1956 | nr_ioapic_registers[apic] = reg_01.bits.entries+1; |
1958 | } | 1957 | } |
1959 | 1958 | ||
1960 | if (!nr_legacy_irqs) | 1959 | if (!legacy_pic->nr_legacy_irqs) |
1961 | return; | 1960 | return; |
1962 | 1961 | ||
1963 | for(apic = 0; apic < nr_ioapics; apic++) { | 1962 | for(apic = 0; apic < nr_ioapics; apic++) { |
@@ -2014,7 +2013,7 @@ void disable_IO_APIC(void) | |||
2014 | */ | 2013 | */ |
2015 | clear_IO_APIC(); | 2014 | clear_IO_APIC(); |
2016 | 2015 | ||
2017 | if (!nr_legacy_irqs) | 2016 | if (!legacy_pic->nr_legacy_irqs) |
2018 | return; | 2017 | return; |
2019 | 2018 | ||
2020 | /* | 2019 | /* |
@@ -2247,9 +2246,9 @@ static unsigned int startup_ioapic_irq(unsigned int irq) | |||
2247 | struct irq_cfg *cfg; | 2246 | struct irq_cfg *cfg; |
2248 | 2247 | ||
2249 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 2248 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
2250 | if (irq < nr_legacy_irqs) { | 2249 | if (irq < legacy_pic->nr_legacy_irqs) { |
2251 | disable_8259A_irq(irq); | 2250 | legacy_pic->chip->mask(irq); |
2252 | if (i8259A_irq_pending(irq)) | 2251 | if (legacy_pic->irq_pending(irq)) |
2253 | was_pending = 1; | 2252 | was_pending = 1; |
2254 | } | 2253 | } |
2255 | cfg = irq_cfg(irq); | 2254 | cfg = irq_cfg(irq); |
@@ -2782,8 +2781,8 @@ static inline void init_IO_APIC_traps(void) | |||
2782 | * so default to an old-fashioned 8259 | 2781 | * so default to an old-fashioned 8259 |
2783 | * interrupt if we can.. | 2782 | * interrupt if we can.. |
2784 | */ | 2783 | */ |
2785 | if (irq < nr_legacy_irqs) | 2784 | if (irq < legacy_pic->nr_legacy_irqs) |
2786 | make_8259A_irq(irq); | 2785 | legacy_pic->make_irq(irq); |
2787 | else | 2786 | else |
2788 | /* Strange. Oh, well.. */ | 2787 | /* Strange. Oh, well.. */ |
2789 | desc->chip = &no_irq_chip; | 2788 | desc->chip = &no_irq_chip; |
@@ -2940,7 +2939,7 @@ static inline void __init check_timer(void) | |||
2940 | /* | 2939 | /* |
2941 | * get/set the timer IRQ vector: | 2940 | * get/set the timer IRQ vector: |
2942 | */ | 2941 | */ |
2943 | disable_8259A_irq(0); | 2942 | legacy_pic->chip->mask(0); |
2944 | assign_irq_vector(0, cfg, apic->target_cpus()); | 2943 | assign_irq_vector(0, cfg, apic->target_cpus()); |
2945 | 2944 | ||
2946 | /* | 2945 | /* |
@@ -2953,7 +2952,7 @@ static inline void __init check_timer(void) | |||
2953 | * automatically. | 2952 | * automatically. |
2954 | */ | 2953 | */ |
2955 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); | 2954 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); |
2956 | init_8259A(1); | 2955 | legacy_pic->init(1); |
2957 | #ifdef CONFIG_X86_32 | 2956 | #ifdef CONFIG_X86_32 |
2958 | { | 2957 | { |
2959 | unsigned int ver; | 2958 | unsigned int ver; |
@@ -3012,7 +3011,7 @@ static inline void __init check_timer(void) | |||
3012 | if (timer_irq_works()) { | 3011 | if (timer_irq_works()) { |
3013 | if (nmi_watchdog == NMI_IO_APIC) { | 3012 | if (nmi_watchdog == NMI_IO_APIC) { |
3014 | setup_nmi(); | 3013 | setup_nmi(); |
3015 | enable_8259A_irq(0); | 3014 | legacy_pic->chip->unmask(0); |
3016 | } | 3015 | } |
3017 | if (disable_timer_pin_1 > 0) | 3016 | if (disable_timer_pin_1 > 0) |
3018 | clear_IO_APIC_pin(0, pin1); | 3017 | clear_IO_APIC_pin(0, pin1); |
@@ -3035,14 +3034,14 @@ static inline void __init check_timer(void) | |||
3035 | */ | 3034 | */ |
3036 | replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); | 3035 | replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); |
3037 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); | 3036 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); |
3038 | enable_8259A_irq(0); | 3037 | legacy_pic->chip->unmask(0); |
3039 | if (timer_irq_works()) { | 3038 | if (timer_irq_works()) { |
3040 | apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); | 3039 | apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); |
3041 | timer_through_8259 = 1; | 3040 | timer_through_8259 = 1; |
3042 | if (nmi_watchdog == NMI_IO_APIC) { | 3041 | if (nmi_watchdog == NMI_IO_APIC) { |
3043 | disable_8259A_irq(0); | 3042 | legacy_pic->chip->mask(0); |
3044 | setup_nmi(); | 3043 | setup_nmi(); |
3045 | enable_8259A_irq(0); | 3044 | legacy_pic->chip->unmask(0); |
3046 | } | 3045 | } |
3047 | goto out; | 3046 | goto out; |
3048 | } | 3047 | } |
@@ -3050,7 +3049,7 @@ static inline void __init check_timer(void) | |||
3050 | * Cleanup, just in case ... | 3049 | * Cleanup, just in case ... |
3051 | */ | 3050 | */ |
3052 | local_irq_disable(); | 3051 | local_irq_disable(); |
3053 | disable_8259A_irq(0); | 3052 | legacy_pic->chip->mask(0); |
3054 | clear_IO_APIC_pin(apic2, pin2); | 3053 | clear_IO_APIC_pin(apic2, pin2); |
3055 | apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n"); | 3054 | apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n"); |
3056 | } | 3055 | } |
@@ -3069,22 +3068,22 @@ static inline void __init check_timer(void) | |||
3069 | 3068 | ||
3070 | lapic_register_intr(0, desc); | 3069 | lapic_register_intr(0, desc); |
3071 | apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ | 3070 | apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ |
3072 | enable_8259A_irq(0); | 3071 | legacy_pic->chip->unmask(0); |
3073 | 3072 | ||
3074 | if (timer_irq_works()) { | 3073 | if (timer_irq_works()) { |
3075 | apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); | 3074 | apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); |
3076 | goto out; | 3075 | goto out; |
3077 | } | 3076 | } |
3078 | local_irq_disable(); | 3077 | local_irq_disable(); |
3079 | disable_8259A_irq(0); | 3078 | legacy_pic->chip->mask(0); |
3080 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); | 3079 | apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); |
3081 | apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n"); | 3080 | apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n"); |
3082 | 3081 | ||
3083 | apic_printk(APIC_QUIET, KERN_INFO | 3082 | apic_printk(APIC_QUIET, KERN_INFO |
3084 | "...trying to set up timer as ExtINT IRQ...\n"); | 3083 | "...trying to set up timer as ExtINT IRQ...\n"); |
3085 | 3084 | ||
3086 | init_8259A(0); | 3085 | legacy_pic->init(0); |
3087 | make_8259A_irq(0); | 3086 | legacy_pic->make_irq(0); |
3088 | apic_write(APIC_LVT0, APIC_DM_EXTINT); | 3087 | apic_write(APIC_LVT0, APIC_DM_EXTINT); |
3089 | 3088 | ||
3090 | unlock_ExtINT_logic(); | 3089 | unlock_ExtINT_logic(); |
@@ -3126,7 +3125,7 @@ void __init setup_IO_APIC(void) | |||
3126 | /* | 3125 | /* |
3127 | * calling enable_IO_APIC() is moved to setup_local_APIC for BP | 3126 | * calling enable_IO_APIC() is moved to setup_local_APIC for BP |
3128 | */ | 3127 | */ |
3129 | io_apic_irqs = nr_legacy_irqs ? ~PIC_IRQS : ~0UL; | 3128 | io_apic_irqs = legacy_pic->nr_legacy_irqs ? ~PIC_IRQS : ~0UL; |
3130 | 3129 | ||
3131 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); | 3130 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); |
3132 | /* | 3131 | /* |
@@ -3137,7 +3136,7 @@ void __init setup_IO_APIC(void) | |||
3137 | sync_Arb_IDs(); | 3136 | sync_Arb_IDs(); |
3138 | setup_IO_APIC_irqs(); | 3137 | setup_IO_APIC_irqs(); |
3139 | init_IO_APIC_traps(); | 3138 | init_IO_APIC_traps(); |
3140 | if (nr_legacy_irqs) | 3139 | if (legacy_pic->nr_legacy_irqs) |
3141 | check_timer(); | 3140 | check_timer(); |
3142 | } | 3141 | } |
3143 | 3142 | ||
@@ -3928,7 +3927,7 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq, | |||
3928 | /* | 3927 | /* |
3929 | * IRQs < 16 are already in the irq_2_pin[] map | 3928 | * IRQs < 16 are already in the irq_2_pin[] map |
3930 | */ | 3929 | */ |
3931 | if (irq >= nr_legacy_irqs) { | 3930 | if (irq >= legacy_pic->nr_legacy_irqs) { |
3932 | cfg = desc->chip_data; | 3931 | cfg = desc->chip_data; |
3933 | if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) { | 3932 | if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) { |
3934 | printk(KERN_INFO "can not add pin %d for irq %d\n", | 3933 | printk(KERN_INFO "can not add pin %d for irq %d\n", |
@@ -4302,3 +4301,24 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | |||
4302 | 4301 | ||
4303 | nr_ioapics++; | 4302 | nr_ioapics++; |
4304 | } | 4303 | } |
4304 | |||
4305 | /* Enable IOAPIC early just for system timer */ | ||
4306 | void __init pre_init_apic_IRQ0(void) | ||
4307 | { | ||
4308 | struct irq_cfg *cfg; | ||
4309 | struct irq_desc *desc; | ||
4310 | |||
4311 | printk(KERN_INFO "Early APIC setup for system timer0\n"); | ||
4312 | #ifndef CONFIG_SMP | ||
4313 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); | ||
4314 | #endif | ||
4315 | desc = irq_to_desc_alloc_node(0, 0); | ||
4316 | |||
4317 | setup_local_APIC(); | ||
4318 | |||
4319 | cfg = irq_cfg(0); | ||
4320 | add_pin_to_irq_node(cfg, 0, 0, 0); | ||
4321 | set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge"); | ||
4322 | |||
4323 | setup_IO_APIC_irq(0, 0, 0, desc, 0, 0); | ||
4324 | } | ||
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index bd7c96b5e8d8..8aa65adbd25d 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c | |||
@@ -177,7 +177,7 @@ int __init check_nmi_watchdog(void) | |||
177 | error: | 177 | error: |
178 | if (nmi_watchdog == NMI_IO_APIC) { | 178 | if (nmi_watchdog == NMI_IO_APIC) { |
179 | if (!timer_through_8259) | 179 | if (!timer_through_8259) |
180 | disable_8259A_irq(0); | 180 | legacy_pic->chip->mask(0); |
181 | on_each_cpu(__acpi_nmi_disable, NULL, 1); | 181 | on_each_cpu(__acpi_nmi_disable, NULL, 1); |
182 | } | 182 | } |
183 | 183 | ||
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 47dd856708e5..3e28401f161c 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c | |||
@@ -277,6 +277,7 @@ static __init void early_check_numaq(void) | |||
277 | x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus; | 277 | x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus; |
278 | x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info; | 278 | x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info; |
279 | x86_init.timers.tsc_pre_init = numaq_tsc_init; | 279 | x86_init.timers.tsc_pre_init = numaq_tsc_init; |
280 | x86_init.pci.init = pci_numaq_init; | ||
280 | } | 281 | } |
281 | } | 282 | } |
282 | 283 | ||
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index 8c93a84bb627..fb725ee15f55 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c | |||
@@ -34,6 +34,12 @@ | |||
34 | static int i8259A_auto_eoi; | 34 | static int i8259A_auto_eoi; |
35 | DEFINE_RAW_SPINLOCK(i8259A_lock); | 35 | DEFINE_RAW_SPINLOCK(i8259A_lock); |
36 | static void mask_and_ack_8259A(unsigned int); | 36 | static void mask_and_ack_8259A(unsigned int); |
37 | static void mask_8259A(void); | ||
38 | static void unmask_8259A(void); | ||
39 | static void disable_8259A_irq(unsigned int irq); | ||
40 | static void enable_8259A_irq(unsigned int irq); | ||
41 | static void init_8259A(int auto_eoi); | ||
42 | static int i8259A_irq_pending(unsigned int irq); | ||
37 | 43 | ||
38 | struct irq_chip i8259A_chip = { | 44 | struct irq_chip i8259A_chip = { |
39 | .name = "XT-PIC", | 45 | .name = "XT-PIC", |
@@ -63,7 +69,7 @@ unsigned int cached_irq_mask = 0xffff; | |||
63 | */ | 69 | */ |
64 | unsigned long io_apic_irqs; | 70 | unsigned long io_apic_irqs; |
65 | 71 | ||
66 | void disable_8259A_irq(unsigned int irq) | 72 | static void disable_8259A_irq(unsigned int irq) |
67 | { | 73 | { |
68 | unsigned int mask = 1 << irq; | 74 | unsigned int mask = 1 << irq; |
69 | unsigned long flags; | 75 | unsigned long flags; |
@@ -77,7 +83,7 @@ void disable_8259A_irq(unsigned int irq) | |||
77 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 83 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
78 | } | 84 | } |
79 | 85 | ||
80 | void enable_8259A_irq(unsigned int irq) | 86 | static void enable_8259A_irq(unsigned int irq) |
81 | { | 87 | { |
82 | unsigned int mask = ~(1 << irq); | 88 | unsigned int mask = ~(1 << irq); |
83 | unsigned long flags; | 89 | unsigned long flags; |
@@ -91,7 +97,7 @@ void enable_8259A_irq(unsigned int irq) | |||
91 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 97 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
92 | } | 98 | } |
93 | 99 | ||
94 | int i8259A_irq_pending(unsigned int irq) | 100 | static int i8259A_irq_pending(unsigned int irq) |
95 | { | 101 | { |
96 | unsigned int mask = 1<<irq; | 102 | unsigned int mask = 1<<irq; |
97 | unsigned long flags; | 103 | unsigned long flags; |
@@ -107,7 +113,7 @@ int i8259A_irq_pending(unsigned int irq) | |||
107 | return ret; | 113 | return ret; |
108 | } | 114 | } |
109 | 115 | ||
110 | void make_8259A_irq(unsigned int irq) | 116 | static void make_8259A_irq(unsigned int irq) |
111 | { | 117 | { |
112 | disable_irq_nosync(irq); | 118 | disable_irq_nosync(irq); |
113 | io_apic_irqs &= ~(1<<irq); | 119 | io_apic_irqs &= ~(1<<irq); |
@@ -281,7 +287,7 @@ static int __init i8259A_init_sysfs(void) | |||
281 | 287 | ||
282 | device_initcall(i8259A_init_sysfs); | 288 | device_initcall(i8259A_init_sysfs); |
283 | 289 | ||
284 | void mask_8259A(void) | 290 | static void mask_8259A(void) |
285 | { | 291 | { |
286 | unsigned long flags; | 292 | unsigned long flags; |
287 | 293 | ||
@@ -293,7 +299,7 @@ void mask_8259A(void) | |||
293 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 299 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
294 | } | 300 | } |
295 | 301 | ||
296 | void unmask_8259A(void) | 302 | static void unmask_8259A(void) |
297 | { | 303 | { |
298 | unsigned long flags; | 304 | unsigned long flags; |
299 | 305 | ||
@@ -305,7 +311,7 @@ void unmask_8259A(void) | |||
305 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 311 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
306 | } | 312 | } |
307 | 313 | ||
308 | void init_8259A(int auto_eoi) | 314 | static void init_8259A(int auto_eoi) |
309 | { | 315 | { |
310 | unsigned long flags; | 316 | unsigned long flags; |
311 | 317 | ||
@@ -358,3 +364,47 @@ void init_8259A(int auto_eoi) | |||
358 | 364 | ||
359 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 365 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
360 | } | 366 | } |
367 | |||
368 | /* | ||
369 | * make i8259 a driver so that we can select pic functions at run time. the goal | ||
370 | * is to make x86 binary compatible among pc compatible and non-pc compatible | ||
371 | * platforms, such as x86 MID. | ||
372 | */ | ||
373 | |||
374 | static void legacy_pic_noop(void) { }; | ||
375 | static void legacy_pic_uint_noop(unsigned int unused) { }; | ||
376 | static void legacy_pic_int_noop(int unused) { }; | ||
377 | |||
378 | static struct irq_chip dummy_pic_chip = { | ||
379 | .name = "dummy pic", | ||
380 | .mask = legacy_pic_uint_noop, | ||
381 | .unmask = legacy_pic_uint_noop, | ||
382 | .disable = legacy_pic_uint_noop, | ||
383 | .mask_ack = legacy_pic_uint_noop, | ||
384 | }; | ||
385 | static int legacy_pic_irq_pending_noop(unsigned int irq) | ||
386 | { | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | struct legacy_pic null_legacy_pic = { | ||
391 | .nr_legacy_irqs = 0, | ||
392 | .chip = &dummy_pic_chip, | ||
393 | .mask_all = legacy_pic_noop, | ||
394 | .restore_mask = legacy_pic_noop, | ||
395 | .init = legacy_pic_int_noop, | ||
396 | .irq_pending = legacy_pic_irq_pending_noop, | ||
397 | .make_irq = legacy_pic_uint_noop, | ||
398 | }; | ||
399 | |||
400 | struct legacy_pic default_legacy_pic = { | ||
401 | .nr_legacy_irqs = NR_IRQS_LEGACY, | ||
402 | .chip = &i8259A_chip, | ||
403 | .mask_all = mask_8259A, | ||
404 | .restore_mask = unmask_8259A, | ||
405 | .init = init_8259A, | ||
406 | .irq_pending = i8259A_irq_pending, | ||
407 | .make_irq = make_8259A_irq, | ||
408 | }; | ||
409 | |||
410 | struct legacy_pic *legacy_pic = &default_legacy_pic; | ||
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index fce55d532631..ef257fc2921b 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c | |||
@@ -99,9 +99,6 @@ int vector_used_by_percpu_irq(unsigned int vector) | |||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | /* Number of legacy interrupts */ | ||
103 | int nr_legacy_irqs __read_mostly = NR_IRQS_LEGACY; | ||
104 | |||
105 | void __init init_ISA_irqs(void) | 102 | void __init init_ISA_irqs(void) |
106 | { | 103 | { |
107 | int i; | 104 | int i; |
@@ -109,12 +106,12 @@ void __init init_ISA_irqs(void) | |||
109 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) | 106 | #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) |
110 | init_bsp_APIC(); | 107 | init_bsp_APIC(); |
111 | #endif | 108 | #endif |
112 | init_8259A(0); | 109 | legacy_pic->init(0); |
113 | 110 | ||
114 | /* | 111 | /* |
115 | * 16 old-style INTA-cycle interrupts: | 112 | * 16 old-style INTA-cycle interrupts: |
116 | */ | 113 | */ |
117 | for (i = 0; i < NR_IRQS_LEGACY; i++) { | 114 | for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) { |
118 | struct irq_desc *desc = irq_to_desc(i); | 115 | struct irq_desc *desc = irq_to_desc(i); |
119 | 116 | ||
120 | desc->status = IRQ_DISABLED; | 117 | desc->status = IRQ_DISABLED; |
@@ -138,7 +135,7 @@ void __init init_IRQ(void) | |||
138 | * then this vector space can be freed and re-used dynamically as the | 135 | * then this vector space can be freed and re-used dynamically as the |
139 | * irq's migrate etc. | 136 | * irq's migrate etc. |
140 | */ | 137 | */ |
141 | for (i = 0; i < nr_legacy_irqs; i++) | 138 | for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) |
142 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; | 139 | per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; |
143 | 140 | ||
144 | x86_init.irqs.intr_init(); | 141 | x86_init.irqs.intr_init(); |
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 3b7078abc871..0aad8670858e 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c | |||
@@ -10,8 +10,211 @@ | |||
10 | * of the License. | 10 | * of the License. |
11 | */ | 11 | */ |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sfi.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/module.h> | ||
13 | 17 | ||
14 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
19 | #include <asm/mpspec_def.h> | ||
20 | #include <asm/hw_irq.h> | ||
21 | #include <asm/apic.h> | ||
22 | #include <asm/io_apic.h> | ||
23 | #include <asm/mrst.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/i8259.h> | ||
26 | #include <asm/apb_timer.h> | ||
27 | |||
28 | static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | ||
29 | static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | ||
30 | int sfi_mtimer_num; | ||
31 | |||
32 | struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; | ||
33 | EXPORT_SYMBOL_GPL(sfi_mrtc_array); | ||
34 | int sfi_mrtc_num; | ||
35 | |||
36 | static inline void assign_to_mp_irq(struct mpc_intsrc *m, | ||
37 | struct mpc_intsrc *mp_irq) | ||
38 | { | ||
39 | memcpy(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
40 | } | ||
41 | |||
42 | static inline int mp_irq_cmp(struct mpc_intsrc *mp_irq, | ||
43 | struct mpc_intsrc *m) | ||
44 | { | ||
45 | return memcmp(mp_irq, m, sizeof(struct mpc_intsrc)); | ||
46 | } | ||
47 | |||
48 | static void save_mp_irq(struct mpc_intsrc *m) | ||
49 | { | ||
50 | int i; | ||
51 | |||
52 | for (i = 0; i < mp_irq_entries; i++) { | ||
53 | if (!mp_irq_cmp(&mp_irqs[i], m)) | ||
54 | return; | ||
55 | } | ||
56 | |||
57 | assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]); | ||
58 | if (++mp_irq_entries == MAX_IRQ_SOURCES) | ||
59 | panic("Max # of irq sources exceeded!!\n"); | ||
60 | } | ||
61 | |||
62 | /* parse all the mtimer info to a static mtimer array */ | ||
63 | static int __init sfi_parse_mtmr(struct sfi_table_header *table) | ||
64 | { | ||
65 | struct sfi_table_simple *sb; | ||
66 | struct sfi_timer_table_entry *pentry; | ||
67 | struct mpc_intsrc mp_irq; | ||
68 | int totallen; | ||
69 | |||
70 | sb = (struct sfi_table_simple *)table; | ||
71 | if (!sfi_mtimer_num) { | ||
72 | sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb, | ||
73 | struct sfi_timer_table_entry); | ||
74 | pentry = (struct sfi_timer_table_entry *) sb->pentry; | ||
75 | totallen = sfi_mtimer_num * sizeof(*pentry); | ||
76 | memcpy(sfi_mtimer_array, pentry, totallen); | ||
77 | } | ||
78 | |||
79 | printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num); | ||
80 | pentry = sfi_mtimer_array; | ||
81 | for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { | ||
82 | printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz," | ||
83 | " irq = %d\n", totallen, (u32)pentry->phys_addr, | ||
84 | pentry->freq_hz, pentry->irq); | ||
85 | if (!pentry->irq) | ||
86 | continue; | ||
87 | mp_irq.type = MP_IOAPIC; | ||
88 | mp_irq.irqtype = mp_INT; | ||
89 | /* triggering mode edge bit 2-3, active high polarity bit 0-1 */ | ||
90 | mp_irq.irqflag = 5; | ||
91 | mp_irq.srcbus = 0; | ||
92 | mp_irq.srcbusirq = pentry->irq; /* IRQ */ | ||
93 | mp_irq.dstapic = MP_APIC_ALL; | ||
94 | mp_irq.dstirq = pentry->irq; | ||
95 | save_mp_irq(&mp_irq); | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct sfi_timer_table_entry *sfi_get_mtmr(int hint) | ||
102 | { | ||
103 | int i; | ||
104 | if (hint < sfi_mtimer_num) { | ||
105 | if (!sfi_mtimer_usage[hint]) { | ||
106 | pr_debug("hint taken for timer %d irq %d\n",\ | ||
107 | hint, sfi_mtimer_array[hint].irq); | ||
108 | sfi_mtimer_usage[hint] = 1; | ||
109 | return &sfi_mtimer_array[hint]; | ||
110 | } | ||
111 | } | ||
112 | /* take the first timer available */ | ||
113 | for (i = 0; i < sfi_mtimer_num;) { | ||
114 | if (!sfi_mtimer_usage[i]) { | ||
115 | sfi_mtimer_usage[i] = 1; | ||
116 | return &sfi_mtimer_array[i]; | ||
117 | } | ||
118 | i++; | ||
119 | } | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr) | ||
124 | { | ||
125 | int i; | ||
126 | for (i = 0; i < sfi_mtimer_num;) { | ||
127 | if (mtmr->irq == sfi_mtimer_array[i].irq) { | ||
128 | sfi_mtimer_usage[i] = 0; | ||
129 | return; | ||
130 | } | ||
131 | i++; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /* parse all the mrtc info to a global mrtc array */ | ||
136 | int __init sfi_parse_mrtc(struct sfi_table_header *table) | ||
137 | { | ||
138 | struct sfi_table_simple *sb; | ||
139 | struct sfi_rtc_table_entry *pentry; | ||
140 | struct mpc_intsrc mp_irq; | ||
141 | |||
142 | int totallen; | ||
143 | |||
144 | sb = (struct sfi_table_simple *)table; | ||
145 | if (!sfi_mrtc_num) { | ||
146 | sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb, | ||
147 | struct sfi_rtc_table_entry); | ||
148 | pentry = (struct sfi_rtc_table_entry *)sb->pentry; | ||
149 | totallen = sfi_mrtc_num * sizeof(*pentry); | ||
150 | memcpy(sfi_mrtc_array, pentry, totallen); | ||
151 | } | ||
152 | |||
153 | printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num); | ||
154 | pentry = sfi_mrtc_array; | ||
155 | for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { | ||
156 | printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n", | ||
157 | totallen, (u32)pentry->phys_addr, pentry->irq); | ||
158 | mp_irq.type = MP_IOAPIC; | ||
159 | mp_irq.irqtype = mp_INT; | ||
160 | mp_irq.irqflag = 0; | ||
161 | mp_irq.srcbus = 0; | ||
162 | mp_irq.srcbusirq = pentry->irq; /* IRQ */ | ||
163 | mp_irq.dstapic = MP_APIC_ALL; | ||
164 | mp_irq.dstirq = pentry->irq; | ||
165 | save_mp_irq(&mp_irq); | ||
166 | } | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * the secondary clock in Moorestown can be APBT or LAPIC clock, default to | ||
172 | * APBT but cmdline option can also override it. | ||
173 | */ | ||
174 | static void __cpuinit mrst_setup_secondary_clock(void) | ||
175 | { | ||
176 | /* restore default lapic clock if disabled by cmdline */ | ||
177 | if (disable_apbt_percpu) | ||
178 | return setup_secondary_APIC_clock(); | ||
179 | apbt_setup_secondary_clock(); | ||
180 | } | ||
181 | |||
182 | static unsigned long __init mrst_calibrate_tsc(void) | ||
183 | { | ||
184 | unsigned long flags, fast_calibrate; | ||
185 | |||
186 | local_irq_save(flags); | ||
187 | fast_calibrate = apbt_quick_calibrate(); | ||
188 | local_irq_restore(flags); | ||
189 | |||
190 | if (fast_calibrate) | ||
191 | return fast_calibrate; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | void __init mrst_time_init(void) | ||
197 | { | ||
198 | sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | ||
199 | pre_init_apic_IRQ0(); | ||
200 | apbt_time_init(); | ||
201 | } | ||
202 | |||
203 | void __init mrst_rtc_init(void) | ||
204 | { | ||
205 | sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * if we use per cpu apb timer, the bootclock already setup. if we use lapic | ||
210 | * timer and one apbt timer for broadcast, we need to set up lapic boot clock. | ||
211 | */ | ||
212 | static void __init mrst_setup_boot_clock(void) | ||
213 | { | ||
214 | pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu); | ||
215 | if (disable_apbt_percpu) | ||
216 | setup_boot_APIC_clock(); | ||
217 | }; | ||
15 | 218 | ||
16 | /* | 219 | /* |
17 | * Moorestown specific x86_init function overrides and early setup | 220 | * Moorestown specific x86_init function overrides and early setup |
@@ -21,4 +224,17 @@ void __init x86_mrst_early_setup(void) | |||
21 | { | 224 | { |
22 | x86_init.resources.probe_roms = x86_init_noop; | 225 | x86_init.resources.probe_roms = x86_init_noop; |
23 | x86_init.resources.reserve_resources = x86_init_noop; | 226 | x86_init.resources.reserve_resources = x86_init_noop; |
227 | |||
228 | x86_init.timers.timer_init = mrst_time_init; | ||
229 | x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock; | ||
230 | |||
231 | x86_init.irqs.pre_vector_init = x86_init_noop; | ||
232 | |||
233 | x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; | ||
234 | |||
235 | x86_platform.calibrate_tsc = mrst_calibrate_tsc; | ||
236 | x86_init.pci.init = pci_mrst_init; | ||
237 | x86_init.pci.fixup_irqs = x86_init_noop; | ||
238 | |||
239 | legacy_pic = &null_legacy_pic; | ||
24 | } | 240 | } |
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c index 9d1d263f786f..8297160c41b3 100644 --- a/arch/x86/kernel/olpc.c +++ b/arch/x86/kernel/olpc.c | |||
@@ -17,7 +17,9 @@ | |||
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | |||
20 | #include <asm/geode.h> | 21 | #include <asm/geode.h> |
22 | #include <asm/setup.h> | ||
21 | #include <asm/olpc.h> | 23 | #include <asm/olpc.h> |
22 | 24 | ||
23 | #ifdef CONFIG_OPEN_FIRMWARE | 25 | #ifdef CONFIG_OPEN_FIRMWARE |
@@ -243,9 +245,11 @@ static int __init olpc_init(void) | |||
243 | olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, | 245 | olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, |
244 | (unsigned char *) &olpc_platform_info.ecver, 1); | 246 | (unsigned char *) &olpc_platform_info.ecver, 1); |
245 | 247 | ||
246 | /* check to see if the VSA exists */ | 248 | #ifdef CONFIG_PCI_OLPC |
247 | if (cs5535_has_vsa2()) | 249 | /* If the VSA exists let it emulate PCI, if not emulate in kernel */ |
248 | olpc_platform_info.flags |= OLPC_F_VSA; | 250 | if (!cs5535_has_vsa2()) |
251 | x86_init.pci.arch_init = pci_olpc_init; | ||
252 | #endif | ||
249 | 253 | ||
250 | printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", | 254 | printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", |
251 | ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", | 255 | ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a435c76d714e..a02e80c3c54b 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/err.h> | 48 | #include <linux/err.h> |
49 | #include <linux/nmi.h> | 49 | #include <linux/nmi.h> |
50 | #include <linux/tboot.h> | 50 | #include <linux/tboot.h> |
51 | #include <linux/stackprotector.h> | ||
51 | 52 | ||
52 | #include <asm/acpi.h> | 53 | #include <asm/acpi.h> |
53 | #include <asm/desc.h> | 54 | #include <asm/desc.h> |
@@ -67,6 +68,7 @@ | |||
67 | #include <linux/mc146818rtc.h> | 68 | #include <linux/mc146818rtc.h> |
68 | 69 | ||
69 | #include <asm/smpboot_hooks.h> | 70 | #include <asm/smpboot_hooks.h> |
71 | #include <asm/i8259.h> | ||
70 | 72 | ||
71 | #ifdef CONFIG_X86_32 | 73 | #ifdef CONFIG_X86_32 |
72 | u8 apicid_2_node[MAX_APICID]; | 74 | u8 apicid_2_node[MAX_APICID]; |
@@ -291,9 +293,9 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
291 | check_tsc_sync_target(); | 293 | check_tsc_sync_target(); |
292 | 294 | ||
293 | if (nmi_watchdog == NMI_IO_APIC) { | 295 | if (nmi_watchdog == NMI_IO_APIC) { |
294 | disable_8259A_irq(0); | 296 | legacy_pic->chip->mask(0); |
295 | enable_NMI_through_LVT0(); | 297 | enable_NMI_through_LVT0(); |
296 | enable_8259A_irq(0); | 298 | legacy_pic->chip->unmask(0); |
297 | } | 299 | } |
298 | 300 | ||
299 | #ifdef CONFIG_X86_32 | 301 | #ifdef CONFIG_X86_32 |
@@ -329,6 +331,9 @@ notrace static void __cpuinit start_secondary(void *unused) | |||
329 | /* enable local interrupts */ | 331 | /* enable local interrupts */ |
330 | local_irq_enable(); | 332 | local_irq_enable(); |
331 | 333 | ||
334 | /* to prevent fake stack check failure in clock setup */ | ||
335 | boot_init_stack_canary(); | ||
336 | |||
332 | x86_cpuinit.setup_percpu_clockev(); | 337 | x86_cpuinit.setup_percpu_clockev(); |
333 | 338 | ||
334 | wmb(); | 339 | wmb(); |
diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c index ab38ce0984fa..e680ea52db9b 100644 --- a/arch/x86/kernel/visws_quirks.c +++ b/arch/x86/kernel/visws_quirks.c | |||
@@ -49,11 +49,6 @@ extern int no_broadcast; | |||
49 | char visws_board_type = -1; | 49 | char visws_board_type = -1; |
50 | char visws_board_rev = -1; | 50 | char visws_board_rev = -1; |
51 | 51 | ||
52 | int is_visws_box(void) | ||
53 | { | ||
54 | return visws_board_type >= 0; | ||
55 | } | ||
56 | |||
57 | static void __init visws_time_init(void) | 52 | static void __init visws_time_init(void) |
58 | { | 53 | { |
59 | printk(KERN_INFO "Starting Cobalt Timer system clock\n"); | 54 | printk(KERN_INFO "Starting Cobalt Timer system clock\n"); |
@@ -242,6 +237,8 @@ void __init visws_early_detect(void) | |||
242 | x86_init.irqs.pre_vector_init = visws_pre_intr_init; | 237 | x86_init.irqs.pre_vector_init = visws_pre_intr_init; |
243 | x86_init.irqs.trap_init = visws_trap_init; | 238 | x86_init.irqs.trap_init = visws_trap_init; |
244 | x86_init.timers.timer_init = visws_time_init; | 239 | x86_init.timers.timer_init = visws_time_init; |
240 | x86_init.pci.init = pci_visws_init; | ||
241 | x86_init.pci.init_irq = x86_init_noop; | ||
245 | 242 | ||
246 | /* | 243 | /* |
247 | * Install reboot quirks: | 244 | * Install reboot quirks: |
@@ -508,7 +505,7 @@ static struct irq_chip cobalt_irq_type = { | |||
508 | */ | 505 | */ |
509 | static unsigned int startup_piix4_master_irq(unsigned int irq) | 506 | static unsigned int startup_piix4_master_irq(unsigned int irq) |
510 | { | 507 | { |
511 | init_8259A(0); | 508 | legacy_pic->init(0); |
512 | 509 | ||
513 | return startup_cobalt_irq(irq); | 510 | return startup_cobalt_irq(irq); |
514 | } | 511 | } |
@@ -532,9 +529,6 @@ static struct irq_chip piix4_master_irq_type = { | |||
532 | 529 | ||
533 | static struct irq_chip piix4_virtual_irq_type = { | 530 | static struct irq_chip piix4_virtual_irq_type = { |
534 | .name = "PIIX4-virtual", | 531 | .name = "PIIX4-virtual", |
535 | .shutdown = disable_8259A_irq, | ||
536 | .enable = enable_8259A_irq, | ||
537 | .disable = disable_8259A_irq, | ||
538 | }; | 532 | }; |
539 | 533 | ||
540 | 534 | ||
@@ -609,7 +603,7 @@ static irqreturn_t piix4_master_intr(int irq, void *dev_id) | |||
609 | handle_IRQ_event(realirq, desc->action); | 603 | handle_IRQ_event(realirq, desc->action); |
610 | 604 | ||
611 | if (!(desc->status & IRQ_DISABLED)) | 605 | if (!(desc->status & IRQ_DISABLED)) |
612 | enable_8259A_irq(realirq); | 606 | legacy_pic->chip->unmask(realirq); |
613 | 607 | ||
614 | return IRQ_HANDLED; | 608 | return IRQ_HANDLED; |
615 | 609 | ||
@@ -628,6 +622,12 @@ static struct irqaction cascade_action = { | |||
628 | .name = "cascade", | 622 | .name = "cascade", |
629 | }; | 623 | }; |
630 | 624 | ||
625 | static inline void set_piix4_virtual_irq_type(void) | ||
626 | { | ||
627 | piix4_virtual_irq_type.shutdown = i8259A_chip.mask; | ||
628 | piix4_virtual_irq_type.enable = i8259A_chip.unmask; | ||
629 | piix4_virtual_irq_type.disable = i8259A_chip.mask; | ||
630 | } | ||
631 | 631 | ||
632 | void init_VISWS_APIC_irqs(void) | 632 | void init_VISWS_APIC_irqs(void) |
633 | { | 633 | { |
@@ -653,6 +653,7 @@ void init_VISWS_APIC_irqs(void) | |||
653 | desc->chip = &piix4_master_irq_type; | 653 | desc->chip = &piix4_master_irq_type; |
654 | } | 654 | } |
655 | else if (i < CO_IRQ_APIC0) { | 655 | else if (i < CO_IRQ_APIC0) { |
656 | set_piix4_virtual_irq_type(); | ||
656 | desc->chip = &piix4_virtual_irq_type; | 657 | desc->chip = &piix4_virtual_irq_type; |
657 | } | 658 | } |
658 | else if (IS_CO_APIC(i)) { | 659 | else if (IS_CO_APIC(i)) { |
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index ee5746c94628..61a1e8c7e19f 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
@@ -4,9 +4,11 @@ | |||
4 | * For licencing details see kernel-base/COPYING | 4 | * For licencing details see kernel-base/COPYING |
5 | */ | 5 | */ |
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/ioport.h> | ||
7 | 8 | ||
8 | #include <asm/bios_ebda.h> | 9 | #include <asm/bios_ebda.h> |
9 | #include <asm/paravirt.h> | 10 | #include <asm/paravirt.h> |
11 | #include <asm/pci_x86.h> | ||
10 | #include <asm/mpspec.h> | 12 | #include <asm/mpspec.h> |
11 | #include <asm/setup.h> | 13 | #include <asm/setup.h> |
12 | #include <asm/apic.h> | 14 | #include <asm/apic.h> |
@@ -70,6 +72,12 @@ struct x86_init_ops x86_init __initdata = { | |||
70 | .iommu = { | 72 | .iommu = { |
71 | .iommu_init = iommu_init_noop, | 73 | .iommu_init = iommu_init_noop, |
72 | }, | 74 | }, |
75 | |||
76 | .pci = { | ||
77 | .init = x86_default_pci_init, | ||
78 | .init_irq = x86_default_pci_init_irq, | ||
79 | .fixup_irqs = x86_default_pci_fixup_irqs, | ||
80 | }, | ||
73 | }; | 81 | }; |
74 | 82 | ||
75 | struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = { | 83 | struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = { |