1/* 2 * Copyright (C) 1997 Geert Uytterhoeven 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file COPYING in the main directory of this archive 6 * for more details. 7 * 8 * This is a duplicate of open_pic.c that deals with U3s MPIC on 9 * G5 PowerMacs. It's the same file except it's using big endian 10 * register accesses 11 */ 12 13#include <linux/types.h> 14#include <linux/kernel.h> 15#include <linux/sched.h> 16#include <linux/init.h> 17#include <linux/interrupt.h> 18#include <linux/sysdev.h> 19#include <linux/errno.h> 20#include <asm/ptrace.h> 21#include <asm/signal.h> 22#include <asm/io.h> 23#include <asm/irq.h> 24#include <asm/sections.h> 25#include <asm/open_pic.h> 26#include <asm/i8259.h> 27#include <asm/machdep.h> 28 29#include "open_pic_defs.h" 30 31void *OpenPIC2_Addr; 32static volatile struct OpenPIC *OpenPIC2 = NULL; 33/* 34 * We define OpenPIC_InitSenses table thusly: 35 * bit 0x1: sense, 0 for edge and 1 for level. 36 * bit 0x2: polarity, 0 for negative, 1 for positive. 37 */ 38extern u_int OpenPIC_NumInitSenses; 39extern u_char *OpenPIC_InitSenses; 40extern int use_of_interrupt_tree; 41 42static u_int NumProcessors; 43static u_int NumSources; 44static int open_pic2_irq_offset; 45static volatile OpenPIC_Source *ISR[NR_IRQS]; 46 47/* Global Operations */ 48static void openpic2_disable_8259_pass_through(void); 49static void openpic2_set_priority(u_int pri); 50static void openpic2_set_spurious(u_int vector); 51 52/* Timer Interrupts */ 53static void openpic2_inittimer(u_int timer, u_int pri, u_int vector); 54static void openpic2_maptimer(u_int timer, u_int cpumask); 55 56/* Interrupt Sources */ 57static void openpic2_enable_irq(u_int irq); 58static void openpic2_disable_irq(u_int irq); 59static void openpic2_initirq(u_int irq, u_int pri, u_int vector, int polarity, 60 int is_level); 61static void openpic2_mapirq(u_int irq, u_int cpumask, u_int keepmask); 62 63/* 64 * These functions are not used but the code is kept here 65 * for completeness and future reference. 66 */ 67static void openpic2_reset(void); 68#ifdef notused 69static void openpic2_enable_8259_pass_through(void); 70static u_int openpic2_get_priority(void); 71static u_int openpic2_get_spurious(void); 72static void openpic2_set_sense(u_int irq, int sense); 73#endif /* notused */ 74 75/* 76 * Description of the openpic for the higher-level irq code 77 */ 78static void openpic2_end_irq(unsigned int irq_nr); 79static void openpic2_ack_irq(unsigned int irq_nr); 80 81struct hw_interrupt_type open_pic2 = { 82 .typename = " OpenPIC2 ", 83 .enable = openpic2_enable_irq, 84 .disable = openpic2_disable_irq, 85 .ack = openpic2_ack_irq, 86 .end = openpic2_end_irq, 87}; 88 89/* 90 * Accesses to the current processor's openpic registers 91 * On cascaded controller, this is only CPU 0 92 */ 93#define THIS_CPU Processor[0] 94#define DECL_THIS_CPU 95#define CHECK_THIS_CPU 96 97#define check_arg_ipi(ipi) \ 98 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \ 99 printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi); 100#define check_arg_timer(timer) \ 101 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \ 102 printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer); 103#define check_arg_vec(vec) \ 104 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \ 105 printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec); 106#define check_arg_pri(pri) \ 107 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \ 108 printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri); 109/* 110 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's 111 * data has probably been corrupted and we're going to panic or deadlock later 112 * anyway --Troy 113 */ 114extern unsigned long* _get_SP(void); 115#define check_arg_irq(irq) \ 116 if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \ 117 || ISR[irq - open_pic2_irq_offset] == 0) { \ 118 printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \ 119 /*print_backtrace(_get_SP());*/ } 120#define check_arg_cpu(cpu) \ 121 if (cpu < 0 || cpu >= NumProcessors){ \ 122 printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \ 123 /*print_backtrace(_get_SP());*/ } 124 125static u_int openpic2_read(volatile u_int *addr) 126{ 127 u_int val; 128 129 val = in_be32(addr); 130 return val; 131} 132 133static inline void openpic2_write(volatile u_int *addr, u_int val) 134{ 135 out_be32(addr, val); 136} 137 138static inline u_int openpic2_readfield(volatile u_int *addr, u_int mask) 139{ 140 u_int val = openpic2_read(addr); 141 return val & mask; 142} 143 144inline void openpic2_writefield(volatile u_int *addr, u_int mask, 145 u_int field) 146{ 147 u_int val = openpic2_read(addr); 148 openpic2_write(addr, (val & ~mask) | (field & mask)); 149} 150 151static inline void openpic2_clearfield(volatile u_int *addr, u_int mask) 152{ 153 openpic2_writefield(addr, mask, 0); 154} 155 156static inline void openpic2_setfield(volatile u_int *addr, u_int mask) 157{ 158 openpic2_writefield(addr, mask, mask); 159} 160 161static void openpic2_safe_writefield(volatile u_int *addr, u_int mask, 162 u_int field) 163{ 164 openpic2_setfield(addr, OPENPIC_MASK); 165 while (openpic2_read(addr) & OPENPIC_ACTIVITY); 166 openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); 167} 168 169static void openpic2_reset(void) 170{ 171 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0, 172 OPENPIC_CONFIG_RESET); 173 while (openpic2_readfield(&OpenPIC2->Global.Global_Configuration0, 174 OPENPIC_CONFIG_RESET)) 175 mb(); 176} 177 178void __init openpic2_set_sources(int first_irq, int num_irqs, void *first_ISR) 179{ 180 volatile OpenPIC_Source *src = first_ISR; 181 int i, last_irq; 182 183 last_irq = first_irq + num_irqs; 184 if (last_irq > NumSources) 185 NumSources = last_irq; 186 if (src == 0) 187 src = &((struct OpenPIC *)OpenPIC2_Addr)->Source[first_irq]; 188 for (i = first_irq; i < last_irq; ++i, ++src) 189 ISR[i] = src; 190} 191 192/* 193 * The `offset' parameter defines where the interrupts handled by the 194 * OpenPIC start in the space of interrupt numbers that the kernel knows 195 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the 196 * kernel's interrupt numbering scheme. 197 * We assume there is only one OpenPIC. 198 */ 199void __init openpic2_init(int offset) 200{ 201 u_int t, i; 202 u_int timerfreq; 203 const char *version; 204 205 if (!OpenPIC2_Addr) { 206 printk("No OpenPIC2 found !\n"); 207 return; 208 } 209 OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr; 210 211 if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122); 212 213 t = openpic2_read(&OpenPIC2->Global.Feature_Reporting0); 214 switch (t & OPENPIC_FEATURE_VERSION_MASK) { 215 case 1: 216 version = "1.0"; 217 break; 218 case 2: 219 version = "1.2"; 220 break; 221 case 3: 222 version = "1.3"; 223 break; 224 default: 225 version = "?"; 226 break; 227 } 228 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> 229 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; 230 if (NumSources == 0) 231 openpic2_set_sources(0, 232 ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> 233 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1, 234 NULL); 235 printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n", 236 version, NumProcessors, NumSources, OpenPIC2); 237 timerfreq = openpic2_read(&OpenPIC2->Global.Timer_Frequency); 238 if (timerfreq) 239 printk("OpenPIC timer frequency is %d.%06d MHz\n", 240 timerfreq / 1000000, timerfreq % 1000000); 241 242 open_pic2_irq_offset = offset; 243 244 /* Initialize timer interrupts */ 245 if ( ppc_md.progress ) ppc_md.progress("openpic2: timer",0x3ba); 246 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { 247 /* Disabled, Priority 0 */ 248 openpic2_inittimer(i, 0, OPENPIC2_VEC_TIMER+i+offset); 249 /* No processor */ 250 openpic2_maptimer(i, 0); 251 } 252 253 /* Initialize external interrupts */ 254 if (ppc_md.progress) ppc_md.progress("openpic2: external",0x3bc); 255 256 openpic2_set_priority(0xf); 257 258 /* Init all external sources, including possibly the cascade. */ 259 for (i = 0; i < NumSources; i++) { 260 int sense; 261 262 if (ISR[i] == 0) 263 continue; 264 265 /* the bootloader may have left it enabled (bad !) */ 266 openpic2_disable_irq(i+offset); 267 268 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \ 269 (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE); 270 271 if (sense & IRQ_SENSE_MASK) 272 irq_desc[i+offset].status = IRQ_LEVEL; 273 274 /* Enabled, Priority 8 */ 275 openpic2_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK), 276 (sense & IRQ_SENSE_MASK)); 277 /* Processor 0 */ 278 openpic2_mapirq(i, 1<<0, 0); 279 } 280 281 /* Init descriptors */ 282 for (i = offset; i < NumSources + offset; i++) 283 irq_desc[i].chip = &open_pic2; 284 285 /* Initialize the spurious interrupt */ 286 if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd); 287 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+offset); 288 289 openpic2_disable_8259_pass_through(); 290 openpic2_set_priority(0); 291 292 if (ppc_md.progress) ppc_md.progress("openpic2: exit",0x222); 293} 294 295#ifdef notused 296static void openpic2_enable_8259_pass_through(void) 297{ 298 openpic2_clearfield(&OpenPIC2->Global.Global_Configuration0, 299 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); 300} 301#endif /* notused */ 302 303/* This can't be __init, it is used in openpic_sleep_restore_intrs */ 304static void openpic2_disable_8259_pass_through(void) 305{ 306 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0, 307 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); 308} 309 310/* 311 * Find out the current interrupt 312 */ 313u_int openpic2_irq(void) 314{ 315 u_int vec; 316 DECL_THIS_CPU; 317 318 CHECK_THIS_CPU; 319 vec = openpic2_readfield(&OpenPIC2->THIS_CPU.Interrupt_Acknowledge, 320 OPENPIC_VECTOR_MASK); 321 return vec; 322} 323 324void openpic2_eoi(void) 325{ 326 DECL_THIS_CPU; 327 328 CHECK_THIS_CPU; 329 openpic2_write(&OpenPIC2->THIS_CPU.EOI, 0); 330 /* Handle PCI write posting */ 331 (void)openpic2_read(&OpenPIC2->THIS_CPU.EOI); 332} 333 334#ifdef notused 335static u_int openpic2_get_priority(void) 336{ 337 DECL_THIS_CPU; 338 339 CHECK_THIS_CPU; 340 return openpic2_readfield(&OpenPIC2->THIS_CPU.Current_Task_Priority, 341 OPENPIC_CURRENT_TASK_PRIORITY_MASK); 342} 343#endif /* notused */ 344 345static void __init openpic2_set_priority(u_int pri) 346{ 347 DECL_THIS_CPU; 348 349 CHECK_THIS_CPU; 350 check_arg_pri(pri); 351 openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority, 352 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri); 353} 354 355/* 356 * Get/set the spurious vector 357 */ 358#ifdef notused 359static u_int openpic2_get_spurious(void) 360{ 361 return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector, 362 OPENPIC_VECTOR_MASK); 363} 364#endif /* notused */ 365 366/* This can't be __init, it is used in openpic_sleep_restore_intrs */ 367static void openpic2_set_spurious(u_int vec) 368{ 369 check_arg_vec(vec); 370 openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK, 371 vec); 372} 373 374static DEFINE_SPINLOCK(openpic2_setup_lock); 375 376/* 377 * Initialize a timer interrupt (and disable it) 378 * 379 * timer: OpenPIC timer number 380 * pri: interrupt source priority 381 * vec: the vector it will produce 382 */ 383static void __init openpic2_inittimer(u_int timer, u_int pri, u_int vec) 384{ 385 check_arg_timer(timer); 386 check_arg_pri(pri); 387 check_arg_vec(vec); 388 openpic2_safe_writefield(&OpenPIC2->Global.Timer[timer].Vector_Priority, 389 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK, 390 (pri << OPENPIC_PRIORITY_SHIFT) | vec); 391} 392 393/* 394 * Map a timer interrupt to one or more CPUs 395 */ 396static void __init openpic2_maptimer(u_int timer, u_int cpumask) 397{ 398 check_arg_timer(timer); 399 openpic2_write(&OpenPIC2->Global.Timer[timer].Destination, 400 cpumask); 401} 402 403/* 404 * Initalize the interrupt source which will generate an NMI. 405 * This raises the interrupt's priority from 8 to 9. 406 * 407 * irq: The logical IRQ which generates an NMI. 408 */ 409void __init 410openpic2_init_nmi_irq(u_int irq) 411{ 412 check_arg_irq(irq); 413 openpic2_safe_writefield(&ISR[irq - open_pic2_irq_offset]->Vector_Priority, 414 OPENPIC_PRIORITY_MASK, 415 9 << OPENPIC_PRIORITY_SHIFT); 416} 417 418/* 419 * 420 * All functions below take an offset'ed irq argument 421 * 422 */ 423 424 425/* 426 * Enable/disable an external interrupt source 427 * 428 * Externally called, irq is an offseted system-wide interrupt number 429 */ 430static void openpic2_enable_irq(u_int irq) 431{ 432 volatile u_int *vpp; 433 434 check_arg_irq(irq); 435 vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority; 436 openpic2_clearfield(vpp, OPENPIC_MASK); 437 /* make sure mask gets to controller before we return to user */ 438 do { 439 mb(); /* sync is probably useless here */ 440 } while (openpic2_readfield(vpp, OPENPIC_MASK)); 441} 442 443static void openpic2_disable_irq(u_int irq) 444{ 445 volatile u_int *vpp; 446 u32 vp; 447 448 check_arg_irq(irq); 449 vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority; 450 openpic2_setfield(vpp, OPENPIC_MASK); 451 /* make sure mask gets to controller before we return to user */ 452 do { 453 mb(); /* sync is probably useless here */ 454 vp = openpic2_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY); 455 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); 456} 457 458 459/* 460 * Initialize an interrupt source (and disable it!) 461 * 462 * irq: OpenPIC interrupt number 463 * pri: interrupt source priority 464 * vec: the vector it will produce 465 * pol: polarity (1 for positive, 0 for negative) 466 * sense: 1 for level, 0 for edge 467 */ 468static void __init 469openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) 470{ 471 openpic2_safe_writefield(&ISR[irq]->Vector_Priority, 472 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | 473 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, 474 (pri << OPENPIC_PRIORITY_SHIFT) | vec | 475 (pol ? OPENPIC_POLARITY_POSITIVE : 476 OPENPIC_POLARITY_NEGATIVE) | 477 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); 478} 479 480/* 481 * Map an interrupt source to one or more CPUs 482 */ 483static void openpic2_mapirq(u_int irq, u_int physmask, u_int keepmask) 484{ 485 if (ISR[irq] == 0) 486 return; 487 if (keepmask != 0) 488 physmask |= openpic2_read(&ISR[irq]->Destination) & keepmask; 489 openpic2_write(&ISR[irq]->Destination, physmask); 490} 491 492#ifdef notused 493/* 494 * Set the sense for an interrupt source (and disable it!) 495 * 496 * sense: 1 for level, 0 for edge 497 */ 498static void openpic2_set_sense(u_int irq, int sense) 499{ 500 if (ISR[irq] != 0) 501 openpic2_safe_writefield(&ISR[irq]->Vector_Priority, 502 OPENPIC_SENSE_LEVEL, 503 (sense ? OPENPIC_SENSE_LEVEL : 0)); 504} 505#endif /* notused */ 506 507/* No spinlocks, should not be necessary with the OpenPIC 508 * (1 register = 1 interrupt and we have the desc lock). 509 */ 510static void openpic2_ack_irq(unsigned int irq_nr) 511{ 512 openpic2_disable_irq(irq_nr); 513 openpic2_eoi(); 514} 515 516static void openpic2_end_irq(unsigned int irq_nr) 517{ 518 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 519 openpic2_enable_irq(irq_nr); 520} 521 522int 523openpic2_get_irq(void) 524{ 525 int irq = openpic2_irq(); 526 527 if (irq == (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset)) 528 irq = -1; 529 return irq; 530} 531 532#ifdef CONFIG_PM 533 534/* 535 * We implement the IRQ controller as a sysdev and put it 536 * to sleep at powerdown stage (the callback is named suspend, 537 * but it's old semantics, for the Device Model, it's really 538 * powerdown). The possible problem is that another sysdev that 539 * happens to be suspend after this one will have interrupts off, 540 * that may be an issue... For now, this isn't an issue on pmac 541 * though... 542 */ 543 544static u32 save_ipi_vp[OPENPIC_NUM_IPI]; 545static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES]; 546static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; 547static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; 548static int openpic_suspend_count; 549 550static void openpic2_cached_enable_irq(u_int irq) 551{ 552 check_arg_irq(irq); 553 save_irq_src_vp[irq - open_pic2_irq_offset] &= ~OPENPIC_MASK; 554} 555 556static void openpic2_cached_disable_irq(u_int irq) 557{ 558 check_arg_irq(irq); 559 save_irq_src_vp[irq - open_pic2_irq_offset] |= OPENPIC_MASK; 560} 561 562/* WARNING: Can be called directly by the cpufreq code with NULL parameter, 563 * we need something better to deal with that... Maybe switch to S1 for 564 * cpufreq changes 565 */ 566int openpic2_suspend(struct sys_device *sysdev, pm_message_t state) 567{ 568 int i; 569 unsigned long flags; 570 571 spin_lock_irqsave(&openpic2_setup_lock, flags); 572 573 if (openpic_suspend_count++ > 0) { 574 spin_unlock_irqrestore(&openpic2_setup_lock, flags); 575 return 0; 576 } 577 578 open_pic2.enable = openpic2_cached_enable_irq; 579 open_pic2.disable = openpic2_cached_disable_irq; 580 581 for (i=0; i<NumProcessors; i++) { 582 save_cpu_task_pri[i] = openpic2_read(&OpenPIC2->Processor[i].Current_Task_Priority); 583 openpic2_writefield(&OpenPIC2->Processor[i].Current_Task_Priority, 584 OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf); 585 } 586 587 for (i=0; i<OPENPIC_NUM_IPI; i++) 588 save_ipi_vp[i] = openpic2_read(&OpenPIC2->Global.IPI_Vector_Priority(i)); 589 for (i=0; i<NumSources; i++) { 590 if (ISR[i] == 0) 591 continue; 592 save_irq_src_vp[i] = openpic2_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY; 593 save_irq_src_dest[i] = openpic2_read(&ISR[i]->Destination); 594 } 595 596 spin_unlock_irqrestore(&openpic2_setup_lock, flags); 597 598 return 0; 599} 600 601/* WARNING: Can be called directly by the cpufreq code with NULL parameter, 602 * we need something better to deal with that... Maybe switch to S1 for 603 * cpufreq changes 604 */ 605int openpic2_resume(struct sys_device *sysdev) 606{ 607 int i; 608 unsigned long flags; 609 u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | 610 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK | 611 OPENPIC_MASK; 612 613 spin_lock_irqsave(&openpic2_setup_lock, flags); 614 615 if ((--openpic_suspend_count) > 0) { 616 spin_unlock_irqrestore(&openpic2_setup_lock, flags); 617 return 0; 618 } 619 620 openpic2_reset(); 621 622 /* OpenPIC sometimes seem to need some time to be fully back up... */ 623 do { 624 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+open_pic2_irq_offset); 625 } while(openpic2_readfield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK) 626 != (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset)); 627 628 openpic2_disable_8259_pass_through(); 629 630 for (i=0; i<OPENPIC_NUM_IPI; i++) 631 openpic2_write(&OpenPIC2->Global.IPI_Vector_Priority(i), 632 save_ipi_vp[i]); 633 for (i=0; i<NumSources; i++) { 634 if (ISR[i] == 0) 635 continue; 636 openpic2_write(&ISR[i]->Destination, save_irq_src_dest[i]); 637 openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); 638 /* make sure mask gets to controller before we return to user */ 639 do { 640 openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]); 641 } while (openpic2_readfield(&ISR[i]->Vector_Priority, vppmask) 642 != (save_irq_src_vp[i] & vppmask)); 643 } 644 for (i=0; i<NumProcessors; i++) 645 openpic2_write(&OpenPIC2->Processor[i].Current_Task_Priority, 646 save_cpu_task_pri[i]); 647 648 open_pic2.enable = openpic2_enable_irq; 649 open_pic2.disable = openpic2_disable_irq; 650 651 spin_unlock_irqrestore(&openpic2_setup_lock, flags); 652 653 return 0; 654} 655 656#endif /* CONFIG_PM */ 657 658/* HACK ALERT */ 659static struct sysdev_class openpic2_sysclass = { 660 set_kset_name("openpic2"), 661}; 662 663static struct sys_device device_openpic2 = { 664 .id = 0, 665 .cls = &openpic2_sysclass, 666}; 667 668static struct sysdev_driver driver_openpic2 = { 669#ifdef CONFIG_PM 670 .suspend = &openpic2_suspend, 671 .resume = &openpic2_resume, 672#endif /* CONFIG_PM */ 673}; 674 675static int __init init_openpic2_sysfs(void) 676{ 677 int rc; 678 679 if (!OpenPIC2_Addr) 680 return -ENODEV; 681 printk(KERN_DEBUG "Registering openpic2 with sysfs...\n"); 682 rc = sysdev_class_register(&openpic2_sysclass); 683 if (rc) { 684 printk(KERN_ERR "Failed registering openpic sys class\n"); 685 return -ENODEV; 686 } 687 rc = sysdev_register(&device_openpic2); 688 if (rc) { 689 printk(KERN_ERR "Failed registering openpic sys device\n"); 690 return -ENODEV; 691 } 692 rc = sysdev_driver_register(&openpic2_sysclass, &driver_openpic2); 693 if (rc) { 694 printk(KERN_ERR "Failed registering openpic sys driver\n"); 695 return -ENODEV; 696 } 697 return 0; 698} 699 700subsys_initcall(init_openpic2_sysfs); 701