at v2.6.14 1086 lines 29 kB view raw
1/* 2 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling 3 * 4 * Copyright (C) 1997 Geert Uytterhoeven 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive 8 * for more details. 9 */ 10 11#include <linux/config.h> 12#include <linux/types.h> 13#include <linux/kernel.h> 14#include <linux/sched.h> 15#include <linux/init.h> 16#include <linux/interrupt.h> 17#include <linux/sysdev.h> 18#include <linux/errno.h> 19#include <asm/ptrace.h> 20#include <asm/signal.h> 21#include <asm/io.h> 22#include <asm/irq.h> 23#include <asm/sections.h> 24#include <asm/open_pic.h> 25#include <asm/i8259.h> 26 27#include "open_pic_defs.h" 28 29#if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx) 30#define OPENPIC_BIG_ENDIAN 31#endif 32 33void __iomem *OpenPIC_Addr; 34static volatile struct OpenPIC __iomem *OpenPIC = NULL; 35 36/* 37 * We define OpenPIC_InitSenses table thusly: 38 * bit 0x1: sense, 0 for edge and 1 for level. 39 * bit 0x2: polarity, 0 for negative, 1 for positive. 40 */ 41u_int OpenPIC_NumInitSenses __initdata = 0; 42u_char *OpenPIC_InitSenses __initdata = NULL; 43extern int use_of_interrupt_tree; 44 45static u_int NumProcessors; 46static u_int NumSources; 47static int open_pic_irq_offset; 48static volatile OpenPIC_Source __iomem *ISR[NR_IRQS]; 49static int openpic_cascade_irq = -1; 50static int (*openpic_cascade_fn)(struct pt_regs *); 51 52/* Global Operations */ 53static void openpic_disable_8259_pass_through(void); 54static void openpic_set_spurious(u_int vector); 55 56#ifdef CONFIG_SMP 57/* Interprocessor Interrupts */ 58static void openpic_initipi(u_int ipi, u_int pri, u_int vector); 59static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *); 60#endif 61 62/* Timer Interrupts */ 63static void openpic_inittimer(u_int timer, u_int pri, u_int vector); 64static void openpic_maptimer(u_int timer, cpumask_t cpumask); 65 66/* Interrupt Sources */ 67static void openpic_enable_irq(u_int irq); 68static void openpic_disable_irq(u_int irq); 69static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, 70 int is_level); 71static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask); 72 73/* 74 * These functions are not used but the code is kept here 75 * for completeness and future reference. 76 */ 77#ifdef notused 78static void openpic_enable_8259_pass_through(void); 79static u_int openpic_get_spurious(void); 80static void openpic_set_sense(u_int irq, int sense); 81#endif /* notused */ 82 83/* 84 * Description of the openpic for the higher-level irq code 85 */ 86static void openpic_end_irq(unsigned int irq_nr); 87static void openpic_ack_irq(unsigned int irq_nr); 88static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask); 89 90struct hw_interrupt_type open_pic = { 91 .typename = " OpenPIC ", 92 .enable = openpic_enable_irq, 93 .disable = openpic_disable_irq, 94 .ack = openpic_ack_irq, 95 .end = openpic_end_irq, 96 .set_affinity = openpic_set_affinity, 97}; 98 99#ifdef CONFIG_SMP 100static void openpic_end_ipi(unsigned int irq_nr); 101static void openpic_ack_ipi(unsigned int irq_nr); 102static void openpic_enable_ipi(unsigned int irq_nr); 103static void openpic_disable_ipi(unsigned int irq_nr); 104 105struct hw_interrupt_type open_pic_ipi = { 106 .typename = " OpenPIC ", 107 .enable = openpic_enable_ipi, 108 .disable = openpic_disable_ipi, 109 .ack = openpic_ack_ipi, 110 .end = openpic_end_ipi, 111}; 112#endif /* CONFIG_SMP */ 113 114/* 115 * Accesses to the current processor's openpic registers 116 */ 117#ifdef CONFIG_SMP 118#define THIS_CPU Processor[cpu] 119#define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()] 120#define CHECK_THIS_CPU check_arg_cpu(cpu) 121#else 122#define THIS_CPU Processor[0] 123#define DECL_THIS_CPU 124#define CHECK_THIS_CPU 125#endif /* CONFIG_SMP */ 126 127#if 1 128#define check_arg_ipi(ipi) \ 129 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ 130 printk("open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi); 131#define check_arg_timer(timer) \ 132 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ 133 printk("open_pic.c:%d: invalid timer %d\n", __LINE__, timer); 134#define check_arg_vec(vec) \ 135 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ 136 printk("open_pic.c:%d: invalid vector %d\n", __LINE__, vec); 137#define check_arg_pri(pri) \ 138 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ 139 printk("open_pic.c:%d: invalid priority %d\n", __LINE__, pri); 140/* 141 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's 142 * data has probably been corrupted and we're going to panic or deadlock later 143 * anyway --Troy 144 */ 145#define check_arg_irq(irq) \ 146 if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \ 147 || ISR[irq - open_pic_irq_offset] == 0) { \ 148 printk("open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \ 149 dump_stack(); } 150#define check_arg_cpu(cpu) \ 151 if (cpu < 0 || cpu >= NumProcessors){ \ 152 printk("open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \ 153 dump_stack(); } 154#else 155#define check_arg_ipi(ipi) do {} while (0) 156#define check_arg_timer(timer) do {} while (0) 157#define check_arg_vec(vec) do {} while (0) 158#define check_arg_pri(pri) do {} while (0) 159#define check_arg_irq(irq) do {} while (0) 160#define check_arg_cpu(cpu) do {} while (0) 161#endif 162 163u_int openpic_read(volatile u_int __iomem *addr) 164{ 165 u_int val; 166 167#ifdef OPENPIC_BIG_ENDIAN 168 val = in_be32(addr); 169#else 170 val = in_le32(addr); 171#endif 172 return val; 173} 174 175static inline void openpic_write(volatile u_int __iomem *addr, u_int val) 176{ 177#ifdef OPENPIC_BIG_ENDIAN 178 out_be32(addr, val); 179#else 180 out_le32(addr, val); 181#endif 182} 183 184static inline u_int openpic_readfield(volatile u_int __iomem *addr, u_int mask) 185{ 186 u_int val = openpic_read(addr); 187 return val & mask; 188} 189 190inline void openpic_writefield(volatile u_int __iomem *addr, u_int mask, 191 u_int field) 192{ 193 u_int val = openpic_read(addr); 194 openpic_write(addr, (val & ~mask) | (field & mask)); 195} 196 197static inline void openpic_clearfield(volatile u_int __iomem *addr, u_int mask) 198{ 199 openpic_writefield(addr, mask, 0); 200} 201 202static inline void openpic_setfield(volatile u_int __iomem *addr, u_int mask) 203{ 204 openpic_writefield(addr, mask, mask); 205} 206 207static void openpic_safe_writefield(volatile u_int __iomem *addr, u_int mask, 208 u_int field) 209{ 210 openpic_setfield(addr, OPENPIC_MASK); 211 while (openpic_read(addr) & OPENPIC_ACTIVITY); 212 openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); 213} 214 215#ifdef CONFIG_SMP 216/* yes this is right ... bug, feature, you decide! -- tgall */ 217u_int openpic_read_IPI(volatile u_int __iomem * addr) 218{ 219 u_int val = 0; 220#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3) 221 val = in_be32(addr); 222#else 223 val = in_le32(addr); 224#endif 225 return val; 226} 227 228/* because of the power3 be / le above, this is needed */ 229inline void openpic_writefield_IPI(volatile u_int __iomem * addr, u_int mask, u_int field) 230{ 231 u_int val = openpic_read_IPI(addr); 232 openpic_write(addr, (val & ~mask) | (field & mask)); 233} 234 235static inline void openpic_clearfield_IPI(volatile u_int __iomem *addr, u_int mask) 236{ 237 openpic_writefield_IPI(addr, mask, 0); 238} 239 240static inline void openpic_setfield_IPI(volatile u_int __iomem *addr, u_int mask) 241{ 242 openpic_writefield_IPI(addr, mask, mask); 243} 244 245static void openpic_safe_writefield_IPI(volatile u_int __iomem *addr, u_int mask, u_int field) 246{ 247 openpic_setfield_IPI(addr, OPENPIC_MASK); 248 249 /* wait until it's not in use */ 250 /* BenH: Is this code really enough ? I would rather check the result 251 * and eventually retry ... 252 */ 253 while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY); 254 255 openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); 256} 257#endif /* CONFIG_SMP */ 258 259#ifdef CONFIG_EPIC_SERIAL_MODE 260/* On platforms that may use EPIC serial mode, the default is enabled. */ 261int epic_serial_mode = 1; 262 263static void __init openpic_eicr_set_clk(u_int clkval) 264{ 265 openpic_writefield(&OpenPIC->Global.Global_Configuration1, 266 OPENPIC_EICR_S_CLK_MASK, (clkval << 28)); 267} 268 269static void __init openpic_enable_sie(void) 270{ 271 openpic_setfield(&OpenPIC->Global.Global_Configuration1, 272 OPENPIC_EICR_SIE); 273} 274#endif 275 276#if defined(CONFIG_EPIC_SERIAL_MODE) 277static void openpic_reset(void) 278{ 279 openpic_setfield(&OpenPIC->Global.Global_Configuration0, 280 OPENPIC_CONFIG_RESET); 281 while (openpic_readfield(&OpenPIC->Global.Global_Configuration0, 282 OPENPIC_CONFIG_RESET)) 283 mb(); 284} 285#endif 286 287void __init openpic_set_sources(int first_irq, int num_irqs, void __iomem *first_ISR) 288{ 289 volatile OpenPIC_Source __iomem *src = first_ISR; 290 int i, last_irq; 291 292 last_irq = first_irq + num_irqs; 293 if (last_irq > NumSources) 294 NumSources = last_irq; 295 if (src == 0) 296 src = &((struct OpenPIC __iomem *)OpenPIC_Addr)->Source[first_irq]; 297 for (i = first_irq; i < last_irq; ++i, ++src) 298 ISR[i] = src; 299} 300 301/* 302 * The `offset' parameter defines where the interrupts handled by the 303 * OpenPIC start in the space of interrupt numbers that the kernel knows 304 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the 305 * kernel's interrupt numbering scheme. 306 * We assume there is only one OpenPIC. 307 */ 308void __init openpic_init(int offset) 309{ 310 u_int t, i; 311 u_int timerfreq; 312 const char *version; 313 314 if (!OpenPIC_Addr) { 315 printk("No OpenPIC found !\n"); 316 return; 317 } 318 OpenPIC = (volatile struct OpenPIC __iomem *)OpenPIC_Addr; 319 320#ifdef CONFIG_EPIC_SERIAL_MODE 321 /* Have to start from ground zero. 322 */ 323 openpic_reset(); 324#endif 325 326 if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122); 327 328 t = openpic_read(&OpenPIC->Global.Feature_Reporting0); 329 switch (t & OPENPIC_FEATURE_VERSION_MASK) { 330 case 1: 331 version = "1.0"; 332 break; 333 case 2: 334 version = "1.2"; 335 break; 336 case 3: 337 version = "1.3"; 338 break; 339 default: 340 version = "?"; 341 break; 342 } 343 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> 344 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; 345 if (NumSources == 0) 346 openpic_set_sources(0, 347 ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> 348 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1, 349 NULL); 350 printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", 351 version, NumProcessors, NumSources, OpenPIC); 352 timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); 353 if (timerfreq) 354 printk("OpenPIC timer frequency is %d.%06d MHz\n", 355 timerfreq / 1000000, timerfreq % 1000000); 356 357 open_pic_irq_offset = offset; 358 359 /* Initialize timer interrupts */ 360 if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba); 361 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { 362 /* Disabled, Priority 0 */ 363 openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset); 364 /* No processor */ 365 openpic_maptimer(i, CPU_MASK_NONE); 366 } 367 368#ifdef CONFIG_SMP 369 /* Initialize IPI interrupts */ 370 if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb); 371 for (i = 0; i < OPENPIC_NUM_IPI; i++) { 372 /* Disabled, increased priorities 10..13 */ 373 openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i, 374 OPENPIC_VEC_IPI+i+offset); 375 /* IPIs are per-CPU */ 376 irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU; 377 irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi; 378 } 379#endif 380 381 /* Initialize external interrupts */ 382 if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc); 383 384 openpic_set_priority(0xf); 385 386 /* Init all external sources, including possibly the cascade. */ 387 for (i = 0; i < NumSources; i++) { 388 int sense; 389 390 if (ISR[i] == 0) 391 continue; 392 393 /* the bootloader may have left it enabled (bad !) */ 394 openpic_disable_irq(i+offset); 395 396 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \ 397 (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE); 398 399 if (sense & IRQ_SENSE_MASK) 400 irq_desc[i+offset].status = IRQ_LEVEL; 401 402 /* Enabled, Default priority */ 403 openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset, 404 (sense & IRQ_POLARITY_MASK), 405 (sense & IRQ_SENSE_MASK)); 406 /* Processor 0 */ 407 openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE); 408 } 409 410 /* Init descriptors */ 411 for (i = offset; i < NumSources + offset; i++) 412 irq_desc[i].handler = &open_pic; 413 414 /* Initialize the spurious interrupt */ 415 if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd); 416 openpic_set_spurious(OPENPIC_VEC_SPURIOUS); 417 openpic_disable_8259_pass_through(); 418#ifdef CONFIG_EPIC_SERIAL_MODE 419 if (epic_serial_mode) { 420 openpic_eicr_set_clk(7); /* Slowest value until we know better */ 421 openpic_enable_sie(); 422 } 423#endif 424 openpic_set_priority(0); 425 426 if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222); 427} 428 429#ifdef notused 430static void openpic_enable_8259_pass_through(void) 431{ 432 openpic_clearfield(&OpenPIC->Global.Global_Configuration0, 433 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); 434} 435#endif /* notused */ 436 437static void openpic_disable_8259_pass_through(void) 438{ 439 openpic_setfield(&OpenPIC->Global.Global_Configuration0, 440 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); 441} 442 443/* 444 * Find out the current interrupt 445 */ 446u_int openpic_irq(void) 447{ 448 u_int vec; 449 DECL_THIS_CPU; 450 451 CHECK_THIS_CPU; 452 vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge, 453 OPENPIC_VECTOR_MASK); 454 return vec; 455} 456 457void openpic_eoi(void) 458{ 459 DECL_THIS_CPU; 460 461 CHECK_THIS_CPU; 462 openpic_write(&OpenPIC->THIS_CPU.EOI, 0); 463 /* Handle PCI write posting */ 464 (void)openpic_read(&OpenPIC->THIS_CPU.EOI); 465} 466 467u_int openpic_get_priority(void) 468{ 469 DECL_THIS_CPU; 470 471 CHECK_THIS_CPU; 472 return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, 473 OPENPIC_CURRENT_TASK_PRIORITY_MASK); 474} 475 476void openpic_set_priority(u_int pri) 477{ 478 DECL_THIS_CPU; 479 480 CHECK_THIS_CPU; 481 check_arg_pri(pri); 482 openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority, 483 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); 484} 485 486/* 487 * Get/set the spurious vector 488 */ 489#ifdef notused 490static u_int openpic_get_spurious(void) 491{ 492 return openpic_readfield(&OpenPIC->Global.Spurious_Vector, 493 OPENPIC_VECTOR_MASK); 494} 495#endif /* notused */ 496 497static void openpic_set_spurious(u_int vec) 498{ 499 check_arg_vec(vec); 500 openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, 501 vec); 502} 503 504#ifdef CONFIG_SMP 505/* 506 * Convert a cpu mask from logical to physical cpu numbers. 507 */ 508static inline cpumask_t physmask(cpumask_t cpumask) 509{ 510 int i; 511 cpumask_t mask = CPU_MASK_NONE; 512 513 cpus_and(cpumask, cpu_online_map, cpumask); 514 515 for (i = 0; i < NR_CPUS; i++) 516 if (cpu_isset(i, cpumask)) 517 cpu_set(smp_hw_index[i], mask); 518 519 return mask; 520} 521#else 522#define physmask(cpumask) (cpumask) 523#endif 524 525void openpic_reset_processor_phys(u_int mask) 526{ 527 openpic_write(&OpenPIC->Global.Processor_Initialization, mask); 528} 529 530#if defined(CONFIG_SMP) || defined(CONFIG_PM) 531static DEFINE_SPINLOCK(openpic_setup_lock); 532#endif 533 534#ifdef CONFIG_SMP 535/* 536 * Initialize an interprocessor interrupt (and disable it) 537 * 538 * ipi: OpenPIC interprocessor interrupt number 539 * pri: interrupt source priority 540 * vec: the vector it will produce 541 */ 542static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec) 543{ 544 check_arg_ipi(ipi); 545 check_arg_pri(pri); 546 check_arg_vec(vec); 547 openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi), 548 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, 549 (pri << OPENPIC_PRIORITY_SHIFT) | vec); 550} 551 552/* 553 * Send an IPI to one or more CPUs 554 * 555 * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI) 556 * and not a system-wide interrupt number 557 */ 558void openpic_cause_IPI(u_int ipi, cpumask_t cpumask) 559{ 560 DECL_THIS_CPU; 561 562 CHECK_THIS_CPU; 563 check_arg_ipi(ipi); 564 openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), 565 cpus_addr(physmask(cpumask))[0]); 566} 567 568void openpic_request_IPIs(void) 569{ 570 int i; 571 572 /* 573 * Make sure this matches what is defined in smp.c for 574 * smp_message_{pass|recv}() or what shows up in 575 * /proc/interrupts will be wrong!!! --Troy */ 576 577 if (OpenPIC == NULL) 578 return; 579 580 /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ 581 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset, 582 openpic_ipi_action, SA_INTERRUPT, 583 "IPI0 (call function)", NULL); 584 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1, 585 openpic_ipi_action, SA_INTERRUPT, 586 "IPI1 (reschedule)", NULL); 587 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2, 588 openpic_ipi_action, SA_INTERRUPT, 589 "IPI2 (invalidate tlb)", NULL); 590 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3, 591 openpic_ipi_action, SA_INTERRUPT, 592 "IPI3 (xmon break)", NULL); 593 594 for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) 595 openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i); 596} 597 598/* 599 * Do per-cpu setup for SMP systems. 600 * 601 * Get IPI's working and start taking interrupts. 602 * -- Cort 603 */ 604 605void __devinit do_openpic_setup_cpu(void) 606{ 607#ifdef CONFIG_IRQ_ALL_CPUS 608 int i; 609 cpumask_t msk = CPU_MASK_NONE; 610#endif 611 spin_lock(&openpic_setup_lock); 612 613#ifdef CONFIG_IRQ_ALL_CPUS 614 cpu_set(smp_hw_index[smp_processor_id()], msk); 615 616 /* let the openpic know we want intrs. default affinity 617 * is 0xffffffff until changed via /proc 618 * That's how it's done on x86. If we want it differently, then 619 * we should make sure we also change the default values of irq_affinity 620 * in irq.c. 621 */ 622 for (i = 0; i < NumSources; i++) 623 openpic_mapirq(i, msk, CPU_MASK_ALL); 624#endif /* CONFIG_IRQ_ALL_CPUS */ 625 openpic_set_priority(0); 626 627 spin_unlock(&openpic_setup_lock); 628} 629#endif /* CONFIG_SMP */ 630 631/* 632 * Initialize a timer interrupt (and disable it) 633 * 634 * timer: OpenPIC timer number 635 * pri: interrupt source priority 636 * vec: the vector it will produce 637 */ 638static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec) 639{ 640 check_arg_timer(timer); 641 check_arg_pri(pri); 642 check_arg_vec(vec); 643 openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority, 644 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, 645 (pri << OPENPIC_PRIORITY_SHIFT) | vec); 646} 647 648/* 649 * Map a timer interrupt to one or more CPUs 650 */ 651static void __init openpic_maptimer(u_int timer, cpumask_t cpumask) 652{ 653 cpumask_t phys = physmask(cpumask); 654 check_arg_timer(timer); 655 openpic_write(&OpenPIC->Global.Timer[timer].Destination, 656 cpus_addr(phys)[0]); 657} 658 659/* 660 * Change the priority of an interrupt 661 */ 662void __init 663openpic_set_irq_priority(u_int irq, u_int pri) 664{ 665 check_arg_irq(irq); 666 openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority, 667 OPENPIC_PRIORITY_MASK, 668 pri << OPENPIC_PRIORITY_SHIFT); 669} 670 671/* 672 * Initalize the interrupt source which will generate an NMI. 673 * This raises the interrupt's priority from 8 to 9. 674 * 675 * irq: The logical IRQ which generates an NMI. 676 */ 677void __init 678openpic_init_nmi_irq(u_int irq) 679{ 680 check_arg_irq(irq); 681 openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI); 682} 683 684/* 685 * 686 * All functions below take an offset'ed irq argument 687 * 688 */ 689 690/* 691 * Hookup a cascade to the OpenPIC. 692 */ 693 694static struct irqaction openpic_cascade_irqaction = { 695 .handler = no_action, 696 .flags = SA_INTERRUPT, 697 .mask = CPU_MASK_NONE, 698}; 699 700void __init 701openpic_hookup_cascade(u_int irq, char *name, 702 int (*cascade_fn)(struct pt_regs *)) 703{ 704 openpic_cascade_irq = irq; 705 openpic_cascade_fn = cascade_fn; 706 707 if (setup_irq(irq, &openpic_cascade_irqaction)) 708 printk("Unable to get OpenPIC IRQ %d for cascade\n", 709 irq - open_pic_irq_offset); 710} 711 712/* 713 * Enable/disable an external interrupt source 714 * 715 * Externally called, irq is an offseted system-wide interrupt number 716 */ 717static void openpic_enable_irq(u_int irq) 718{ 719 volatile u_int __iomem *vpp; 720 721 check_arg_irq(irq); 722 vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; 723 openpic_clearfield(vpp, OPENPIC_MASK); 724 /* make sure mask gets to controller before we return to user */ 725 do { 726 mb(); /* sync is probably useless here */ 727 } while (openpic_readfield(vpp, OPENPIC_MASK)); 728} 729 730static void openpic_disable_irq(u_int irq) 731{ 732 volatile u_int __iomem *vpp; 733 u32 vp; 734 735 check_arg_irq(irq); 736 vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority; 737 openpic_setfield(vpp, OPENPIC_MASK); 738 /* make sure mask gets to controller before we return to user */ 739 do { 740 mb(); /* sync is probably useless here */ 741 vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY); 742 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); 743} 744 745#ifdef CONFIG_SMP 746/* 747 * Enable/disable an IPI interrupt source 748 * 749 * Externally called, irq is an offseted system-wide interrupt number 750 */ 751void openpic_enable_ipi(u_int irq) 752{ 753 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset); 754 check_arg_ipi(irq); 755 openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); 756 757} 758 759void openpic_disable_ipi(u_int irq) 760{ 761 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset); 762 check_arg_ipi(irq); 763 openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); 764} 765#endif 766 767/* 768 * Initialize an interrupt source (and disable it!) 769 * 770 * irq: OpenPIC interrupt number 771 * pri: interrupt source priority 772 * vec: the vector it will produce 773 * pol: polarity (1 for positive, 0 for negative) 774 * sense: 1 for level, 0 for edge 775 */ 776static void __init 777openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) 778{ 779 openpic_safe_writefield(&ISR[irq]->Vector_Priority, 780 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | 781 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, 782 (pri << OPENPIC_PRIORITY_SHIFT) | vec | 783 (pol ? OPENPIC_POLARITY_POSITIVE : 784 OPENPIC_POLARITY_NEGATIVE) | 785 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); 786} 787 788/* 789 * Map an interrupt source to one or more CPUs 790 */ 791static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask) 792{ 793 if (ISR[irq] == 0) 794 return; 795 if (!cpus_empty(keepmask)) { 796 cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) }; 797 cpus_and(irqdest, irqdest, keepmask); 798 cpus_or(physmask, physmask, irqdest); 799 } 800 openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]); 801} 802 803#ifdef notused 804/* 805 * Set the sense for an interrupt source (and disable it!) 806 * 807 * sense: 1 for level, 0 for edge 808 */ 809static void openpic_set_sense(u_int irq, int sense) 810{ 811 if (ISR[irq] != 0) 812 openpic_safe_writefield(&ISR[irq]->Vector_Priority, 813 OPENPIC_SENSE_LEVEL, 814 (sense ? OPENPIC_SENSE_LEVEL : 0)); 815} 816#endif /* notused */ 817 818/* No spinlocks, should not be necessary with the OpenPIC 819 * (1 register = 1 interrupt and we have the desc lock). 820 */ 821static void openpic_ack_irq(unsigned int irq_nr) 822{ 823#ifdef __SLOW_VERSION__ 824 openpic_disable_irq(irq_nr); 825 openpic_eoi(); 826#else 827 if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) 828 openpic_eoi(); 829#endif 830} 831 832static void openpic_end_irq(unsigned int irq_nr) 833{ 834#ifdef __SLOW_VERSION__ 835 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 836 && irq_desc[irq_nr].action) 837 openpic_enable_irq(irq_nr); 838#else 839 if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0) 840 openpic_eoi(); 841#endif 842} 843 844static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask) 845{ 846 openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE); 847} 848 849#ifdef CONFIG_SMP 850static void openpic_ack_ipi(unsigned int irq_nr) 851{ 852 openpic_eoi(); 853} 854 855static void openpic_end_ipi(unsigned int irq_nr) 856{ 857} 858 859static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) 860{ 861 smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs); 862 return IRQ_HANDLED; 863} 864 865#endif /* CONFIG_SMP */ 866 867int 868openpic_get_irq(struct pt_regs *regs) 869{ 870 int irq = openpic_irq(); 871 872 /* 873 * Check for the cascade interrupt and call the cascaded 874 * interrupt controller function (usually i8259_irq) if so. 875 * This should move to irq.c eventually. -- paulus 876 */ 877 if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) { 878 int cirq = openpic_cascade_fn(regs); 879 880 /* Allow for the cascade being shared with other devices */ 881 if (cirq != -1) { 882 irq = cirq; 883 openpic_eoi(); 884 } 885 } else if (irq == OPENPIC_VEC_SPURIOUS) 886 irq = -1; 887 return irq; 888} 889 890#ifdef CONFIG_SMP 891void 892smp_openpic_message_pass(int target, int msg, unsigned long data, int wait) 893{ 894 cpumask_t mask = CPU_MASK_ALL; 895 /* make sure we're sending something that translates to an IPI */ 896 if (msg > 0x3) { 897 printk("SMP %d: smp_message_pass: unknown msg %d\n", 898 smp_processor_id(), msg); 899 return; 900 } 901 switch (target) { 902 case MSG_ALL: 903 openpic_cause_IPI(msg, mask); 904 break; 905 case MSG_ALL_BUT_SELF: 906 cpu_clear(smp_processor_id(), mask); 907 openpic_cause_IPI(msg, mask); 908 break; 909 default: 910 openpic_cause_IPI(msg, cpumask_of_cpu(target)); 911 break; 912 } 913} 914#endif /* CONFIG_SMP */ 915 916#ifdef CONFIG_PM 917 918/* 919 * We implement the IRQ controller as a sysdev and put it 920 * to sleep at powerdown stage (the callback is named suspend, 921 * but it's old semantics, for the Device Model, it's really 922 * powerdown). The possible problem is that another sysdev that 923 * happens to be suspend after this one will have interrupts off, 924 * that may be an issue... For now, this isn't an issue on pmac 925 * though... 926 */ 927 928static u32 save_ipi_vp[OPENPIC_NUM_IPI]; 929static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES]; 930static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; 931static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; 932static int openpic_suspend_count; 933 934static void openpic_cached_enable_irq(u_int irq) 935{ 936 check_arg_irq(irq); 937 save_irq_src_vp[irq - open_pic_irq_offset] &= ~OPENPIC_MASK; 938} 939 940static void openpic_cached_disable_irq(u_int irq) 941{ 942 check_arg_irq(irq); 943 save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK; 944} 945 946/* WARNING: Can be called directly by the cpufreq code with NULL parameter, 947 * we need something better to deal with that... Maybe switch to S1 for 948 * cpufreq changes 949 */ 950int openpic_suspend(struct sys_device *sysdev, pm_message_t state) 951{ 952 int i; 953 unsigned long flags; 954 955 spin_lock_irqsave(&openpic_setup_lock, flags); 956 957 if (openpic_suspend_count++ > 0) { 958 spin_unlock_irqrestore(&openpic_setup_lock, flags); 959 return 0; 960 } 961 962 openpic_set_priority(0xf); 963 964 open_pic.enable = openpic_cached_enable_irq; 965 open_pic.disable = openpic_cached_disable_irq; 966 967 for (i=0; i<NumProcessors; i++) { 968 save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority); 969 openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority, 970 OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf); 971 } 972 973 for (i=0; i<OPENPIC_NUM_IPI; i++) 974 save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i)); 975 for (i=0; i<NumSources; i++) { 976 if (ISR[i] == 0) 977 continue; 978 save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY; 979 save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination); 980 } 981 982 spin_unlock_irqrestore(&openpic_setup_lock, flags); 983 984 return 0; 985} 986 987/* WARNING: Can be called directly by the cpufreq code with NULL parameter, 988 * we need something better to deal with that... Maybe switch to S1 for 989 * cpufreq changes 990 */ 991int openpic_resume(struct sys_device *sysdev) 992{ 993 int i; 994 unsigned long flags; 995 u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | 996 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK | 997 OPENPIC_MASK; 998 999 spin_lock_irqsave(&openpic_setup_lock, flags); 1000 1001 if ((--openpic_suspend_count) > 0) { 1002 spin_unlock_irqrestore(&openpic_setup_lock, flags); 1003 return 0; 1004 } 1005 1006 /* OpenPIC sometimes seem to need some time to be fully back up... */ 1007 do { 1008 openpic_set_spurious(OPENPIC_VEC_SPURIOUS); 1009 } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK) 1010 != OPENPIC_VEC_SPURIOUS); 1011 1012 openpic_disable_8259_pass_through(); 1013 1014 for (i=0; i<OPENPIC_NUM_IPI; i++) 1015 openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), 1016 save_ipi_vp[i]); 1017 for (i=0; i<NumSources; i++) { 1018 if (ISR[i] == 0) 1019 continue; 1020 openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]); 1021 openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); 1022 /* make sure mask gets to controller before we return to user */ 1023 do { 1024 openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); 1025 } while (openpic_readfield(&ISR[i]->Vector_Priority, vppmask) 1026 != (save_irq_src_vp[i] & vppmask)); 1027 } 1028 for (i=0; i<NumProcessors; i++) 1029 openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, 1030 save_cpu_task_pri[i]); 1031 1032 open_pic.enable = openpic_enable_irq; 1033 open_pic.disable = openpic_disable_irq; 1034 1035 openpic_set_priority(0); 1036 1037 spin_unlock_irqrestore(&openpic_setup_lock, flags); 1038 1039 return 0; 1040} 1041 1042#endif /* CONFIG_PM */ 1043 1044static struct sysdev_class openpic_sysclass = { 1045 set_kset_name("openpic"), 1046}; 1047 1048static struct sys_device device_openpic = { 1049 .id = 0, 1050 .cls = &openpic_sysclass, 1051}; 1052 1053static struct sysdev_driver driver_openpic = { 1054#ifdef CONFIG_PM 1055 .suspend = &openpic_suspend, 1056 .resume = &openpic_resume, 1057#endif /* CONFIG_PM */ 1058}; 1059 1060static int __init init_openpic_sysfs(void) 1061{ 1062 int rc; 1063 1064 if (!OpenPIC_Addr) 1065 return -ENODEV; 1066 printk(KERN_DEBUG "Registering openpic with sysfs...\n"); 1067 rc = sysdev_class_register(&openpic_sysclass); 1068 if (rc) { 1069 printk(KERN_ERR "Failed registering openpic sys class\n"); 1070 return -ENODEV; 1071 } 1072 rc = sysdev_register(&device_openpic); 1073 if (rc) { 1074 printk(KERN_ERR "Failed registering openpic sys device\n"); 1075 return -ENODEV; 1076 } 1077 rc = sysdev_driver_register(&openpic_sysclass, &driver_openpic); 1078 if (rc) { 1079 printk(KERN_ERR "Failed registering openpic sys driver\n"); 1080 return -ENODEV; 1081 } 1082 return 0; 1083} 1084 1085subsys_initcall(init_openpic_sysfs); 1086