ip32-irq.c 12.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 * Code to handle IP32 IRQs
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2000 Harald Koerfgen
 * Copyright (C) 2001 Keith M Wesolowski
 */
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/sched.h>

#include <asm/mipsregs.h>
#include <asm/signal.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/ip32/crime.h>
#include <asm/ip32/mace.h>
#include <asm/ip32/ip32_ints.h>

/* issue a PIO read to make sure no PIO writes are pending */
static void inline flush_crime_bus(void)
{
R
Ralf Baechle 已提交
34
	crime->control;
L
Linus Torvalds 已提交
35 36 37 38
}

static void inline flush_mace_bus(void)
{
R
Ralf Baechle 已提交
39
	mace->perif.ctrl.misc;
L
Linus Torvalds 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
}

#undef DEBUG_IRQ
#ifdef DEBUG_IRQ
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif

/* O2 irq map
 *
 * IP0 -> software (ignored)
 * IP1 -> software (ignored)
 * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
 * IP3 -> (irq1) X unknown
 * IP4 -> (irq2) X unknown
 * IP5 -> (irq3) X unknown
 * IP6 -> (irq4) X unknown
 * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
 *
 * crime: (C)
 *
 * CRIME_INT_STAT 31:0:
 *
 * 0  -> 1  Video in 1
 * 1  -> 2  Video in 2
 * 2  -> 3  Video out
 * 3  -> 4  Mace ethernet
 * 4  -> S  SuperIO sub-interrupt
 * 5  -> M  Miscellaneous sub-interrupt
 * 6  -> A  Audio sub-interrupt
 * 7  -> 8  PCI bridge errors
 * 8  -> 9  PCI SCSI aic7xxx 0
 * 9  -> 10 PCI SCSI aic7xxx 1
 * 10 -> 11 PCI slot 0
 * 11 -> 12 unused (PCI slot 1)
 * 12 -> 13 unused (PCI slot 2)
 * 13 -> 14 unused (PCI shared 0)
 * 14 -> 15 unused (PCI shared 1)
 * 15 -> 16 unused (PCI shared 2)
 * 16 -> 17 GBE0 (E)
 * 17 -> 18 GBE1 (E)
 * 18 -> 19 GBE2 (E)
 * 19 -> 20 GBE3 (E)
 * 20 -> 21 CPU errors
 * 21 -> 22 Memory errors
 * 22 -> 23 RE empty edge (E)
 * 23 -> 24 RE full edge (E)
 * 24 -> 25 RE idle edge (E)
 * 25 -> 26 RE empty level
 * 26 -> 27 RE full level
 * 27 -> 28 RE idle level
 * 28 -> 29 unused (software 0) (E)
 * 29 -> 30 unused (software 1) (E)
 * 30 -> 31 unused (software 2) - crime 1.5 CPU SysCorError (E)
 * 31 -> 32 VICE
 *
 * S, M, A: Use the MACE ISA interrupt register
 * MACE_ISA_INT_STAT 31:0
 *
 * 0-7 -> 33-40 Audio
 * 8 -> 41 RTC
 * 9 -> 42 Keyboard
 * 10 -> X Keyboard polled
 * 11 -> 44 Mouse
 * 12 -> X Mouse polled
 * 13-15 -> 46-48 Count/compare timers
 * 16-19 -> 49-52 Parallel (16 E)
 * 20-25 -> 53-58 Serial 1 (22 E)
 * 26-31 -> 59-64 Serial 2 (28 E)
 *
 * Note that this means IRQs 5-7, 43, and 45 do not exist.  This is a
 * different IRQ map than IRIX uses, but that's OK as Linux irq handling
 * is quite different anyway.
 */

/* Some initial interrupts to set up */
117 118
extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
L
Linus Torvalds 已提交
119

120 121 122 123 124 125 126 127 128 129 130 131
struct irqaction memerr_irq = {
	.handler = crime_memerr_intr,
	.flags = IRQF_DISABLED,
	.mask = CPU_MASK_NONE,
	.name = "CRIME memory error",
};
struct irqaction cpuerr_irq = {
	.handler = crime_cpuerr_intr,
	.flags = IRQF_DISABLED,
	.mask = CPU_MASK_NONE,
	.name = "CRIME CPU error",
};
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

/*
 * For interrupts wired from a single device to the CPU.  Only the clock
 * uses this it seems, which is IRQ 0 and IP7.
 */

static void enable_cpu_irq(unsigned int irq)
{
	set_c0_status(STATUSF_IP7);
}

