diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/interrupt.c')
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 419 |
1 files changed, 186 insertions, 233 deletions
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 22da1335445a..9d5da7896892 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Cell Internal Interrupt Controller | 2 | * Cell Internal Interrupt Controller |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
5 | * IBM, Corp. | ||
6 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | 7 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 |
5 | * | 8 | * |
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | 9 | * Author: Arnd Bergmann <arndb@de.ibm.com> |
@@ -25,11 +28,13 @@ | |||
25 | #include <linux/module.h> | 28 | #include <linux/module.h> |
26 | #include <linux/percpu.h> | 29 | #include <linux/percpu.h> |
27 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/ioport.h> | ||
28 | 32 | ||
29 | #include <asm/io.h> | 33 | #include <asm/io.h> |
30 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
31 | #include <asm/prom.h> | 35 | #include <asm/prom.h> |
32 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
37 | #include <asm/machdep.h> | ||
33 | 38 | ||
34 | #include "interrupt.h" | 39 | #include "interrupt.h" |
35 | #include "cbe_regs.h" | 40 | #include "cbe_regs.h" |
@@ -37,231 +42,65 @@ | |||
37 | struct iic { | 42 | struct iic { |
38 | struct cbe_iic_thread_regs __iomem *regs; | 43 | struct cbe_iic_thread_regs __iomem *regs; |
39 | u8 target_id; | 44 | u8 target_id; |
45 | u8 eoi_stack[16]; | ||
46 | int eoi_ptr; | ||
47 | struct irq_host *host; | ||
40 | }; | 48 | }; |
41 | 49 | ||
42 | static DEFINE_PER_CPU(struct iic, iic); | 50 | static DEFINE_PER_CPU(struct iic, iic); |
51 | #define IIC_NODE_COUNT 2 | ||
52 | static struct irq_host *iic_hosts[IIC_NODE_COUNT]; | ||
43 | 53 | ||
44 | void iic_local_enable(void) | 54 | /* Convert between "pending" bits and hw irq number */ |
55 | static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) | ||
45 | { | 56 | { |
46 | struct iic *iic = &__get_cpu_var(iic); | 57 | unsigned char unit = bits.source & 0xf; |
47 | u64 tmp; | ||
48 | |||
49 | /* | ||
50 | * There seems to be a bug that is present in DD2.x CPUs | ||
51 | * and still only partially fixed in DD3.1. | ||
52 | * This bug causes a value written to the priority register | ||
53 | * not to make it there, resulting in a system hang unless we | ||
54 | * write it again. | ||
55 | * Masking with 0xf0 is done because the Cell BE does not | ||
56 | * implement the lower four bits of the interrupt priority, | ||
57 | * they always read back as zeroes, although future CPUs | ||
58 | * might implement different bits. | ||
59 | */ | ||
60 | do { | ||
61 | out_be64(&iic->regs->prio, 0xff); | ||
62 | tmp = in_be64(&iic->regs->prio); | ||
63 | } while ((tmp & 0xf0) != 0xf0); | ||
64 | } | ||
65 | |||
66 | void iic_local_disable(void) | ||
67 | { | ||
68 | out_be64(&__get_cpu_var(iic).regs->prio, 0x0); | ||
69 | } | ||
70 | 58 | ||
71 | static unsigned int iic_startup(unsigned int irq) | 59 | if (bits.flags & CBE_IIC_IRQ_IPI) |
72 | { | 60 | return IIC_IRQ_IPI0 | (bits.prio >> 4); |
73 | return 0; | 61 | else if (bits.class <= 3) |
62 | return (bits.class << 4) | unit; | ||
63 | else | ||
64 | return IIC_IRQ_INVALID; | ||
74 | } | 65 | } |
75 | 66 | ||
76 | static void iic_enable(unsigned int irq) | 67 | static void iic_mask(unsigned int irq) |
77 | { | 68 | { |
78 | iic_local_enable(); | ||
79 | } | 69 | } |
80 | 70 | ||
81 | static void iic_disable(unsigned int irq) | 71 | static void iic_unmask(unsigned int irq) |
82 | { | 72 | { |
83 | } | 73 | } |
84 | 74 | ||
85 | static void iic_end(unsigned int irq) | 75 | static void iic_eoi(unsigned int irq) |
86 | { | 76 | { |
87 | iic_local_enable(); | 77 | struct iic *iic = &__get_cpu_var(iic); |
78 | out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]); | ||
79 | BUG_ON(iic->eoi_ptr < 0); | ||
88 | } | 80 | } |
89 | 81 | ||
90 | static struct hw_interrupt_type iic_pic = { | 82 | static struct irq_chip iic_chip = { |
91 | .typename = " CELL-IIC ", | 83 | .typename = " CELL-IIC ", |
92 | .startup = iic_startup, | 84 | .mask = iic_mask, |
93 | .enable = iic_enable, | 85 | .unmask = iic_unmask, |
94 | .disable = iic_disable, | 86 | .eoi = iic_eoi, |
95 | .end = iic_end, | ||
96 | }; | 87 | }; |
97 | 88 | ||
98 | static int iic_external_get_irq(struct cbe_iic_pending_bits pending) | ||
99 | { | ||
100 | int irq; | ||
101 | unsigned char node, unit; | ||
102 | |||
103 | node = pending.source >> 4; | ||
104 | unit = pending.source & 0xf; | ||
105 | irq = -1; | ||
106 | |||
107 | /* | ||
108 | * This mapping is specific to the Cell Broadband | ||
109 | * Engine. We might need to get the numbers | ||
110 | * from the device tree to support future CPUs. | ||
111 | */ | ||
112 | switch (unit) { | ||
113 | case 0x00: | ||
114 | case 0x0b: | ||
115 | /* | ||
116 | * One of these units can be connected | ||
117 | * to an external interrupt controller. | ||
118 | */ | ||
119 | if (pending.class != 2) | ||
120 | break; | ||
121 | irq = IIC_EXT_OFFSET | ||
122 | + spider_get_irq(node) | ||
123 | + node * IIC_NODE_STRIDE; | ||
124 | break; | ||
125 | case 0x01 ... 0x04: | ||
126 | case 0x07 ... 0x0a: | ||
127 | /* | ||
128 | * These units are connected to the SPEs | ||
129 | */ | ||
130 | if (pending.class > 2) | ||
131 | break; | ||
132 | irq = IIC_SPE_OFFSET | ||
133 | + pending.class * IIC_CLASS_STRIDE | ||
134 | + node * IIC_NODE_STRIDE | ||
135 | + unit; | ||
136 | break; | ||
137 | } | ||
138 | if (irq == -1) | ||
139 | printk(KERN_WARNING "Unexpected interrupt class %02x, " | ||
140 | "source %02x, prio %02x, cpu %02x\n", pending.class, | ||
141 | pending.source, pending.prio, smp_processor_id()); | ||
142 | return irq; | ||
143 | } | ||
144 | |||
145 | /* Get an IRQ number from the pending state register of the IIC */ | 89 | /* Get an IRQ number from the pending state register of the IIC */ |
146 | int iic_get_irq(struct pt_regs *regs) | 90 | static unsigned int iic_get_irq(struct pt_regs *regs) |
147 | { | 91 | { |
148 | struct iic *iic; | 92 | struct cbe_iic_pending_bits pending; |
149 | int irq; | 93 | struct iic *iic; |
150 | struct cbe_iic_pending_bits pending; | 94 | |
151 | 95 | iic = &__get_cpu_var(iic); | |
152 | iic = &__get_cpu_var(iic); | 96 | *(unsigned long *) &pending = |
153 | *(unsigned long *) &pending = | 97 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); |
154 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); | 98 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; |
155 | 99 | BUG_ON(iic->eoi_ptr > 15); | |
156 | irq = -1; | 100 | if (pending.flags & CBE_IIC_IRQ_VALID) |
157 | if (pending.flags & CBE_IIC_IRQ_VALID) { | 101 | return irq_linear_revmap(iic->host, |
158 | if (pending.flags & CBE_IIC_IRQ_IPI) { | 102 | iic_pending_to_hwnum(pending)); |
159 | irq = IIC_IPI_OFFSET + (pending.prio >> 4); | 103 | return NO_IRQ; |
160 | /* | ||
161 | if (irq > 0x80) | ||
162 | printk(KERN_WARNING "Unexpected IPI prio %02x" | ||
163 | "on CPU %02x\n", pending.prio, | ||
164 | smp_processor_id()); | ||
165 | */ | ||
166 | } else { | ||
167 | irq = iic_external_get_irq(pending); | ||
168 | } | ||
169 | } | ||
170 | return irq; | ||
171 | } | ||
172 | |||
173 | /* hardcoded part to be compatible with older firmware */ | ||
174 | |||
175 | static int setup_iic_hardcoded(void) | ||
176 | { | ||
177 | struct device_node *np; | ||
178 | int nodeid, cpu; | ||
179 | unsigned long regs; | ||
180 | struct iic *iic; | ||
181 | |||
182 | for_each_possible_cpu(cpu) { | ||
183 | iic = &per_cpu(iic, cpu); | ||
184 | nodeid = cpu/2; | ||
185 | |||
186 | for (np = of_find_node_by_type(NULL, "cpu"); | ||
187 | np; | ||
188 | np = of_find_node_by_type(np, "cpu")) { | ||
189 | if (nodeid == *(int *)get_property(np, "node-id", NULL)) | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | if (!np) { | ||
194 | printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); | ||
195 | iic->regs = NULL; | ||
196 | iic->target_id = 0xff; | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | regs = *(long *)get_property(np, "iic", NULL); | ||
201 | |||
202 | /* hack until we have decided on the devtree info */ | ||
203 | regs += 0x400; | ||
204 | if (cpu & 1) | ||
205 | regs += 0x20; | ||
206 | |||
207 | printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); | ||
208 | iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs)); | ||
209 | iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); | ||
210 | } | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int setup_iic(void) | ||
216 | { | ||
217 | struct device_node *dn; | ||
218 | unsigned long *regs; | ||
219 | char *compatible; | ||
220 | unsigned *np, found = 0; | ||
221 | struct iic *iic = NULL; | ||
222 | |||
223 | for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { | ||
224 | compatible = (char *)get_property(dn, "compatible", NULL); | ||
225 | |||
226 | if (!compatible) { | ||
227 | printk(KERN_WARNING "no compatible property found !\n"); | ||
228 | continue; | ||
229 | } | ||
230 | |||
231 | if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller")) | ||
232 | regs = (unsigned long *)get_property(dn,"reg", NULL); | ||
233 | else | ||
234 | continue; | ||
235 | |||
236 | if (!regs) | ||
237 | printk(KERN_WARNING "IIC: no reg property\n"); | ||
238 | |||
239 | np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL); | ||
240 | |||
241 | if (!np) { | ||
242 | printk(KERN_WARNING "IIC: CPU association not found\n"); | ||
243 | iic->regs = NULL; | ||
244 | iic->target_id = 0xff; | ||
245 | return -ENODEV; | ||
246 | } | ||
247 | |||
248 | iic = &per_cpu(iic, np[0]); | ||
249 | iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs)); | ||
250 | iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); | ||
251 | printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); | ||
252 | |||
253 | iic = &per_cpu(iic, np[1]); | ||
254 | iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs)); | ||
255 | iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); | ||
256 | printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); | ||
257 | |||
258 | found++; | ||
259 | } | ||
260 | |||
261 | if (found) | ||
262 | return 0; | ||
263 | else | ||
264 | return -ENODEV; | ||
265 | } | 104 | } |
266 | 105 | ||
267 | #ifdef CONFIG_SMP | 106 | #ifdef CONFIG_SMP |
@@ -269,12 +108,12 @@ static int setup_iic(void) | |||
269 | /* Use the highest interrupt priorities for IPI */ | 108 | /* Use the highest interrupt priorities for IPI */ |
270 | static inline int iic_ipi_to_irq(int ipi) | 109 | static inline int iic_ipi_to_irq(int ipi) |
271 | { | 110 | { |
272 | return IIC_IPI_OFFSET + IIC_NUM_IPIS - 1 - ipi; | 111 | return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi; |
273 | } | 112 | } |
274 | 113 | ||
275 | static inline int iic_irq_to_ipi(int irq) | 114 | static inline int iic_irq_to_ipi(int irq) |
276 | { | 115 | { |
277 | return IIC_NUM_IPIS - 1 - (irq - IIC_IPI_OFFSET); | 116 | return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0); |
278 | } | 117 | } |
279 | 118 | ||
280 | void iic_setup_cpu(void) | 119 | void iic_setup_cpu(void) |
@@ -293,22 +132,51 @@ u8 iic_get_target_id(int cpu) | |||
293 | } | 132 | } |
294 | EXPORT_SYMBOL_GPL(iic_get_target_id); | 133 | EXPORT_SYMBOL_GPL(iic_get_target_id); |
295 | 134 | ||
135 | struct irq_host *iic_get_irq_host(int node) | ||
136 | { | ||
137 | if (node < 0 || node >= IIC_NODE_COUNT) | ||
138 | return NULL; | ||
139 | return iic_hosts[node]; | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(iic_get_irq_host); | ||
142 | |||
143 | |||
296 | static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | 144 | static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) |
297 | { | 145 | { |
298 | smp_message_recv(iic_irq_to_ipi(irq), regs); | 146 | int ipi = (int)(long)dev_id; |
147 | |||
148 | smp_message_recv(ipi, regs); | ||
149 | |||
299 | return IRQ_HANDLED; | 150 | return IRQ_HANDLED; |
300 | } | 151 | } |
301 | 152 | ||
302 | static void iic_request_ipi(int ipi, const char *name) | 153 | static void iic_request_ipi(int ipi, const char *name) |
303 | { | 154 | { |
304 | int irq; | 155 | int node, virq; |
305 | 156 | ||
306 | irq = iic_ipi_to_irq(ipi); | 157 | for (node = 0; node < IIC_NODE_COUNT; node++) { |
307 | /* IPIs are marked IRQF_DISABLED as they must run with irqs | 158 | char *rname; |
308 | * disabled */ | 159 | if (iic_hosts[node] == NULL) |
309 | get_irq_desc(irq)->chip = &iic_pic; | 160 | continue; |
310 | get_irq_desc(irq)->status |= IRQ_PER_CPU; | 161 | virq = irq_create_mapping(iic_hosts[node], |
311 | request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL); | 162 | iic_ipi_to_irq(ipi), 0); |
163 | if (virq == NO_IRQ) { | ||
164 | printk(KERN_ERR | ||
165 | "iic: failed to map IPI %s on node %d\n", | ||
166 | name, node); | ||
167 | continue; | ||
168 | } | ||
169 | rname = kzalloc(strlen(name) + 16, GFP_KERNEL); | ||
170 | if (rname) | ||
171 | sprintf(rname, "%s node %d", name, node); | ||
172 | else | ||
173 | rname = (char *)name; | ||
174 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, | ||
175 | rname, (void *)(long)ipi)) | ||
176 | printk(KERN_ERR | ||
177 | "iic: failed to request IPI %s on node %d\n", | ||
178 | name, node); | ||
179 | } | ||
312 | } | 180 | } |
313 | 181 | ||
314 | void iic_request_IPIs(void) | 182 | void iic_request_IPIs(void) |
@@ -319,34 +187,119 @@ void iic_request_IPIs(void) | |||
319 | iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); | 187 | iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); |
320 | #endif /* CONFIG_DEBUGGER */ | 188 | #endif /* CONFIG_DEBUGGER */ |
321 | } | 189 | } |
190 | |||
322 | #endif /* CONFIG_SMP */ | 191 | #endif /* CONFIG_SMP */ |
323 | 192 | ||
324 | static void iic_setup_spe_handlers(void) | 193 | |
194 | static int iic_host_match(struct irq_host *h, struct device_node *node) | ||
195 | { | ||
196 | return h->host_data != NULL && node == h->host_data; | ||
197 | } | ||
198 | |||
199 | static int iic_host_map(struct irq_host *h, unsigned int virq, | ||
200 | irq_hw_number_t hw, unsigned int flags) | ||
201 | { | ||
202 | if (hw < IIC_IRQ_IPI0) | ||
203 | set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); | ||
204 | else | ||
205 | set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int iic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
210 | u32 *intspec, unsigned int intsize, | ||
211 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
212 | |||
213 | { | ||
214 | /* Currently, we don't translate anything. That needs to be fixed as | ||
215 | * we get better defined device-trees. iic interrupts have to be | ||
216 | * explicitely mapped by whoever needs them | ||
217 | */ | ||
218 | return -ENODEV; | ||
219 | } | ||
220 | |||
221 | static struct irq_host_ops iic_host_ops = { | ||
222 | .match = iic_host_match, | ||
223 | .map = iic_host_map, | ||
224 | .xlate = iic_host_xlate, | ||
225 | }; | ||
226 | |||
227 | static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, | ||
228 | struct irq_host *host) | ||
325 | { | 229 | { |
326 | int be, isrc; | 230 | /* XXX FIXME: should locate the linux CPU number from the HW cpu |
231 | * number properly. We are lucky for now | ||
232 | */ | ||
233 | struct iic *iic = &per_cpu(iic, hw_cpu); | ||
234 | |||
235 | iic->regs = ioremap(addr, sizeof(struct cbe_iic_thread_regs)); | ||
236 | BUG_ON(iic->regs == NULL); | ||
327 | 237 | ||
328 | /* Assume two threads per BE are present */ | 238 | iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); |
329 | for (be=0; be < num_present_cpus() / 2; be++) { | 239 | iic->eoi_stack[0] = 0xff; |
330 | for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) { | 240 | iic->host = host; |
331 | int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc; | 241 | out_be64(&iic->regs->prio, 0); |
332 | get_irq_desc(irq)->chip = &iic_pic; | 242 | |
243 | printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n", | ||
244 | hw_cpu, addr, iic->regs, iic->target_id); | ||
245 | } | ||
246 | |||
247 | static int __init setup_iic(void) | ||
248 | { | ||
249 | struct device_node *dn; | ||
250 | struct resource r0, r1; | ||
251 | struct irq_host *host; | ||
252 | int found = 0; | ||
253 | u32 *np; | ||
254 | |||
255 | for (dn = NULL; | ||
256 | (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) { | ||
257 | if (!device_is_compatible(dn, | ||
258 | "IBM,CBEA-Internal-Interrupt-Controller")) | ||
259 | continue; | ||
260 | np = (u32 *)get_property(dn, "ibm,interrupt-server-ranges", | ||
261 | NULL); | ||
262 | if (np == NULL) { | ||
263 | printk(KERN_WARNING "IIC: CPU association not found\n"); | ||
264 | of_node_put(dn); | ||
265 | return -ENODEV; | ||
266 | } | ||
267 | if (of_address_to_resource(dn, 0, &r0) || | ||
268 | of_address_to_resource(dn, 1, &r1)) { | ||
269 | printk(KERN_WARNING "IIC: Can't resolve addresses\n"); | ||
270 | of_node_put(dn); | ||
271 | return -ENODEV; | ||
333 | } | 272 | } |
273 | host = NULL; | ||
274 | if (found < IIC_NODE_COUNT) { | ||
275 | host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, | ||
276 | IIC_SOURCE_COUNT, | ||
277 | &iic_host_ops, | ||
278 | IIC_IRQ_INVALID); | ||
279 | iic_hosts[found] = host; | ||
280 | BUG_ON(iic_hosts[found] == NULL); | ||
281 | iic_hosts[found]->host_data = of_node_get(dn); | ||
282 | found++; | ||
283 | } | ||
284 | init_one_iic(np[0], r0.start, host); | ||
285 | init_one_iic(np[1], r1.start, host); | ||
334 | } | 286 | } |
287 | |||
288 | if (found) | ||
289 | return 0; | ||
290 | else | ||
291 | return -ENODEV; | ||
335 | } | 292 | } |
336 | 293 | ||
337 | void iic_init_IRQ(void) | 294 | void __init iic_init_IRQ(void) |
338 | { | 295 | { |
339 | int cpu, irq_offset; | 296 | /* Discover and initialize iics */ |
340 | struct iic *iic; | ||
341 | |||
342 | if (setup_iic() < 0) | 297 | if (setup_iic() < 0) |
343 | setup_iic_hardcoded(); | 298 | panic("IIC: Failed to initialize !\n"); |
344 | 299 | ||
345 | irq_offset = 0; | 300 | /* Set master interrupt handling function */ |
346 | for_each_possible_cpu(cpu) { | 301 | ppc_md.get_irq = iic_get_irq; |
347 | iic = &per_cpu(iic, cpu); | 302 | |
348 | if (iic->regs) | 303 | /* Enable on current CPU */ |
349 | out_be64(&iic->regs->prio, 0xff); | 304 | iic_setup_cpu(); |
350 | } | ||
351 | iic_setup_spe_handlers(); | ||
352 | } | 305 | } |