xref: /linux/arch/powerpc/sysdev/xics/icp-native.c (revision 12871a0bd67dd4db4418e1daafcd46e9d329ef10)
1 /*
2  * Copyright 2011 IBM Corporation.
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public License
6  *  as published by the Free Software Foundation; either version
7  *  2 of the License, or (at your option) any later version.
8  *
9  */
10 
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/irq.h>
14 #include <linux/smp.h>
15 #include <linux/interrupt.h>
16 #include <linux/init.h>
17 #include <linux/cpu.h>
18 #include <linux/of.h>
19 #include <linux/spinlock.h>
20 
21 #include <asm/prom.h>
22 #include <asm/io.h>
23 #include <asm/smp.h>
24 #include <asm/irq.h>
25 #include <asm/errno.h>
26 #include <asm/xics.h>
27 
28 struct icp_ipl {
29 	union {
30 		u32 word;
31 		u8 bytes[4];
32 	} xirr_poll;
33 	union {
34 		u32 word;
35 		u8 bytes[4];
36 	} xirr;
37 	u32 dummy;
38 	union {
39 		u32 word;
40 		u8 bytes[4];
41 	} qirr;
42 	u32 link_a;
43 	u32 link_b;
44 	u32 link_c;
45 };
46 
47 static struct icp_ipl __iomem *icp_native_regs[NR_CPUS];
48 
49 static inline unsigned int icp_native_get_xirr(void)
50 {
51 	int cpu = smp_processor_id();
52 
53 	return in_be32(&icp_native_regs[cpu]->xirr.word);
54 }
55 
56 static inline void icp_native_set_xirr(unsigned int value)
57 {
58 	int cpu = smp_processor_id();
59 
60 	out_be32(&icp_native_regs[cpu]->xirr.word, value);
61 }
62 
63 static inline void icp_native_set_cppr(u8 value)
64 {
65 	int cpu = smp_processor_id();
66 
67 	out_8(&icp_native_regs[cpu]->xirr.bytes[0], value);
68 }
69 
70 static inline void icp_native_set_qirr(int n_cpu, u8 value)
71 {
72 	out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value);
73 }
74 
75 static void icp_native_set_cpu_priority(unsigned char cppr)
76 {
77 	xics_set_base_cppr(cppr);
78 	icp_native_set_cppr(cppr);
79 	iosync();
80 }
81 
82 static void icp_native_eoi(struct irq_data *d)
83 {
84 	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
85 
86 	iosync();
87 	icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq);
88 }
89 
90 static void icp_native_teardown_cpu(void)
91 {
92 	int cpu = smp_processor_id();
93 
94 	/* Clear any pending IPI */
95 	icp_native_set_qirr(cpu, 0xff);
96 }
97 
98 static void icp_native_flush_ipi(void)
99 {
100 	/* We take the ipi irq but and never return so we
101 	 * need to EOI the IPI, but want to leave our priority 0
102 	 *
103 	 * should we check all the other interrupts too?
104 	 * should we be flagging idle loop instead?
105 	 * or creating some task to be scheduled?
106 	 */
107 
108 	icp_native_set_xirr((0x00 << 24) | XICS_IPI);
109 }
110 
111 static unsigned int icp_native_get_irq(void)
112 {
113 	unsigned int xirr = icp_native_get_xirr();
114 	unsigned int vec = xirr & 0x00ffffff;
115 	unsigned int irq;
116 
117 	if (vec == XICS_IRQ_SPURIOUS)
118 		return NO_IRQ;
119 
120 	irq = irq_radix_revmap_lookup(xics_host, vec);
121 	if (likely(irq != NO_IRQ)) {
122 		xics_push_cppr(vec);
123 		return irq;
124 	}
125 
126 	/* We don't have a linux mapping, so have rtas mask it. */
127 	xics_mask_unknown_vec(vec);
128 
129 	/* We might learn about it later, so EOI it */
130 	icp_native_set_xirr(xirr);
131 
132 	return NO_IRQ;
133 }
134 
135 #ifdef CONFIG_SMP
136 
137 static void icp_native_cause_ipi(int cpu, unsigned long data)
138 {
139 	icp_native_set_qirr(cpu, IPI_PRIORITY);
140 }
141 
142 static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
143 {
144 	int cpu = smp_processor_id();
145 
146 	icp_native_set_qirr(cpu, 0xff);
147 
148 	return smp_ipi_demux();
149 }
150 
151 #endif /* CONFIG_SMP */
152 
153 static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr,
154 					 unsigned long size)
155 {
156 	char *rname;
157 	int i, cpu = -1;
158 
159 	/* This may look gross but it's good enough for now, we don't quite
160 	 * have a hard -> linux processor id matching.
161 	 */
162 	for_each_possible_cpu(i) {
163 		if (!cpu_present(i))
164 			continue;
165 		if (hw_id == get_hard_smp_processor_id(i)) {
166 			cpu = i;
167 			break;
168 		}
169 	}
170 
171 	/* Fail, skip that CPU. Don't print, it's normal, some XICS come up
172 	 * with way more entries in there than you have CPUs
173 	 */
174 	if (cpu == -1)
175 		return 0;
176 
177 	rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation",
178 			  cpu, hw_id);
179 
180 	if (!request_mem_region(addr, size, rname)) {
181 		pr_warning("icp_native: Could not reserve ICP MMIO"
182 			   " for CPU %d, interrupt server #0x%x\n",
183 			   cpu, hw_id);
184 		return -EBUSY;
185 	}
186 
187 	icp_native_regs[cpu] = ioremap(addr, size);
188 	if (!icp_native_regs[cpu]) {
189 		pr_warning("icp_native: Failed ioremap for CPU %d, "
190 			   "interrupt server #0x%x, addr %#lx\n",
191 			   cpu, hw_id, addr);
192 		release_mem_region(addr, size);
193 		return -ENOMEM;
194 	}
195 	return 0;
196 }
197 
198 static int __init icp_native_init_one_node(struct device_node *np,
199 					   unsigned int *indx)
200 {
201 	unsigned int ilen;
202 	const u32 *ireg;
203 	int i;
204 	int reg_tuple_size;
205 	int num_servers = 0;
206 
207 	/* This code does the theorically broken assumption that the interrupt
208 	 * server numbers are the same as the hard CPU numbers.
209 	 * This happens to be the case so far but we are playing with fire...
210 	 * should be fixed one of these days. -BenH.
211 	 */
212 	ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen);
213 
214 	/* Do that ever happen ? we'll know soon enough... but even good'old
215 	 * f80 does have that property ..
216 	 */
217 	WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32)));
218 
219 	if (ireg) {
220 		*indx = of_read_number(ireg, 1);
221 		if (ilen >= 2*sizeof(u32))
222 			num_servers = of_read_number(ireg + 1, 1);
223 	}
224 
225 	ireg = of_get_property(np, "reg", &ilen);
226 	if (!ireg) {
227 		pr_err("icp_native: Can't find interrupt reg property");
228 		return -1;
229 	}
230 
231 	reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4;
232 	if (((ilen % reg_tuple_size) != 0)
233 	    || (num_servers && (num_servers != (ilen / reg_tuple_size)))) {
234 		pr_err("icp_native: ICP reg len (%d) != num servers (%d)",
235 		       ilen / reg_tuple_size, num_servers);
236 		return -1;
237 	}
238 
239 	for (i = 0; i < (ilen / reg_tuple_size); i++) {
240 		struct resource r;
241 		int err;
242 
243 		err = of_address_to_resource(np, i, &r);
244 		if (err) {
245 			pr_err("icp_native: Could not translate ICP MMIO"
246 			       " for interrupt server 0x%x (%d)\n", *indx, err);
247 			return -1;
248 		}
249 
250 		if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start))
251 			return -1;
252 
253 		(*indx)++;
254 	}
255 	return 0;
256 }
257 
258 static const struct icp_ops icp_native_ops = {
259 	.get_irq	= icp_native_get_irq,
260 	.eoi		= icp_native_eoi,
261 	.set_priority	= icp_native_set_cpu_priority,
262 	.teardown_cpu	= icp_native_teardown_cpu,
263 	.flush_ipi	= icp_native_flush_ipi,
264 #ifdef CONFIG_SMP
265 	.ipi_action	= icp_native_ipi_action,
266 	.cause_ipi	= icp_native_cause_ipi,
267 #endif
268 };
269 
270 int icp_native_init(void)
271 {
272 	struct device_node *np;
273 	u32 indx = 0;
274 	int found = 0;
275 
276 	for_each_compatible_node(np, NULL, "ibm,ppc-xicp")
277 		if (icp_native_init_one_node(np, &indx) == 0)
278 			found = 1;
279 	if (!found) {
280 		for_each_node_by_type(np,
281 			"PowerPC-External-Interrupt-Presentation") {
282 				if (icp_native_init_one_node(np, &indx) == 0)
283 					found = 1;
284 		}
285 	}
286 
287 	if (found == 0)
288 		return -ENODEV;
289 
290 	icp_ops = &icp_native_ops;
291 
292 	return 0;
293 }
294