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.15 177 lines 4.3 kB view raw
1/* The CPM2 internal interrupt controller. It is usually 2 * the only interrupt controller. 3 * There are two 32-bit registers (high/low) for up to 64 4 * possible interrupts. 5 * 6 * Now, the fun starts.....Interrupt Numbers DO NOT MAP 7 * in a simple arithmetic fashion to mask or pending registers. 8 * That is, interrupt 4 does not map to bit position 4. 9 * We create two tables, indexed by vector number, to indicate 10 * which register to use and which bit in the register to use. 11 */ 12 13#include <linux/stddef.h> 14#include <linux/init.h> 15#include <linux/sched.h> 16#include <linux/signal.h> 17#include <linux/irq.h> 18 19#include <asm/immap_cpm2.h> 20#include <asm/mpc8260.h> 21 22#include "cpm2_pic.h" 23 24static u_char irq_to_siureg[] = { 25 1, 1, 1, 1, 1, 1, 1, 1, 26 1, 1, 1, 1, 1, 1, 1, 1, 27 0, 0, 0, 0, 0, 0, 0, 0, 28 0, 0, 0, 0, 0, 0, 0, 0, 29 1, 1, 1, 1, 1, 1, 1, 1, 30 1, 1, 1, 1, 1, 1, 1, 1, 31 0, 0, 0, 0, 0, 0, 0, 0, 32 0, 0, 0, 0, 0, 0, 0, 0 33}; 34 35/* bit numbers do not match the docs, these are precomputed so the bit for 36 * a given irq is (1 << irq_to_siubit[irq]) */ 37static u_char irq_to_siubit[] = { 38 0, 15, 14, 13, 12, 11, 10, 9, 39 8, 7, 6, 5, 4, 3, 2, 1, 40 2, 1, 0, 14, 13, 12, 11, 10, 41 9, 8, 7, 6, 5, 4, 3, 0, 42 31, 30, 29, 28, 27, 26, 25, 24, 43 23, 22, 21, 20, 19, 18, 17, 16, 44 16, 17, 18, 19, 20, 21, 22, 23, 45 24, 25, 26, 27, 28, 29, 30, 31, 46}; 47 48static void cpm2_mask_irq(unsigned int irq_nr) 49{ 50 int bit, word; 51 volatile uint *simr; 52 53 irq_nr -= CPM_IRQ_OFFSET; 54 55 bit = irq_to_siubit[irq_nr]; 56 word = irq_to_siureg[irq_nr]; 57 58 simr = &(cpm2_immr->im_intctl.ic_simrh); 59 ppc_cached_irq_mask[word] &= ~(1 << bit); 60 simr[word] = ppc_cached_irq_mask[word]; 61} 62 63static void cpm2_unmask_irq(unsigned int irq_nr) 64{ 65 int bit, word; 66 volatile uint *simr; 67 68 irq_nr -= CPM_IRQ_OFFSET; 69 70 bit = irq_to_siubit[irq_nr]; 71 word = irq_to_siureg[irq_nr]; 72 73 simr = &(cpm2_immr->im_intctl.ic_simrh); 74 ppc_cached_irq_mask[word] |= 1 << bit; 75 simr[word] = ppc_cached_irq_mask[word]; 76} 77 78static void cpm2_mask_and_ack(unsigned int irq_nr) 79{ 80 int bit, word; 81 volatile uint *simr, *sipnr; 82 83 irq_nr -= CPM_IRQ_OFFSET; 84 85 bit = irq_to_siubit[irq_nr]; 86 word = irq_to_siureg[irq_nr]; 87 88 simr = &(cpm2_immr->im_intctl.ic_simrh); 89 sipnr = &(cpm2_immr->im_intctl.ic_sipnrh); 90 ppc_cached_irq_mask[word] &= ~(1 << bit); 91 simr[word] = ppc_cached_irq_mask[word]; 92 sipnr[word] = 1 << bit; 93} 94 95static void cpm2_end_irq(unsigned int irq_nr) 96{ 97 int bit, word; 98 volatile uint *simr; 99 100 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 101 && irq_desc[irq_nr].action) { 102 103 irq_nr -= CPM_IRQ_OFFSET; 104 bit = irq_to_siubit[irq_nr]; 105 word = irq_to_siureg[irq_nr]; 106 107 simr = &(cpm2_immr->im_intctl.ic_simrh); 108 ppc_cached_irq_mask[word] |= 1 << bit; 109 simr[word] = ppc_cached_irq_mask[word]; 110 /* 111 * Work around large numbers of spurious IRQs on PowerPC 82xx 112 * systems. 113 */ 114 mb(); 115 } 116} 117 118static struct hw_interrupt_type cpm2_pic = { 119 .typename = " CPM2 SIU ", 120 .enable = cpm2_unmask_irq, 121 .disable = cpm2_mask_irq, 122 .ack = cpm2_mask_and_ack, 123 .end = cpm2_end_irq, 124}; 125 126int cpm2_get_irq(struct pt_regs *regs) 127{ 128 int irq; 129 unsigned long bits; 130 131 /* For CPM2, read the SIVEC register and shift the bits down 132 * to get the irq number. */ 133 bits = cpm2_immr->im_intctl.ic_sivec; 134 irq = bits >> 26; 135 136 if (irq == 0) 137 return(-1); 138 return irq+CPM_IRQ_OFFSET; 139} 140 141void cpm2_init_IRQ(void) 142{ 143 int i; 144 145 /* Clear the CPM IRQ controller, in case it has any bits set 146 * from the bootloader 147 */ 148 149 /* Mask out everything */ 150 cpm2_immr->im_intctl.ic_simrh = 0x00000000; 151 cpm2_immr->im_intctl.ic_simrl = 0x00000000; 152 wmb(); 153 154 /* Ack everything */ 155 cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff; 156 cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff; 157 wmb(); 158 159 /* Dummy read of the vector */ 160 i = cpm2_immr->im_intctl.ic_sivec; 161 rmb(); 162 163 /* Initialize the default interrupt mapping priorities, 164 * in case the boot rom changed something on us. 165 */ 166 cpm2_immr->im_intctl.ic_sicr = 0; 167 cpm2_immr->im_intctl.ic_scprrh = 0x05309770; 168 cpm2_immr->im_intctl.ic_scprrl = 0x05309770; 169 170 171 /* Enable chaining to OpenPIC, and make everything level 172 */ 173 for (i = 0; i < NR_CPM_INTS; i++) { 174 irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic; 175 irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL; 176 } 177}