blob: e02494bf5ef3541edae07756e622867e67f44729 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/alpha/kernel/sys_titan.c
3 *
4 * Copyright (C) 1995 David A Rusling
5 * Copyright (C) 1996, 1999 Jay A Estabrook
6 * Copyright (C) 1998, 1999 Richard Henderson
7 * Copyright (C) 1999, 2000 Jeff Wiedemeier
8 *
9 * Code supporting TITAN systems (EV6+TITAN), currently:
10 * Privateer
11 * Falcon
12 * Granite
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/types.h>
17#include <linux/mm.h>
18#include <linux/sched.h>
19#include <linux/pci.h>
20#include <linux/init.h>
21#include <linux/bitops.h>
22
23#include <asm/ptrace.h>
24#include <asm/system.h>
25#include <asm/dma.h>
26#include <asm/irq.h>
27#include <asm/mmu_context.h>
28#include <asm/io.h>
29#include <asm/pgtable.h>
30#include <asm/core_titan.h>
31#include <asm/hwrpb.h>
32#include <asm/tlbflush.h>
33
34#include "proto.h"
35#include "irq_impl.h"
36#include "pci_impl.h"
37#include "machvec_impl.h"
38#include "err_impl.h"
39
40
41/*
42 * Titan generic
43 */
44
45/*
46 * Titan supports up to 4 CPUs
47 */
48static unsigned long titan_cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
49
50/*
51 * Mask is set (1) if enabled
52 */
53static unsigned long titan_cached_irq_mask;
54
55/*
56 * Need SMP-safe access to interrupt CSRs
57 */
58DEFINE_SPINLOCK(titan_irq_lock);
59
60static void
61titan_update_irq_hw(unsigned long mask)
62{
63 register titan_cchip *cchip = TITAN_cchip;
64 unsigned long isa_enable = 1UL << 55;
65 register int bcpu = boot_cpuid;
66
67#ifdef CONFIG_SMP
Ivan Kokshayskyc7d2d282006-06-04 02:51:34 -070068 cpumask_t cpm = cpu_present_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 volatile unsigned long *dim0, *dim1, *dim2, *dim3;
70 unsigned long mask0, mask1, mask2, mask3, dummy;
71
72 mask &= ~isa_enable;
73 mask0 = mask & titan_cpu_irq_affinity[0];
74 mask1 = mask & titan_cpu_irq_affinity[1];
75 mask2 = mask & titan_cpu_irq_affinity[2];
76 mask3 = mask & titan_cpu_irq_affinity[3];
77
78 if (bcpu == 0) mask0 |= isa_enable;
79 else if (bcpu == 1) mask1 |= isa_enable;
80 else if (bcpu == 2) mask2 |= isa_enable;
81 else mask3 |= isa_enable;
82
83 dim0 = &cchip->dim0.csr;
84 dim1 = &cchip->dim1.csr;
85 dim2 = &cchip->dim2.csr;
86 dim3 = &cchip->dim3.csr;
87 if (!cpu_isset(0, cpm)) dim0 = &dummy;
88 if (!cpu_isset(1, cpm)) dim1 = &dummy;
89 if (!cpu_isset(2, cpm)) dim2 = &dummy;
90 if (!cpu_isset(3, cpm)) dim3 = &dummy;
91
92 *dim0 = mask0;
93 *dim1 = mask1;
94 *dim2 = mask2;
95 *dim3 = mask3;
96 mb();
97 *dim0;
98 *dim1;
99 *dim2;
100 *dim3;
101#else
102 volatile unsigned long *dimB;
103 dimB = &cchip->dim0.csr;
104 if (bcpu == 1) dimB = &cchip->dim1.csr;
105 else if (bcpu == 2) dimB = &cchip->dim2.csr;
106 else if (bcpu == 3) dimB = &cchip->dim3.csr;
107
108 *dimB = mask | isa_enable;
109 mb();
110 *dimB;
111#endif
112}
113
114static inline void
115titan_enable_irq(unsigned int irq)
116{
117 spin_lock(&titan_irq_lock);
118 titan_cached_irq_mask |= 1UL << (irq - 16);
119 titan_update_irq_hw(titan_cached_irq_mask);
120 spin_unlock(&titan_irq_lock);
121}
122
123static inline void
124titan_disable_irq(unsigned int irq)
125{
126 spin_lock(&titan_irq_lock);
127 titan_cached_irq_mask &= ~(1UL << (irq - 16));
128 titan_update_irq_hw(titan_cached_irq_mask);
129 spin_unlock(&titan_irq_lock);
130}
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static void
133titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
134{
135 int cpu;
136
137 for (cpu = 0; cpu < 4; cpu++) {
138 if (cpu_isset(cpu, affinity))
139 titan_cpu_irq_affinity[cpu] |= 1UL << irq;
140 else
141 titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
142 }
143
144}
145
Yinghai Lud5dedd42009-04-27 17:59:21 -0700146static int
Rusty Russell0de26522008-12-13 21:20:26 +1030147titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
149 spin_lock(&titan_irq_lock);
Rusty Russell0de26522008-12-13 21:20:26 +1030150 titan_cpu_set_irq_affinity(irq - 16, *affinity);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 titan_update_irq_hw(titan_cached_irq_mask);
152 spin_unlock(&titan_irq_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700153
154 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
157static void
Al Viro7ca56052006-10-08 14:36:08 +0100158titan_device_interrupt(unsigned long vector)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Frans Pop7f2d8892010-03-01 13:29:14 -0500160 printk("titan_device_interrupt: NOT IMPLEMENTED YET!!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
163static void
Al Viro7ca56052006-10-08 14:36:08 +0100164titan_srm_device_interrupt(unsigned long vector)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
166 int irq;
167
168 irq = (vector - 0x800) >> 4;
Al Viro3dbb8c62006-10-08 14:37:32 +0100169 handle_irq(irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170}
171
172
173static void __init
Thomas Gleixner44377f62009-06-16 15:33:25 -0700174init_titan_irqs(struct irq_chip * ops, int imin, int imax)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 long i;
177 for (i = imin; i <= imax; ++i) {
Kyle McMartina891b392010-10-14 22:31:25 -0400178 irq_to_desc(i)->status |= IRQ_LEVEL;
Kyle McMartin7d209c82010-10-14 22:31:34 -0400179 set_irq_chip_and_handler(i, ops, handle_level_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181}
182
Thomas Gleixner44377f62009-06-16 15:33:25 -0700183static struct irq_chip titan_irq_type = {
Kyle McMartin7d209c82010-10-14 22:31:34 -0400184 .name = "TITAN",
185 .unmask = titan_enable_irq,
186 .mask = titan_disable_irq,
187 .mask_ack = titan_disable_irq,
188 .set_affinity = titan_set_irq_affinity,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189};
190
191static irqreturn_t
Al Viro041a6ba2006-10-09 12:46:52 +0100192titan_intr_nop(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
194 /*
195 * This is a NOP interrupt handler for the purposes of
196 * event counting -- just return.
197 */
198 return IRQ_HANDLED;
199}
200
201static void __init
202titan_init_irq(void)
203{
204 if (alpha_using_srm && !alpha_mv.device_interrupt)
205 alpha_mv.device_interrupt = titan_srm_device_interrupt;
206 if (!alpha_mv.device_interrupt)
207 alpha_mv.device_interrupt = titan_device_interrupt;
208
209 titan_update_irq_hw(0);
210
211 init_titan_irqs(&titan_irq_type, 16, 63 + 16);
212}
213
214static void __init
215titan_legacy_init_irq(void)
216{
217 /* init the legacy dma controller */
218 outb(0, DMA1_RESET_REG);
219 outb(0, DMA2_RESET_REG);
220 outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
221 outb(0, DMA2_MASK_REG);
222
223 /* init the legacy irq controller */
224 init_i8259a_irqs();
225
226 /* init the titan irqs */
227 titan_init_irq();
228}
229
230void
Al Viro2f116cb2006-10-08 14:45:28 +0100231titan_dispatch_irqs(u64 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 unsigned long vector;
234
235 /*
236 * Mask down to those interrupts which are enable on this processor
237 */
238 mask &= titan_cpu_irq_affinity[smp_processor_id()];
239
240 /*
241 * Dispatch all requested interrupts
242 */
243 while (mask) {
244 /* convert to SRM vector... priority is <63> -> <0> */
Ivan Kokshaysky88ed39b2007-04-16 22:53:21 -0700245 vector = 63 - __kernel_ctlz(mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 mask &= ~(1UL << vector); /* clear it out */
247 vector = 0x900 + (vector << 4); /* convert to SRM vector */
248
249 /* dispatch it */
Al Viro7ca56052006-10-08 14:36:08 +0100250 alpha_mv.device_interrupt(vector);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
252}
253
254
255/*
256 * Titan Family
257 */
258static void __init
Jay Estabrookf6901e62007-08-10 13:01:12 -0700259titan_request_irq(unsigned int irq, irq_handler_t handler,
260 unsigned long irqflags, const char *devname,
261 void *dev_id)
262{
263 int err;
264 err = request_irq(irq, handler, irqflags, devname, dev_id);
265 if (err) {
266 printk("titan_request_irq for IRQ %d returned %d; ignoring\n",
267 irq, err);
268 }
269}
270
271static void __init
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272titan_late_init(void)
273{
274 /*
275 * Enable the system error interrupts. These interrupts are
276 * all reported to the kernel as machine checks, so the handler
277 * is a nop so it can be called to count the individual events.
278 */
Jay Estabrookf6901e62007-08-10 13:01:12 -0700279 titan_request_irq(63+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 "CChip Error", NULL);
Jay Estabrookf6901e62007-08-10 13:01:12 -0700281 titan_request_irq(62+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 "PChip 0 H_Error", NULL);
Jay Estabrookf6901e62007-08-10 13:01:12 -0700283 titan_request_irq(61+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 "PChip 1 H_Error", NULL);
Jay Estabrookf6901e62007-08-10 13:01:12 -0700285 titan_request_irq(60+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 "PChip 0 C_Error", NULL);
Jay Estabrookf6901e62007-08-10 13:01:12 -0700287 titan_request_irq(59+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 "PChip 1 C_Error", NULL);
289
290 /*
291 * Register our error handlers.
292 */
293 titan_register_error_handlers();
294
295 /*
296 * Check if the console left us any error logs.
297 */
298 cdl_check_console_data_log();
299
300}
301
302static int __devinit
303titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
304{
305 u8 intline;
306 int irq;
307
308 /* Get the current intline. */
309 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
310 irq = intline;
311
312 /* Is it explicitly routed through ISA? */
313 if ((irq & 0xF0) == 0xE0)
314 return irq;
315
316 /* Offset by 16 to make room for ISA interrupts 0 - 15. */
317 return irq + 16;
318}
319
320static void __init
321titan_init_pci(void)
322{
323 /*
324 * This isn't really the right place, but there's some init
325 * that needs to be done after everything is basically up.
326 */
327 titan_late_init();
328
329 pci_probe_only = 1;
330 common_init_pci();
331 SMC669_Init(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 locate_and_init_vga(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
335
336/*
337 * Privateer
338 */
339static void __init
340privateer_init_pci(void)
341{
342 /*
343 * Hook a couple of extra err interrupts that the
344 * common titan code won't.
345 */
Jay Estabrookf6901e62007-08-10 13:01:12 -0700346 titan_request_irq(53+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 "NMI", NULL);
Jay Estabrookf6901e62007-08-10 13:01:12 -0700348 titan_request_irq(50+16, titan_intr_nop, IRQF_DISABLED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 "Temperature Warning", NULL);
350
351 /*
352 * Finish with the common version.
353 */
354 return titan_init_pci();
355}
356
357
358/*
359 * The System Vectors.
360 */
361struct alpha_machine_vector titan_mv __initmv = {
362 .vector_name = "TITAN",
363 DO_EV6_MMU,
364 DO_DEFAULT_RTC,
365 DO_TITAN_IO,
366 .machine_check = titan_machine_check,
367 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
368 .min_io_address = DEFAULT_IO_BASE,
369 .min_mem_address = DEFAULT_MEM_BASE,
370 .pci_dac_offset = TITAN_DAC_OFFSET,
371
372 .nr_irqs = 80, /* 64 + 16 */
373 /* device_interrupt will be filled in by titan_init_irq */
374
375 .agp_info = titan_agp_info,
376
377 .init_arch = titan_init_arch,
378 .init_irq = titan_legacy_init_irq,
379 .init_rtc = common_init_rtc,
380 .init_pci = titan_init_pci,
381
382 .kill_arch = titan_kill_arch,
383 .pci_map_irq = titan_map_irq,
384 .pci_swizzle = common_swizzle,
385};
386ALIAS_MV(titan)
387
388struct alpha_machine_vector privateer_mv __initmv = {
389 .vector_name = "PRIVATEER",
390 DO_EV6_MMU,
391 DO_DEFAULT_RTC,
392 DO_TITAN_IO,
393 .machine_check = privateer_machine_check,
394 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
395 .min_io_address = DEFAULT_IO_BASE,
396 .min_mem_address = DEFAULT_MEM_BASE,
397 .pci_dac_offset = TITAN_DAC_OFFSET,
398
399 .nr_irqs = 80, /* 64 + 16 */
400 /* device_interrupt will be filled in by titan_init_irq */
401
402 .agp_info = titan_agp_info,
403
404 .init_arch = titan_init_arch,
405 .init_irq = titan_legacy_init_irq,
406 .init_rtc = common_init_rtc,
407 .init_pci = privateer_init_pci,
408
409 .kill_arch = titan_kill_arch,
410 .pci_map_irq = titan_map_irq,
411 .pci_swizzle = common_swizzle,
412};
413/* No alpha_mv alias for privateer since we compile it
414 in unconditionally with titan; setup_arch knows how to cope. */