static void disable_cpu_irq(unsigned int irq)
{
	clear_c0_status(STATUSF_IP7);
}

static void end_cpu_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
151
		enable_cpu_irq(irq);
L
Linus Torvalds 已提交
152 153
}

154
static struct irq_chip ip32_cpu_interrupt = {
155
	.name = "IP32 CPU",
A
Atsushi Nemoto 已提交
156 157 158 159
	.ack = disable_cpu_irq,
	.mask = disable_cpu_irq,
	.mask_ack = disable_cpu_irq,
	.unmask = enable_cpu_irq,
160
	.end = end_cpu_irq,
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
};

/*
 * This is for pure CRIME interrupts - ie not MACE.  The advantage?
 * We get to split the register in half and do faster lookups.
 */

static uint64_t crime_mask;

static void enable_crime_irq(unsigned int irq)
{
	crime_mask |= 1 << (irq - 1);
	crime->imask = crime_mask;
}

static void disable_crime_irq(unsigned int irq)
{
	crime_mask &= ~(1 << (irq - 1));
	crime->imask = crime_mask;
	flush_crime_bus();
}

static void mask_and_ack_crime_irq(unsigned int irq)
{
	/* Edge triggered interrupts must be cleared. */
	if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ)
	    || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ)
	    || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
	        uint64_t crime_int;
		crime_int = crime->hard_int;
		crime_int &= ~(1 << (irq - 1));
		crime->hard_int = crime_int;
	}
	disable_crime_irq(irq);
}

static void end_crime_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
		enable_crime_irq(irq);
}

203
static struct irq_chip ip32_crime_interrupt = {
204
	.name = "IP32 CRIME",
205
	.ack = mask_and_ack_crime_irq,
A
Atsushi Nemoto 已提交
206 207 208
	.mask = disable_crime_irq,
	.mask_ack = mask_and_ack_crime_irq,
	.unmask = enable_crime_irq,
209
	.end = end_crime_irq,
L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
};

/*
 * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
 * as close to the source as possible.  This also means we can take the
 * next chunk of the CRIME register in one piece.
 */

static unsigned long macepci_mask;

static void enable_macepci_irq(unsigned int irq)
{
	macepci_mask |= MACEPCI_CONTROL_INT(irq - 9);
	mace->pci.control = macepci_mask;
	crime_mask |= 1 << (irq - 1);
	crime->imask = crime_mask;
}

static void disable_macepci_irq(unsigned int irq)
{
	crime_mask &= ~(1 << (irq - 1));
	crime->imask = crime_mask;
	flush_crime_bus();
	macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
	mace->pci.control = macepci_mask;
	flush_mace_bus();
}

static void end_macepci_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
		enable_macepci_irq(irq);
}

244
static struct irq_chip ip32_macepci_interrupt = {
245
	.name = "IP32 MACE PCI",
A
Atsushi Nemoto 已提交
246 247 248 249
	.ack = disable_macepci_irq,
	.mask = disable_macepci_irq,
	.mask_ack = disable_macepci_irq,
	.unmask = enable_macepci_irq,
250
	.end = end_macepci_irq,
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
};

/* This is used for MACE ISA interrupts.  That means bits 4-6 in the
 * CRIME register.
 */

#define MACEISA_AUDIO_INT	(MACEISA_AUDIO_SW_INT |		\
				 MACEISA_AUDIO_SC_INT |		\
				 MACEISA_AUDIO1_DMAT_INT |	\
				 MACEISA_AUDIO1_OF_INT |	\
				 MACEISA_AUDIO2_DMAT_INT |	\
				 MACEISA_AUDIO2_MERR_INT |	\
				 MACEISA_AUDIO3_DMAT_INT |	\
				 MACEISA_AUDIO3_MERR_INT)
#define MACEISA_MISC_INT	(MACEISA_RTC_INT |		\
				 MACEISA_KEYB_INT |		\
				 MACEISA_KEYB_POLL_INT |	\
				 MACEISA_MOUSE_INT |		\
				 MACEISA_MOUSE_POLL_INT |	\
