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

[POWERPC] cpm2: CPM2 interrupt controller fix

This contains important fixes for the CPM2 PIC code. Eliminated
CPM_IRQ_OFFSET, pulling the respective interrupt numbers from the interrupt
mapping. Updated devicetree files to reflect that. Changed direct
IC-related IO accesses to the IO accessors. Fixed all the sense values to
keep coherency with ipic. In the current code, CPM2 stuff will have no IRQs
and hence could be hardly usable.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Vitaly Bordug and committed by
Paul Mackerras
73844ecb c19cdcb1

+145 -88
+27 -20
arch/powerpc/boot/dts/mpc8272ads.dts
··· 53 53 reg = <00000000 4000000 f4500000 00000020>; 54 54 }; 55 55 56 + chosen { 57 + name = "chosen"; 58 + linux,platform = <0>; 59 + interrupt-controller = <10c00>; 60 + linux,phandle = <400>; 61 + }; 62 + 56 63 soc8272@f0000000 { 57 64 #address-cells = <1>; 58 65 #size-cells = <1>; ··· 78 71 ethernet-phy@0 { 79 72 linux,phandle = <2452000>; 80 73 interrupt-parent = <10c00>; 81 - interrupts = <19 1>; 74 + interrupts = <17 4>; 82 75 reg = <0>; 83 76 bitbang = [ 12 12 13 02 02 01 ]; 84 77 device_type = "ethernet-phy"; ··· 86 79 ethernet-phy@1 { 87 80 linux,phandle = <2452001>; 88 81 interrupt-parent = <10c00>; 89 - interrupts = <19 1>; 82 + interrupts = <17 4>; 90 83 bitbang = [ 12 12 13 02 02 01 ]; 91 84 reg = <3>; 92 85 device_type = "ethernet-phy"; ··· 97 90 #address-cells = <1>; 98 91 #size-cells = <0>; 99 92 device_type = "network"; 100 - device-id = <2>; 93 + device-id = <1>; 101 94 compatible = "fs_enet"; 102 95 model = "FCC"; 103 96 reg = <11300 20 8400 100 11380 30>; ··· 111 104 112 105 ethernet@25000 { 113 106 device_type = "network"; 114 - device-id = <3>; 107 + device-id = <2>; 115 108 compatible = "fs_enet"; 116 109 model = "FCC"; 117 110 reg = <11320 20 8500 100 113b0 30>; ··· 140 133 device_type = "serial"; 141 134 compatible = "cpm_uart"; 142 135 model = "SCC"; 143 - device-id = <2>; 136 + device-id = <1>; 144 137 reg = <11a00 20 8000 100>; 145 138 current-speed = <1c200>; 146 139 interrupts = <28 2>; ··· 154 147 device_type = "serial"; 155 148 compatible = "cpm_uart"; 156 149 model = "SCC"; 157 - device-id = <5>; 150 + device-id = <4>; 158 151 reg = <11a60 20 8300 100>; 159 152 current-speed = <1c200>; 160 153 interrupts = <2b 2>; ··· 188 181 interrupt-map = < 189 182 190 183 /* IDSEL 0x16 */ 191 - b000 0 0 1 f8200000 40 0 192 - b000 0 0 2 f8200000 41 0 193 - b000 0 0 3 f8200000 42 0 194 - b000 0 0 4 f8200000 43 0 184 + b000 0 0 1 f8200000 40 8 185 + b000 0 0 2 f8200000 41 8 186 + b000 0 0 3 f8200000 42 8 187 + b000 0 0 4 f8200000 43 8 195 188 196 189 /* IDSEL 0x17 */ 197 - b800 0 0 1 f8200000 43 0 198 - b800 0 0 2 f8200000 40 0 199 - b800 0 0 3 f8200000 41 0 200 - b800 0 0 4 f8200000 42 0 190 + b800 0 0 1 f8200000 43 8 191 + b800 0 0 2 f8200000 40 8 192 + b800 0 0 3 f8200000 41 8 193 + b800 0 0 4 f8200000 42 8 201 194 202 195 /* IDSEL 0x18 */ 203 - c000 0 0 1 f8200000 42 0 204 - c000 0 0 2 f8200000 43 0 205 - c000 0 0 3 f8200000 40 0 206 - c000 0 0 4 f8200000 41 0>; 196 + c000 0 0 1 f8200000 42 8 197 + c000 0 0 2 f8200000 43 8 198 + c000 0 0 3 f8200000 40 8 199 + c000 0 0 4 f8200000 41 8>; 207 200 interrupt-parent = <10c00>; 208 - interrupts = <14 3>; 201 + interrupts = <14 8>; 209 202 bus-range = <0 0>; 210 203 ranges = <02000000 0 80000000 80000000 0 40000000 211 204 01000000 0 00000000 f6000000 0 02000000>; ··· 217 210 model = "SEC2"; 218 211 compatible = "talitos"; 219 212 reg = <30000 10000>; 220 - interrupts = <b 0>; 213 + interrupts = <b 2>; 221 214 interrupt-parent = <10c00>; 222 215 num-channels = <4>; 223 216 channel-fifo-len = <18>;
+5 -5
arch/powerpc/boot/dts/mpc8560ads.dts
··· 200 200 a800 0 0 4 40000 31 1>; 201 201 202 202 interrupt-parent = <40000>; 203 - interrupts = <42 0>; 203 + interrupts = <8 0>; 204 204 bus-range = <0 0>; 205 205 ranges = <02000000 0 80000000 80000000 0 20000000 206 206 01000000 0 00000000 e2000000 0 01000000>; ··· 250 250 rx-clock = <1>; 251 251 tx-clock = <1>; 252 252 current-speed = <1c200>; 253 - interrupts = <64 1>; 253 + interrupts = <28 8>; 254 254 interrupt-parent = <90c00>; 255 255 }; 256 256 ··· 264 264 rx-clock = <2>; 265 265 tx-clock = <2>; 266 266 current-speed = <1c200>; 267 - interrupts = <65 1>; 267 + interrupts = <29 8>; 268 268 interrupt-parent = <90c00>; 269 269 }; 270 270 ··· 278 278 clock-setup = <ff00ffff 250000>; 279 279 rx-clock = <15>; 280 280 tx-clock = <16>; 281 - interrupts = <5d 1>; 281 + interrupts = <21 8>; 282 282 interrupt-parent = <90c00>; 283 283 phy-handle = <2452002>; 284 284 }; ··· 293 293 clock-setup = <ffff00ff 3700>; 294 294 rx-clock = <17>; 295 295 tx-clock = <18>; 296 - interrupts = <5e 1>; 296 + interrupts = <22 8>; 297 297 interrupt-parent = <90c00>; 298 298 phy-handle = <2452003>; 299 299 };
+89 -61
arch/powerpc/sysdev/cpm2_pic.c
··· 36 36 #include <asm/mpc8260.h> 37 37 #include <asm/io.h> 38 38 #include <asm/prom.h> 39 + #include <asm/fs_pd.h> 39 40 40 41 #include "cpm2_pic.h" 42 + 43 + /* External IRQS */ 44 + #define CPM2_IRQ_EXT1 19 45 + #define CPM2_IRQ_EXT7 25 46 + 47 + /* Port C IRQS */ 48 + #define CPM2_IRQ_PORTC15 48 49 + #define CPM2_IRQ_PORTC0 63 50 + 51 + static intctl_cpm2_t *cpm2_intctl; 41 52 42 53 static struct device_node *cpm2_pic_node; 43 54 static struct irq_host *cpm2_pic_host; ··· 79 68 24, 25, 26, 27, 28, 29, 30, 31, 80 69 }; 81 70 82 - static void cpm2_mask_irq(unsigned int irq_nr) 71 + static void cpm2_mask_irq(unsigned int virq) 83 72 { 84 73 int bit, word; 85 - volatile uint *simr; 86 - 87 - irq_nr -= CPM_IRQ_OFFSET; 74 + unsigned int irq_nr = virq_to_hw(virq); 88 75 89 76 bit = irq_to_siubit[irq_nr]; 90 77 word = irq_to_siureg[irq_nr]; 91 78 92 - simr = &(cpm2_intctl->ic_simrh); 93 79 ppc_cached_irq_mask[word] &= ~(1 << bit); 94 - simr[word] = ppc_cached_irq_mask[word]; 80 + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 95 81 } 96 82 97 - static void cpm2_unmask_irq(unsigned int irq_nr) 83 + static void cpm2_unmask_irq(unsigned int virq) 98 84 { 99 85 int bit, word; 100 - volatile uint *simr; 101 - 102 - irq_nr -= CPM_IRQ_OFFSET; 86 + unsigned int irq_nr = virq_to_hw(virq); 103 87 104 88 bit = irq_to_siubit[irq_nr]; 105 89 word = irq_to_siureg[irq_nr]; 106 90 107 - simr = &(cpm2_intctl->ic_simrh); 108 91 ppc_cached_irq_mask[word] |= 1 << bit; 109 - simr[word] = ppc_cached_irq_mask[word]; 92 + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 110 93 } 111 94 112 - static void cpm2_mask_and_ack(unsigned int irq_nr) 95 + static void cpm2_ack(unsigned int virq) 113 96 { 114 97 int bit, word; 115 - volatile uint *simr, *sipnr; 116 - 117 - irq_nr -= CPM_IRQ_OFFSET; 98 + unsigned int irq_nr = virq_to_hw(virq); 118 99 119 100 bit = irq_to_siubit[irq_nr]; 120 101 word = irq_to_siureg[irq_nr]; 121 102 122 - simr = &(cpm2_intctl->ic_simrh); 123 - sipnr = &(cpm2_intctl->ic_sipnrh); 124 - ppc_cached_irq_mask[word] &= ~(1 << bit); 125 - simr[word] = ppc_cached_irq_mask[word]; 126 - sipnr[word] = 1 << bit; 103 + out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); 127 104 } 128 105 129 - static void cpm2_end_irq(unsigned int irq_nr) 106 + static void cpm2_end_irq(unsigned int virq) 130 107 { 131 108 int bit, word; 132 - volatile uint *simr; 109 + unsigned int irq_nr = virq_to_hw(virq); 133 110 134 111 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 135 112 && irq_desc[irq_nr].action) { 136 113 137 - irq_nr -= CPM_IRQ_OFFSET; 138 114 bit = irq_to_siubit[irq_nr]; 139 115 word = irq_to_siureg[irq_nr]; 140 116 141 - simr = &(cpm2_intctl->ic_simrh); 142 117 ppc_cached_irq_mask[word] |= 1 << bit; 143 - simr[word] = ppc_cached_irq_mask[word]; 118 + out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); 119 + 144 120 /* 145 121 * Work around large numbers of spurious IRQs on PowerPC 82xx 146 122 * systems. ··· 136 138 } 137 139 } 138 140 141 + static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) 142 + { 143 + unsigned int src = virq_to_hw(virq); 144 + struct irq_desc *desc = get_irq_desc(virq); 145 + unsigned int vold, vnew, edibit; 146 + 147 + if (flow_type == IRQ_TYPE_NONE) 148 + flow_type = IRQ_TYPE_LEVEL_LOW; 149 + 150 + if (flow_type & IRQ_TYPE_EDGE_RISING) { 151 + printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n", 152 + flow_type); 153 + return -EINVAL; 154 + } 155 + 156 + desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 157 + desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; 158 + if (flow_type & IRQ_TYPE_LEVEL_LOW) { 159 + desc->status |= IRQ_LEVEL; 160 + desc->handle_irq = handle_level_irq; 161 + } else 162 + desc->handle_irq = handle_edge_irq; 163 + 164 + /* internal IRQ senses are LEVEL_LOW 165 + * EXT IRQ and Port C IRQ senses are programmable 166 + */ 167 + if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7) 168 + edibit = (14 - (src - CPM2_IRQ_EXT1)); 169 + else 170 + if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) 171 + edibit = (31 - (src - CPM2_IRQ_PORTC15)); 172 + else 173 + return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; 174 + 175 + vold = in_be32(&cpm2_intctl->ic_siexr); 176 + 177 + if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) 178 + vnew = vold | (1 << edibit); 179 + else 180 + vnew = vold & ~(1 << edibit); 181 + 182 + if (vold != vnew) 183 + out_be32(&cpm2_intctl->ic_siexr, vnew); 184 + return 0; 185 + } 186 + 139 187 static struct irq_chip cpm2_pic = { 140 188 .typename = " CPM2 SIU ", 141 - .enable = cpm2_unmask_irq, 142 - .disable = cpm2_mask_irq, 189 + .mask = cpm2_mask_irq, 143 190 .unmask = cpm2_unmask_irq, 144 - .mask_ack = cpm2_mask_and_ack, 145 - .end = cpm2_end_irq, 191 + .ack = cpm2_ack, 192 + .eoi = cpm2_end_irq, 193 + .set_type = cpm2_set_irq_type, 146 194 }; 147 195 148 196 unsigned int cpm2_get_irq(void) ··· 198 154 199 155 /* For CPM2, read the SIVEC register and shift the bits down 200 156 * to get the irq number. */ 201 - bits = cpm2_intctl->ic_sivec; 157 + bits = in_be32(&cpm2_intctl->ic_sivec); 202 158 irq = bits >> 26; 203 159 204 160 if (irq == 0) 205 161 return(-1); 206 - return irq+CPM_IRQ_OFFSET; 162 + return irq_linear_revmap(cpm2_pic_host, irq); 207 163 } 208 164 209 165 static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node) 210 166 { 211 - return cpm2_pic_node == NULL || cpm2_pic_node == node; 167 + return cpm2_pic_node == node; 212 168 } 213 169 214 170 static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, ··· 221 177 return 0; 222 178 } 223 179 224 - static void cpm2_host_unmap(struct irq_host *h, unsigned int virq) 225 - { 226 - /* Make sure irq is masked in hardware */ 227 - cpm2_mask_irq(virq); 228 - 229 - /* remove chip and handler */ 230 - set_irq_chip_and_handler(virq, NULL, NULL); 231 - } 232 - 233 180 static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, 234 181 u32 *intspec, unsigned int intsize, 235 182 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 236 183 { 237 - static const unsigned char map_cpm2_senses[4] = { 238 - IRQ_TYPE_LEVEL_LOW, 239 - IRQ_TYPE_LEVEL_HIGH, 240 - IRQ_TYPE_EDGE_FALLING, 241 - IRQ_TYPE_EDGE_RISING, 242 - }; 243 - 244 184 *out_hwirq = intspec[0]; 245 - if (intsize > 1 && intspec[1] < 4) 246 - *out_flags = map_cpm2_senses[intspec[1]]; 185 + if (intsize > 1) 186 + *out_flags = intspec[1]; 247 187 else 248 188 *out_flags = IRQ_TYPE_NONE; 249 - 250 189 return 0; 251 190 } 252 191 253 192 static struct irq_host_ops cpm2_pic_host_ops = { 254 193 .match = cpm2_pic_host_match, 255 194 .map = cpm2_pic_host_map, 256 - .unmap = cpm2_host_unmap, 257 195 .xlate = cpm2_pic_host_xlate, 258 196 }; 259 197 ··· 243 217 { 244 218 int i; 245 219 220 + cpm2_intctl = cpm2_map(im_intctl); 221 + 246 222 /* Clear the CPM IRQ controller, in case it has any bits set 247 223 * from the bootloader 248 224 */ 249 225 250 226 /* Mask out everything */ 251 227 252 - cpm2_intctl->ic_simrh = 0x00000000; 253 - cpm2_intctl->ic_simrl = 0x00000000; 228 + out_be32(&cpm2_intctl->ic_simrh, 0x00000000); 229 + out_be32(&cpm2_intctl->ic_simrl, 0x00000000); 254 230 255 231 wmb(); 256 232 257 233 /* Ack everything */ 258 - cpm2_intctl->ic_sipnrh = 0xffffffff; 259 - cpm2_intctl->ic_sipnrl = 0xffffffff; 234 + out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff); 235 + out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff); 260 236 wmb(); 261 237 262 238 /* Dummy read of the vector */ 263 - i = cpm2_intctl->ic_sivec; 239 + i = in_be32(&cpm2_intctl->ic_sivec); 264 240 rmb(); 265 241 266 242 /* Initialize the default interrupt mapping priorities, 267 243 * in case the boot rom changed something on us. 268 244 */ 269 - cpm2_intctl->ic_sicr = 0; 270 - cpm2_intctl->ic_scprrh = 0x05309770; 271 - cpm2_intctl->ic_scprrl = 0x05309770; 245 + out_be16(&cpm2_intctl->ic_sicr, 0); 246 + out_be32(&cpm2_intctl->ic_scprrh, 0x05309770); 247 + out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); 272 248 273 249 /* create a legacy host */ 274 250 cpm2_pic_node = of_node_get(node);
-2
arch/powerpc/sysdev/cpm2_pic.h
··· 1 1 #ifndef _PPC_KERNEL_CPM2_H 2 2 #define _PPC_KERNEL_CPM2_H 3 3 4 - extern intctl_cpm2_t *cpm2_intctl; 5 - 6 4 extern unsigned int cpm2_get_irq(void); 7 5 8 6 extern void cpm2_pic_init(struct device_node*);
+24
include/asm-powerpc/mpc8260.h
··· 1 + /* 2 + * Since there are many different boards and no standard configuration, 3 + * we have a unique include file for each. Rather than change every 4 + * file that has to include MPC8260 configuration, they all include 5 + * this one and the configuration switching is done here. 6 + */ 7 + #ifdef __KERNEL__ 8 + #ifndef __ASM_PPC_MPC8260_H__ 9 + #define __ASM_PPC_MPC8260_H__ 10 + 11 + 12 + #ifdef CONFIG_8260 13 + 14 + #if defined(CONFIG_PQ2ADS) || defined (CONFIG_PQ2FADS) 15 + #include <platforms/82xx/pq2ads.h> 16 + #endif 17 + 18 + #ifdef CONFIG_PCI_8260 19 + #include <platforms/82xx/m82xx_pci.h> 20 + #endif 21 + 22 + #endif /* CONFIG_8260 */ 23 + #endif /* !__ASM_PPC_MPC8260_H__ */ 24 + #endif /* __KERNEL__ */