Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.14 429 lines 13 kB view raw
1/* 2 * arch/ppc/kernel/mv64360_pic.c 3 * 4 * Interrupt controller support for Marvell's MV64360. 5 * 6 * Author: Rabeeh Khoury <rabeeh@galileo.co.il> 7 * Based on MV64360 PIC written by 8 * Chris Zankel <chris@mvista.com> 9 * Mark A. Greer <mgreer@mvista.com> 10 * 11 * Copyright 2004 MontaVista Software, Inc. 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 */ 18 19/* 20 * This file contains the specific functions to support the MV64360 21 * interrupt controller. 22 * 23 * The MV64360 has two main interrupt registers (high and low) that 24 * summarizes the interrupts generated by the units of the MV64360. 25 * Each bit is assigned to an interrupt number, where the low register 26 * are assigned from IRQ0 to IRQ31 and the high cause register 27 * from IRQ32 to IRQ63 28 * The GPP (General Purpose Pins) interrupts are assigned from IRQ64 (GPP0) 29 * to IRQ95 (GPP31). 30 * get_irq() returns the lowest interrupt number that is currently asserted. 31 * 32 * Note: 33 * - This driver does not initialize the GPP when used as an interrupt 34 * input. 35 */ 36 37#include <linux/stddef.h> 38#include <linux/init.h> 39#include <linux/sched.h> 40#include <linux/signal.h> 41#include <linux/stddef.h> 42#include <linux/delay.h> 43#include <linux/irq.h> 44#include <linux/interrupt.h> 45 46#include <asm/io.h> 47#include <asm/processor.h> 48#include <asm/system.h> 49#include <asm/irq.h> 50#include <asm/mv64x60.h> 51 52#ifdef CONFIG_IRQ_ALL_CPUS 53#error "The mv64360 does not support distribution of IRQs on all CPUs" 54#endif 55/* ========================== forward declaration ========================== */ 56 57static void mv64360_unmask_irq(unsigned int); 58static void mv64360_mask_irq(unsigned int); 59static irqreturn_t mv64360_cpu_error_int_handler(int, void *, struct pt_regs *); 60static irqreturn_t mv64360_sram_error_int_handler(int, void *, 61 struct pt_regs *); 62static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *); 63 64/* ========================== local declarations =========================== */ 65 66struct hw_interrupt_type mv64360_pic = { 67 .typename = " mv64360 ", 68 .enable = mv64360_unmask_irq, 69 .disable = mv64360_mask_irq, 70 .ack = mv64360_mask_irq, 71 .end = mv64360_unmask_irq, 72}; 73 74#define CPU_INTR_STR "mv64360 cpu interface error" 75#define SRAM_INTR_STR "mv64360 internal sram error" 76#define PCI0_INTR_STR "mv64360 pci 0 error" 77#define PCI1_INTR_STR "mv64360 pci 1 error" 78 79static struct mv64x60_handle bh; 80 81u32 mv64360_irq_base = 0; /* MV64360 handles the next 96 IRQs from here */ 82 83/* mv64360_init_irq() 84 * 85 * This function initializes the interrupt controller. It assigns 86 * all interrupts from IRQ0 to IRQ95 to the mv64360 interrupt controller. 87 * 88 * Input Variable(s): 89 * None. 90 * 91 * Outpu. Variable(s): 92 * None. 93 * 94 * Returns: 95 * void 96 * 97 * Note: 98 * We register all GPP inputs as interrupt source, but disable them. 99 */ 100void __init 101mv64360_init_irq(void) 102{ 103 int i; 104 105 if (ppc_md.progress) 106 ppc_md.progress("mv64360_init_irq: enter", 0x0); 107 108 bh.v_base = mv64x60_get_bridge_vbase(); 109 110 ppc_cached_irq_mask[0] = 0; 111 ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */ 112 ppc_cached_irq_mask[2] = 0; 113 114 /* disable all interrupts and clear current interrupts */ 115 mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, 0); 116 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, ppc_cached_irq_mask[2]); 117 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO,ppc_cached_irq_mask[0]); 118 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI,ppc_cached_irq_mask[1]); 119 120 /* All interrupts are level interrupts */ 121 for (i = mv64360_irq_base; i < (mv64360_irq_base + 96); i++) { 122 irq_desc[i].status |= IRQ_LEVEL; 123 irq_desc[i].handler = &mv64360_pic; 124 } 125 126 if (ppc_md.progress) 127 ppc_md.progress("mv64360_init_irq: exit", 0x0); 128} 129 130/* mv64360_get_irq() 131 * 132 * This function returns the lowest interrupt number of all interrupts that 133 * are currently asserted. 134 * 135 * Input Variable(s): 136 * struct pt_regs* not used 137 * 138 * Output Variable(s): 139 * None. 140 * 141 * Returns: 142 * int <interrupt number> or -2 (bogus interrupt) 143 * 144 */ 145int 146mv64360_get_irq(struct pt_regs *regs) 147{ 148 int irq; 149 int irq_gpp; 150 151#ifdef CONFIG_SMP 152 /* 153 * Second CPU gets only doorbell (message) interrupts. 154 * The doorbell interrupt is BIT28 in the main interrupt low cause reg. 155 */ 156 int cpu_nr = smp_processor_id(); 157 if (cpu_nr == 1) { 158 if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) & 159 (1 << MV64x60_IRQ_DOORBELL))) 160 return -1; 161 return mv64360_irq_base + MV64x60_IRQ_DOORBELL; 162 } 163#endif 164 165 irq = mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO); 166 irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]); 167 168 if (irq == -1) { 169 irq = mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_HI); 170 irq = __ilog2((irq & 0x1f0003f7) & ppc_cached_irq_mask[1]); 171 172 if (irq == -1) 173 irq = -2; /* bogus interrupt, should never happen */ 174 else { 175 if ((irq >= 24) && (irq < MV64x60_IRQ_DOORBELL)) { 176 irq_gpp = mv64x60_read(&bh, 177 MV64x60_GPP_INTR_CAUSE); 178 irq_gpp = __ilog2(irq_gpp & 179 ppc_cached_irq_mask[2]); 180 181 if (irq_gpp == -1) 182 irq = -2; 183 else { 184 irq = irq_gpp + 64; 185 mv64x60_write(&bh, 186 MV64x60_GPP_INTR_CAUSE, 187 ~(1 << (irq - 64))); 188 } 189 } 190 else 191 irq += 32; 192 } 193 } 194 195 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE); 196 197 if (irq < 0) 198 return (irq); 199 else 200 return (mv64360_irq_base + irq); 201} 202 203/* mv64360_unmask_irq() 204 * 205 * This function enables an interrupt. 206 * 207 * Input Variable(s): 208 * unsigned int interrupt number (IRQ0...IRQ95). 209 * 210 * Output Variable(s): 211 * None. 212 * 213 * Returns: 214 * void 215 */ 216static void 217mv64360_unmask_irq(unsigned int irq) 218{ 219#ifdef CONFIG_SMP 220 /* second CPU gets only doorbell interrupts */ 221 if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) { 222 mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, 223 (1 << MV64x60_IRQ_DOORBELL)); 224 return; 225 } 226#endif 227 irq -= mv64360_irq_base; 228 229 if (irq > 31) { 230 if (irq > 63) /* unmask GPP irq */ 231 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, 232 ppc_cached_irq_mask[2] |= (1 << (irq - 64))); 233 else /* mask high interrupt register */ 234 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI, 235 ppc_cached_irq_mask[1] |= (1 << (irq - 32))); 236 } 237 else /* mask low interrupt register */ 238 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO, 239 ppc_cached_irq_mask[0] |= (1 << irq)); 240 241 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK); 242 return; 243} 244 245/* mv64360_mask_irq() 246 * 247 * This function disables the requested interrupt. 248 * 249 * Input Variable(s): 250 * unsigned int interrupt number (IRQ0...IRQ95). 251 * 252 * Output Variable(s): 253 * None. 254 * 255 * Returns: 256 * void 257 */ 258static void 259mv64360_mask_irq(unsigned int irq) 260{ 261#ifdef CONFIG_SMP 262 if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) { 263 mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO, 264 (1 << MV64x60_IRQ_DOORBELL)); 265 return; 266 } 267#endif 268 irq -= mv64360_irq_base; 269 270 if (irq > 31) { 271 if (irq > 63) /* mask GPP irq */ 272 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, 273 ppc_cached_irq_mask[2] &= ~(1 << (irq - 64))); 274 else /* mask high interrupt register */ 275 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI, 276 ppc_cached_irq_mask[1] &= ~(1 << (irq - 32))); 277 } 278 else /* mask low interrupt register */ 279 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO, 280 ppc_cached_irq_mask[0] &= ~(1 << irq)); 281 282 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK); 283 return; 284} 285 286static irqreturn_t 287mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) 288{ 289 printk(KERN_ERR "mv64360_cpu_error_int_handler: %s 0x%08x\n", 290 "Error on CPU interface - Cause regiser", 291 mv64x60_read(&bh, MV64x60_CPU_ERR_CAUSE)); 292 printk(KERN_ERR "\tCPU error register dump:\n"); 293 printk(KERN_ERR "\tAddress low 0x%08x\n", 294 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_LO)); 295 printk(KERN_ERR "\tAddress high 0x%08x\n", 296 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_HI)); 297 printk(KERN_ERR "\tData low 0x%08x\n", 298 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_LO)); 299 printk(KERN_ERR "\tData high 0x%08x\n", 300 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_HI)); 301 printk(KERN_ERR "\tParity 0x%08x\n", 302 mv64x60_read(&bh, MV64x60_CPU_ERR_PARITY)); 303 mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0); 304 return IRQ_HANDLED; 305} 306 307static irqreturn_t 308mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) 309{ 310 printk(KERN_ERR "mv64360_sram_error_int_handler: %s 0x%08x\n", 311 "Error in internal SRAM - Cause register", 312 mv64x60_read(&bh, MV64360_SRAM_ERR_CAUSE)); 313 printk(KERN_ERR "\tSRAM error register dump:\n"); 314 printk(KERN_ERR "\tAddress Low 0x%08x\n", 315 mv64x60_read(&bh, MV64360_SRAM_ERR_ADDR_LO)); 316 printk(KERN_ERR "\tAddress High 0x%08x\n", 317 mv64x60_read(&bh, MV64360_SRAM_ERR_ADDR_HI)); 318 printk(KERN_ERR "\tData Low 0x%08x\n", 319 mv64x60_read(&bh, MV64360_SRAM_ERR_DATA_LO)); 320 printk(KERN_ERR "\tData High 0x%08x\n", 321 mv64x60_read(&bh, MV64360_SRAM_ERR_DATA_HI)); 322 printk(KERN_ERR "\tParity 0x%08x\n", 323 mv64x60_read(&bh, MV64360_SRAM_ERR_PARITY)); 324 mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0); 325 return IRQ_HANDLED; 326} 327 328static irqreturn_t 329mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs) 330{ 331 u32 val; 332 unsigned int pci_bus = (unsigned int)dev_id; 333 334 if (pci_bus == 0) { /* Error on PCI 0 */ 335 val = mv64x60_read(&bh, MV64x60_PCI0_ERR_CAUSE); 336 printk(KERN_ERR "%s: Error in PCI %d Interface\n", 337 "mv64360_pci_error_int_handler", pci_bus); 338 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus); 339 printk(KERN_ERR "\tCause register 0x%08x\n", val); 340 printk(KERN_ERR "\tAddress Low 0x%08x\n", 341 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_LO)); 342 printk(KERN_ERR "\tAddress High 0x%08x\n", 343 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_HI)); 344 printk(KERN_ERR "\tAttribute 0x%08x\n", 345 mv64x60_read(&bh, MV64x60_PCI0_ERR_DATA_LO)); 346 printk(KERN_ERR "\tCommand 0x%08x\n", 347 mv64x60_read(&bh, MV64x60_PCI0_ERR_CMD)); 348 mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, ~val); 349 } 350 if (pci_bus == 1) { /* Error on PCI 1 */ 351 val = mv64x60_read(&bh, MV64x60_PCI1_ERR_CAUSE); 352 printk(KERN_ERR "%s: Error in PCI %d Interface\n", 353 "mv64360_pci_error_int_handler", pci_bus); 354 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus); 355 printk(KERN_ERR "\tCause register 0x%08x\n", val); 356 printk(KERN_ERR "\tAddress Low 0x%08x\n", 357 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_LO)); 358 printk(KERN_ERR "\tAddress High 0x%08x\n", 359 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_HI)); 360 printk(KERN_ERR "\tAttribute 0x%08x\n", 361 mv64x60_read(&bh, MV64x60_PCI1_ERR_DATA_LO)); 362 printk(KERN_ERR "\tCommand 0x%08x\n", 363 mv64x60_read(&bh, MV64x60_PCI1_ERR_CMD)); 364 mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, ~val); 365 } 366 return IRQ_HANDLED; 367} 368 369/* 370 * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of 371 * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as 372 * well. IOW, don't set bit 0. 373 */ 374#define MV64360_PCI0_ERR_MASK_VAL 0x00a50c24 375 376static int __init 377mv64360_register_hdlrs(void) 378{ 379 int rc; 380 381 /* Clear old errors and register CPU interface error intr handler */ 382 mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0); 383 if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base, 384 mv64360_cpu_error_int_handler, SA_INTERRUPT, CPU_INTR_STR, 0))) 385 printk(KERN_WARNING "Can't register cpu error handler: %d", rc); 386 387 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0); 388 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0x000000ff); 389 390 /* Clear old errors and register internal SRAM error intr handler */ 391 mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0); 392 if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base, 393 mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0))) 394 printk(KERN_WARNING "Can't register SRAM error handler: %d",rc); 395 396 /* Clear old errors and register PCI 0 error intr handler */ 397 mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0); 398 if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base, 399 mv64360_pci_error_int_handler, 400 SA_INTERRUPT, PCI0_INTR_STR, (void *)0))) 401 printk(KERN_WARNING "Can't register pci 0 error handler: %d", 402 rc); 403 404 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0); 405 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL); 406 407 /* Erratum FEr PCI-#16 says to clear bit 0 of PCI SERRn Mask reg. */ 408 mv64x60_write(&bh, MV64x60_PCI0_ERR_SERR_MASK, 409 mv64x60_read(&bh, MV64x60_PCI0_ERR_SERR_MASK) & ~0x1UL); 410 411 /* Clear old errors and register PCI 1 error intr handler */ 412 mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0); 413 if ((rc = request_irq(MV64360_IRQ_PCI1 + mv64360_irq_base, 414 mv64360_pci_error_int_handler, 415 SA_INTERRUPT, PCI1_INTR_STR, (void *)1))) 416 printk(KERN_WARNING "Can't register pci 1 error handler: %d", 417 rc); 418 419 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0); 420 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, MV64360_PCI0_ERR_MASK_VAL); 421 422 /* Erratum FEr PCI-#16 says to clear bit 0 of PCI Intr Mask reg. */ 423 mv64x60_write(&bh, MV64x60_PCI1_ERR_SERR_MASK, 424 mv64x60_read(&bh, MV64x60_PCI1_ERR_SERR_MASK) & ~0x1UL); 425 426 return 0; 427} 428 429arch_initcall(mv64360_register_hdlrs);