270 271 272
				 MACEISA_TIMER0_INT |		\
				 MACEISA_TIMER1_INT |		\
				 MACEISA_TIMER2_INT)
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
#define MACEISA_SUPERIO_INT	(MACEISA_PARALLEL_INT |		\
				 MACEISA_PAR_CTXA_INT |		\
				 MACEISA_PAR_CTXB_INT |		\
				 MACEISA_PAR_MERR_INT |		\
				 MACEISA_SERIAL1_INT |		\
				 MACEISA_SERIAL1_TDMAT_INT |	\
				 MACEISA_SERIAL1_TDMAPR_INT |	\
				 MACEISA_SERIAL1_TDMAME_INT |	\
				 MACEISA_SERIAL1_RDMAT_INT |	\
				 MACEISA_SERIAL1_RDMAOR_INT |	\
				 MACEISA_SERIAL2_INT |		\
				 MACEISA_SERIAL2_TDMAT_INT |	\
				 MACEISA_SERIAL2_TDMAPR_INT |	\
				 MACEISA_SERIAL2_TDMAME_INT |	\
				 MACEISA_SERIAL2_RDMAT_INT |	\
				 MACEISA_SERIAL2_RDMAOR_INT)

static unsigned long maceisa_mask;

292
static void enable_maceisa_irq(unsigned int irq)
L
Linus Torvalds 已提交
293 294 295
{
	unsigned int crime_int = 0;

296
	DBG("maceisa enable: %u\n", irq);
L
Linus Torvalds 已提交
297 298 299 300 301

	switch (irq) {
	case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
		crime_int = MACE_AUDIO_INT;
		break;
302
	case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
L
Linus Torvalds 已提交
303 304 305 306 307 308
		crime_int = MACE_MISC_INT;
		break;
	case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
		crime_int = MACE_SUPERIO_INT;
		break;
	}
309
	DBG("crime_int %08x enabled\n", crime_int);
L
Linus Torvalds 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	crime_mask |= crime_int;
	crime->imask = crime_mask;
	maceisa_mask |= 1 << (irq - 33);
	mace->perif.ctrl.imask = maceisa_mask;
}

static void disable_maceisa_irq(unsigned int irq)
{
	unsigned int crime_int = 0;

	maceisa_mask &= ~(1 << (irq - 33));
        if(!(maceisa_mask & MACEISA_AUDIO_INT))
		crime_int |= MACE_AUDIO_INT;
        if(!(maceisa_mask & MACEISA_MISC_INT))
		crime_int |= MACE_MISC_INT;
        if(!(maceisa_mask & MACEISA_SUPERIO_INT))
		crime_int |= MACE_SUPERIO_INT;
	crime_mask &= ~crime_int;
	crime->imask = crime_mask;
	flush_crime_bus();
	mace->perif.ctrl.imask = maceisa_mask;
	flush_mace_bus();
}

static void mask_and_ack_maceisa_irq(unsigned int irq)
{
A
Atsushi Nemoto 已提交
336
	unsigned long mace_int;
L
Linus Torvalds 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356

	switch (irq) {
	case MACEISA_PARALLEL_IRQ:
	case MACEISA_SERIAL1_TDMAPR_IRQ:
	case MACEISA_SERIAL2_TDMAPR_IRQ:
		/* edge triggered */
		mace_int = mace->perif.ctrl.istat;
		mace_int &= ~(1 << (irq - 33));
		mace->perif.ctrl.istat = mace_int;
		break;
	}
	disable_maceisa_irq(irq);
}

static void end_maceisa_irq(unsigned irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
		enable_maceisa_irq(irq);
}

357
static struct irq_chip ip32_maceisa_interrupt = {
358
	.name = "IP32 MACE ISA",
359
	.ack = mask_and_ack_maceisa_irq,
A
Atsushi Nemoto 已提交
360 361 362
	.mask = disable_maceisa_irq,
	.mask_ack = mask_and_ack_maceisa_irq,
	.unmask = enable_maceisa_irq,
363
	.end = end_maceisa_irq,
L
Linus Torvalds 已提交
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
};

/* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
 * bits 0-3 and 7 in the CRIME register.
 */

static void enable_mace_irq(unsigned int irq)
{
	crime_mask |= 1 << (irq - 1);
	crime->imask = crime_mask;
}

static void disable_mace_irq(unsigned int irq)
{
	crime_mask &= ~(1 << (irq - 1));
	crime->imask = crime_mask;
	flush_crime_bus();
}

static void end_mace_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
		enable_mace_irq(irq);
}

389
static struct irq_chip ip32_mace_interrupt = {
390
	.name = "IP32 MACE",
A
Atsushi Nemoto 已提交
391 392 393 394
	.ack = disable_mace_irq,
	.mask = disable_mace_irq,
	.mask_ack = disable_mace_irq,
	.unmask = enable_mace_irq,
395
	.end = end_mace_irq,
L
Linus Torvalds 已提交
396 397
};

398
static void ip32_unknown_interrupt(void)
L
Linus Torvalds 已提交
399
{
400 401 402 403 404 405 406 407 408
	printk("Unknown interrupt occurred!\n");
	printk("cp0_status: %08x\n", read_c0_status());
	printk("cp0_cause: %08x\n", read_c0_cause());
	printk("CRIME intr mask: %016lx\n", crime->imask);
	printk("CRIME intr status: %016lx\n", crime->istat);
	printk("CRIME hardware intr register: %016lx\n", crime->hard_int);
	printk("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask);
	printk("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat);
	printk("MACE PCI control register: %08x\n", mace->pci.control);
L
Linus Torvalds 已提交
409 410

	printk("Register dump:\n");
411
	show_regs(get_irq_regs());
L
Linus Torvalds 已提交
412 413 414 415 416 417 418 419

	printk("Please mail this report to linux-mips@linux-mips.org\n");
	printk("Spinning...");
	while(1) ;
}

/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
/* change this to loop over all edge-triggered irqs, exception masked out ones */
420
static void ip32_irq0(void)
L
Linus Torvalds 已提交
421 422 423 424 425
{
	uint64_t crime_int;
	int irq = 0;

	crime_int = crime->istat & crime_mask;
426 427
	irq = __ffs(crime_int);
	crime_int = 1 << irq;
L
Linus Torvalds 已提交
428 429 430

	if (crime_int & CRIME_MACEISA_INT_MASK) {
		unsigned long mace_int = mace->perif.ctrl.istat;
431
		irq = __ffs(mace_int & maceisa_mask) + 32;
L
Linus Torvalds 已提交
432
	}
433
	irq++;
L
Linus Torvalds 已提交
434
	DBG("*irq %u*\n", irq);
435
	do_IRQ(irq);
L
Linus Torvalds 已提交
436 437
}

438
static void ip32_irq1(void)
L
Linus Torvalds 已提交
439
{
440
	ip32_unknown_interrupt();
L
Linus Torvalds 已提交
441 442
}

443
static void ip32_irq2(void)
L
Linus Torvalds 已提交
444
{
445
	ip32_unknown_interrupt();
L
Linus Torvalds 已提交
446 447
}

448
static void ip32_irq3(void)
L
Linus Torvalds 已提交
449
{
450
	ip32_unknown_interrupt();
L
Linus Torvalds 已提交
451 452
}

453
static void ip32_irq4(void)
L
Linus Torvalds 已提交
454
{
455
	ip32_unknown_interrupt();
L
Linus Torvalds 已提交
456 457
}

458
static void ip32_irq5(void)
L
Linus Torvalds 已提交
459
{
460
	do_IRQ(IP32_R4K_TIMER_IRQ);
L
Linus Torvalds 已提交
461 462
}

463
asmlinkage void plat_irq_dispatch(void)
464
{
465
	unsigned int pending = read_c0_status() & read_c0_cause();
466 467

	if (likely(pending & IE_IRQ0))
468
		ip32_irq0();
469
	else if (unlikely(pending & IE_IRQ1))
470
		ip32_irq1();
471
	else if (unlikely(pending & IE_IRQ2))
472
		ip32_irq2();
473
	else if (unlikely(pending & IE_IRQ3))
474
		ip32_irq3();
475
	else if (unlikely(pending & IE_IRQ4))
476
		ip32_irq4();
477
	else if (likely(pending & IE_IRQ5))
478
		ip32_irq5();
479 480
}

L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489 490 491 492 493
void __init arch_init_irq(void)
{
	unsigned int irq;

	/* Install our interrupt handler, then clear and disable all
	 * CRIME and MACE interrupts. */
	crime->imask = 0;
	crime->hard_int = 0;
	crime->soft_int = 0;
	mace->perif.ctrl.istat = 0;
	mace->perif.ctrl.imask = 0;

	for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
494
		struct irq_chip *controller;
L
Linus Torvalds 已提交
495 496 497 498 499 500 501 502 503 504 505 506

		if (irq == IP32_R4K_TIMER_IRQ)
			controller = &ip32_cpu_interrupt;
		else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
			controller = &ip32_mace_interrupt;
		else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
			controller = &ip32_macepci_interrupt;
		else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
			controller = &ip32_crime_interrupt;
		else
			controller = &ip32_maceisa_interrupt;

A
Atsushi Nemoto 已提交
507
		set_irq_chip(irq, controller);
L
Linus Torvalds 已提交
508 509 510 511 512 513 514
	}
	setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
	setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);

#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
	change_c0_status(ST0_IM, ALLINTS);
}