xref: /kvmtool/powerpc/xics.c (revision 9dc5430ce7c9fba3398197eee0f5927d31259741)
1f17e5a37SMatt Evans /*
2f17e5a37SMatt Evans  * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
3f17e5a37SMatt Evans  *
4f17e5a37SMatt Evans  * Borrowed heavily from QEMU's xics.c,
5f17e5a37SMatt Evans  * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
6f17e5a37SMatt Evans  *
7f17e5a37SMatt Evans  * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
8f17e5a37SMatt Evans  *
9f17e5a37SMatt Evans  * This program is free software; you can redistribute it and/or modify it
10f17e5a37SMatt Evans  * under the terms of the GNU General Public License version 2 as published
11f17e5a37SMatt Evans  * by the Free Software Foundation.
12f17e5a37SMatt Evans  */
13f17e5a37SMatt Evans 
14f17e5a37SMatt Evans #include "spapr.h"
15f17e5a37SMatt Evans #include "xics.h"
16f17e5a37SMatt Evans #include "kvm/util.h"
17*9dc5430cSWill Deacon #include "kvm/kvm.h"
18f17e5a37SMatt Evans 
19f17e5a37SMatt Evans #include <stdio.h>
20f17e5a37SMatt Evans #include <malloc.h>
21f17e5a37SMatt Evans 
22e016c60dSMichael Ellerman #define XICS_NUM_IRQS	1024
23e016c60dSMichael Ellerman 
24f17e5a37SMatt Evans 
25f17e5a37SMatt Evans /* #define DEBUG_XICS yes */
26f17e5a37SMatt Evans #ifdef DEBUG_XICS
27f17e5a37SMatt Evans #define xics_dprintf(fmt, ...)					\
28f17e5a37SMatt Evans 	do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
29f17e5a37SMatt Evans #else
30f17e5a37SMatt Evans #define xics_dprintf(fmt, ...)			\
31f17e5a37SMatt Evans 	do { } while (0)
32f17e5a37SMatt Evans #endif
33f17e5a37SMatt Evans 
34f17e5a37SMatt Evans /*
35f17e5a37SMatt Evans  * ICP: Presentation layer
36f17e5a37SMatt Evans  */
37f17e5a37SMatt Evans 
38f17e5a37SMatt Evans struct icp_server_state {
39f17e5a37SMatt Evans 	uint32_t xirr;
40f17e5a37SMatt Evans 	uint8_t pending_priority;
41f17e5a37SMatt Evans 	uint8_t mfrr;
42f17e5a37SMatt Evans 	struct kvm_cpu *cpu;
43f17e5a37SMatt Evans };
44f17e5a37SMatt Evans 
45*9dc5430cSWill Deacon #define XICS_IRQ_OFFSET KVM_IRQ_OFFSET
46f17e5a37SMatt Evans #define XISR_MASK	0x00ffffff
47f17e5a37SMatt Evans #define CPPR_MASK	0xff000000
48f17e5a37SMatt Evans 
49f17e5a37SMatt Evans #define XISR(ss)   (((ss)->xirr) & XISR_MASK)
50f17e5a37SMatt Evans #define CPPR(ss)   (((ss)->xirr) >> 24)
51f17e5a37SMatt Evans 
52f17e5a37SMatt Evans struct ics_state;
53f17e5a37SMatt Evans 
54f17e5a37SMatt Evans struct icp_state {
55f17e5a37SMatt Evans 	unsigned long nr_servers;
56f17e5a37SMatt Evans 	struct icp_server_state *ss;
57f17e5a37SMatt Evans 	struct ics_state *ics;
58f17e5a37SMatt Evans };
59f17e5a37SMatt Evans 
60f17e5a37SMatt Evans static void ics_reject(struct ics_state *ics, int nr);
61f17e5a37SMatt Evans static void ics_resend(struct ics_state *ics);
62f17e5a37SMatt Evans static void ics_eoi(struct ics_state *ics, int nr);
63f17e5a37SMatt Evans 
cpu_irq_raise(struct kvm_cpu * vcpu)64f17e5a37SMatt Evans static inline void cpu_irq_raise(struct kvm_cpu *vcpu)
65f17e5a37SMatt Evans {
66f17e5a37SMatt Evans 	xics_dprintf("INT1[%p]\n", vcpu);
67f17e5a37SMatt Evans 	kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1);
68f17e5a37SMatt Evans }
69f17e5a37SMatt Evans 
cpu_irq_lower(struct kvm_cpu * vcpu)70f17e5a37SMatt Evans static inline void cpu_irq_lower(struct kvm_cpu *vcpu)
71f17e5a37SMatt Evans {
72f17e5a37SMatt Evans 	xics_dprintf("INT0[%p]\n", vcpu);
73f17e5a37SMatt Evans 	kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 0);
74f17e5a37SMatt Evans }
75f17e5a37SMatt Evans 
icp_check_ipi(struct icp_state * icp,int server)76f17e5a37SMatt Evans static void icp_check_ipi(struct icp_state *icp, int server)
77f17e5a37SMatt Evans {
78f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + server;
79f17e5a37SMatt Evans 
80f17e5a37SMatt Evans 	if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
81f17e5a37SMatt Evans 		return;
82f17e5a37SMatt Evans 	}
83f17e5a37SMatt Evans 
84f17e5a37SMatt Evans 	if (XISR(ss)) {
85f17e5a37SMatt Evans 		ics_reject(icp->ics, XISR(ss));
86f17e5a37SMatt Evans 	}
87f17e5a37SMatt Evans 
88f17e5a37SMatt Evans 	ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
89f17e5a37SMatt Evans 	ss->pending_priority = ss->mfrr;
90f17e5a37SMatt Evans 	cpu_irq_raise(ss->cpu);
91f17e5a37SMatt Evans }
92f17e5a37SMatt Evans 
icp_resend(struct icp_state * icp,int server)93f17e5a37SMatt Evans static void icp_resend(struct icp_state *icp, int server)
94f17e5a37SMatt Evans {
95f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + server;
96f17e5a37SMatt Evans 
97f17e5a37SMatt Evans 	if (ss->mfrr < CPPR(ss)) {
98f17e5a37SMatt Evans 		icp_check_ipi(icp, server);
99f17e5a37SMatt Evans 	}
100f17e5a37SMatt Evans 	ics_resend(icp->ics);
101f17e5a37SMatt Evans }
102f17e5a37SMatt Evans 
icp_set_cppr(struct icp_state * icp,int server,uint8_t cppr)103f17e5a37SMatt Evans static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
104f17e5a37SMatt Evans {
105f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + server;
106f17e5a37SMatt Evans 	uint8_t old_cppr;
107f17e5a37SMatt Evans 	uint32_t old_xisr;
108f17e5a37SMatt Evans 
109f17e5a37SMatt Evans 	old_cppr = CPPR(ss);
110f17e5a37SMatt Evans 	ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
111f17e5a37SMatt Evans 
112f17e5a37SMatt Evans 	if (cppr < old_cppr) {
113f17e5a37SMatt Evans 		if (XISR(ss) && (cppr <= ss->pending_priority)) {
114f17e5a37SMatt Evans 			old_xisr = XISR(ss);
115f17e5a37SMatt Evans 			ss->xirr &= ~XISR_MASK; /* Clear XISR */
116f17e5a37SMatt Evans 			cpu_irq_lower(ss->cpu);
117f17e5a37SMatt Evans 			ics_reject(icp->ics, old_xisr);
118f17e5a37SMatt Evans 		}
119f17e5a37SMatt Evans 	} else {
120f17e5a37SMatt Evans 		if (!XISR(ss)) {
121f17e5a37SMatt Evans 			icp_resend(icp, server);
122f17e5a37SMatt Evans 		}
123f17e5a37SMatt Evans 	}
124f17e5a37SMatt Evans }
125f17e5a37SMatt Evans 
icp_set_mfrr(struct icp_state * icp,int nr,uint8_t mfrr)126f17e5a37SMatt Evans static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
127f17e5a37SMatt Evans {
128f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + nr;
129f17e5a37SMatt Evans 
130f17e5a37SMatt Evans 	ss->mfrr = mfrr;
131f17e5a37SMatt Evans 	if (mfrr < CPPR(ss)) {
132f17e5a37SMatt Evans 		icp_check_ipi(icp, nr);
133f17e5a37SMatt Evans 	}
134f17e5a37SMatt Evans }
135f17e5a37SMatt Evans 
icp_accept(struct icp_server_state * ss)136f17e5a37SMatt Evans static uint32_t icp_accept(struct icp_server_state *ss)
137f17e5a37SMatt Evans {
138f17e5a37SMatt Evans 	uint32_t xirr;
139f17e5a37SMatt Evans 
140f17e5a37SMatt Evans 	cpu_irq_lower(ss->cpu);
141f17e5a37SMatt Evans 	xirr = ss->xirr;
142f17e5a37SMatt Evans 	ss->xirr = ss->pending_priority << 24;
143f17e5a37SMatt Evans 	return xirr;
144f17e5a37SMatt Evans }
145f17e5a37SMatt Evans 
icp_eoi(struct icp_state * icp,int server,uint32_t xirr)146f17e5a37SMatt Evans static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
147f17e5a37SMatt Evans {
148f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + server;
149f17e5a37SMatt Evans 
150f17e5a37SMatt Evans 	ics_eoi(icp->ics, xirr & XISR_MASK);
151f17e5a37SMatt Evans 	/* Send EOI -> ICS */
152f17e5a37SMatt Evans 	ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
153f17e5a37SMatt Evans 	if (!XISR(ss)) {
154f17e5a37SMatt Evans 		icp_resend(icp, server);
155f17e5a37SMatt Evans 	}
156f17e5a37SMatt Evans }
157f17e5a37SMatt Evans 
icp_irq(struct icp_state * icp,int server,int nr,uint8_t priority)158f17e5a37SMatt Evans static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
159f17e5a37SMatt Evans {
160f17e5a37SMatt Evans 	struct icp_server_state *ss = icp->ss + server;
161f17e5a37SMatt Evans 	xics_dprintf("icp_irq(nr %d, server %d, prio 0x%x)\n", nr, server, priority);
162f17e5a37SMatt Evans 	if ((priority >= CPPR(ss))
163f17e5a37SMatt Evans 	    || (XISR(ss) && (ss->pending_priority <= priority))) {
164f17e5a37SMatt Evans 		xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
165f17e5a37SMatt Evans 			     nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
166f17e5a37SMatt Evans 		ics_reject(icp->ics, nr);
167f17e5a37SMatt Evans 	} else {
168f17e5a37SMatt Evans 		if (XISR(ss)) {
169f17e5a37SMatt Evans 			xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
170f17e5a37SMatt Evans 				     nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
171f17e5a37SMatt Evans 			ics_reject(icp->ics, XISR(ss));
172f17e5a37SMatt Evans 		}
173f17e5a37SMatt Evans 		ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
174f17e5a37SMatt Evans 		ss->pending_priority = priority;
175f17e5a37SMatt Evans 		cpu_irq_raise(ss->cpu);
176f17e5a37SMatt Evans 	}
177f17e5a37SMatt Evans }
178f17e5a37SMatt Evans 
179f17e5a37SMatt Evans /*
180f17e5a37SMatt Evans  * ICS: Source layer
181f17e5a37SMatt Evans  */
182f17e5a37SMatt Evans 
183f17e5a37SMatt Evans struct ics_irq_state {
184f17e5a37SMatt Evans 	int server;
185f17e5a37SMatt Evans 	uint8_t priority;
186f17e5a37SMatt Evans 	uint8_t saved_priority;
187f17e5a37SMatt Evans 	int rejected:1;
188f17e5a37SMatt Evans 	int masked_pending:1;
189f17e5a37SMatt Evans };
190f17e5a37SMatt Evans 
191f17e5a37SMatt Evans struct ics_state {
192f17e5a37SMatt Evans 	unsigned int nr_irqs;
193f17e5a37SMatt Evans 	unsigned int offset;
194f17e5a37SMatt Evans 	struct ics_irq_state *irqs;
195f17e5a37SMatt Evans 	struct icp_state *icp;
196f17e5a37SMatt Evans };
197f17e5a37SMatt Evans 
ics_valid_irq(struct ics_state * ics,uint32_t nr)198f17e5a37SMatt Evans static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
199f17e5a37SMatt Evans {
200f17e5a37SMatt Evans 	return (nr >= ics->offset)
201f17e5a37SMatt Evans 		&& (nr < (ics->offset + ics->nr_irqs));
202f17e5a37SMatt Evans }
203f17e5a37SMatt Evans 
ics_set_irq_msi(struct ics_state * ics,int srcno,int val)204f17e5a37SMatt Evans static void ics_set_irq_msi(struct ics_state *ics, int srcno, int val)
205f17e5a37SMatt Evans {
206f17e5a37SMatt Evans 	struct ics_irq_state *irq = ics->irqs + srcno;
207f17e5a37SMatt Evans 
208f17e5a37SMatt Evans 	if (val) {
209f17e5a37SMatt Evans 		if (irq->priority == 0xff) {
210f17e5a37SMatt Evans 			xics_dprintf(" irq pri ff, masked pending\n");
211f17e5a37SMatt Evans 			irq->masked_pending = 1;
212f17e5a37SMatt Evans 		} else	{
213f17e5a37SMatt Evans 			icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
214f17e5a37SMatt Evans 		}
215f17e5a37SMatt Evans 	}
216f17e5a37SMatt Evans }
217f17e5a37SMatt Evans 
ics_reject_msi(struct ics_state * ics,int nr)218f17e5a37SMatt Evans static void ics_reject_msi(struct ics_state *ics, int nr)
219f17e5a37SMatt Evans {
220f17e5a37SMatt Evans 	struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
221f17e5a37SMatt Evans 
222f17e5a37SMatt Evans 	irq->rejected = 1;
223f17e5a37SMatt Evans }
224f17e5a37SMatt Evans 
ics_resend_msi(struct ics_state * ics)225f17e5a37SMatt Evans static void ics_resend_msi(struct ics_state *ics)
226f17e5a37SMatt Evans {
227f17e5a37SMatt Evans 	unsigned int i;
228f17e5a37SMatt Evans 
229f17e5a37SMatt Evans 	for (i = 0; i < ics->nr_irqs; i++) {
230f17e5a37SMatt Evans 		struct ics_irq_state *irq = ics->irqs + i;
231f17e5a37SMatt Evans 
232f17e5a37SMatt Evans 		/* FIXME: filter by server#? */
233f17e5a37SMatt Evans 		if (irq->rejected) {
234f17e5a37SMatt Evans 			irq->rejected = 0;
235f17e5a37SMatt Evans 			if (irq->priority != 0xff) {
236f17e5a37SMatt Evans 				icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
237f17e5a37SMatt Evans 			}
238f17e5a37SMatt Evans 		}
239f17e5a37SMatt Evans 	}
240f17e5a37SMatt Evans }
241f17e5a37SMatt Evans 
ics_write_xive_msi(struct ics_state * ics,int nr,int server,uint8_t priority)242f17e5a37SMatt Evans static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
243f17e5a37SMatt Evans 			       uint8_t priority)
244f17e5a37SMatt Evans {
245f17e5a37SMatt Evans 	struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
246f17e5a37SMatt Evans 
247f17e5a37SMatt Evans 	irq->server = server;
248f17e5a37SMatt Evans 	irq->priority = priority;
249f17e5a37SMatt Evans 	xics_dprintf("ics_write_xive_msi(nr %d, server %d, pri 0x%x)\n", nr, server, priority);
250f17e5a37SMatt Evans 
251f17e5a37SMatt Evans 	if (!irq->masked_pending || (priority == 0xff)) {
252f17e5a37SMatt Evans 		return;
253f17e5a37SMatt Evans 	}
254f17e5a37SMatt Evans 
255f17e5a37SMatt Evans 	irq->masked_pending = 0;
256f17e5a37SMatt Evans 	icp_irq(ics->icp, server, nr, priority);
257f17e5a37SMatt Evans }
258f17e5a37SMatt Evans 
ics_reject(struct ics_state * ics,int nr)259f17e5a37SMatt Evans static void ics_reject(struct ics_state *ics, int nr)
260f17e5a37SMatt Evans {
261f17e5a37SMatt Evans 	ics_reject_msi(ics, nr);
262f17e5a37SMatt Evans }
263f17e5a37SMatt Evans 
ics_resend(struct ics_state * ics)264f17e5a37SMatt Evans static void ics_resend(struct ics_state *ics)
265f17e5a37SMatt Evans {
266f17e5a37SMatt Evans 	ics_resend_msi(ics);
267f17e5a37SMatt Evans }
268f17e5a37SMatt Evans 
ics_eoi(struct ics_state * ics,int nr)269f17e5a37SMatt Evans static void ics_eoi(struct ics_state *ics, int nr)
270f17e5a37SMatt Evans {
271f17e5a37SMatt Evans }
272f17e5a37SMatt Evans 
273f17e5a37SMatt Evans /*
274f17e5a37SMatt Evans  * Exported functions
275f17e5a37SMatt Evans  */
276f17e5a37SMatt Evans 
h_cppr(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)277f17e5a37SMatt Evans static target_ulong h_cppr(struct kvm_cpu *vcpu,
278f17e5a37SMatt Evans 			   target_ulong opcode, target_ulong *args)
279f17e5a37SMatt Evans {
280f17e5a37SMatt Evans 	target_ulong cppr = args[0];
281f17e5a37SMatt Evans 
282f17e5a37SMatt Evans 	xics_dprintf("h_cppr(%lx)\n", cppr);
28342ac24f9SSasha Levin 	icp_set_cppr(vcpu->kvm->arch.icp, vcpu->cpu_id, cppr);
284f17e5a37SMatt Evans 	return H_SUCCESS;
285f17e5a37SMatt Evans }
286f17e5a37SMatt Evans 
h_ipi(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)287f17e5a37SMatt Evans static target_ulong h_ipi(struct kvm_cpu *vcpu,
288f17e5a37SMatt Evans 			  target_ulong opcode, target_ulong *args)
289f17e5a37SMatt Evans {
290f17e5a37SMatt Evans 	target_ulong server = args[0];
291f17e5a37SMatt Evans 	target_ulong mfrr = args[1];
292f17e5a37SMatt Evans 
293f17e5a37SMatt Evans 	xics_dprintf("h_ipi(%lx, %lx)\n", server, mfrr);
29442ac24f9SSasha Levin 	if (server >= vcpu->kvm->arch.icp->nr_servers) {
295f17e5a37SMatt Evans 		return H_PARAMETER;
296f17e5a37SMatt Evans 	}
297f17e5a37SMatt Evans 
29842ac24f9SSasha Levin 	icp_set_mfrr(vcpu->kvm->arch.icp, server, mfrr);
299f17e5a37SMatt Evans 	return H_SUCCESS;
300f17e5a37SMatt Evans }
301f17e5a37SMatt Evans 
h_xirr(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)302f17e5a37SMatt Evans static target_ulong h_xirr(struct kvm_cpu *vcpu,
303f17e5a37SMatt Evans 			   target_ulong opcode, target_ulong *args)
304f17e5a37SMatt Evans {
30542ac24f9SSasha Levin 	uint32_t xirr = icp_accept(vcpu->kvm->arch.icp->ss + vcpu->cpu_id);
306f17e5a37SMatt Evans 
307f17e5a37SMatt Evans 	xics_dprintf("h_xirr() = %x\n", xirr);
308f17e5a37SMatt Evans 	args[0] = xirr;
309f17e5a37SMatt Evans 	return H_SUCCESS;
310f17e5a37SMatt Evans }
311f17e5a37SMatt Evans 
h_eoi(struct kvm_cpu * vcpu,target_ulong opcode,target_ulong * args)312f17e5a37SMatt Evans static target_ulong h_eoi(struct kvm_cpu *vcpu,
313f17e5a37SMatt Evans 			  target_ulong opcode, target_ulong *args)
314f17e5a37SMatt Evans {
315f17e5a37SMatt Evans 	target_ulong xirr = args[0];
316f17e5a37SMatt Evans 
317f17e5a37SMatt Evans 	xics_dprintf("h_eoi(%lx)\n", xirr);
31842ac24f9SSasha Levin 	icp_eoi(vcpu->kvm->arch.icp, vcpu->cpu_id, xirr);
319f17e5a37SMatt Evans 	return H_SUCCESS;
320f17e5a37SMatt Evans }
321f17e5a37SMatt Evans 
rtas_set_xive(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)322f17e5a37SMatt Evans static void rtas_set_xive(struct kvm_cpu *vcpu, uint32_t token,
323f17e5a37SMatt Evans 			  uint32_t nargs, target_ulong args,
324f17e5a37SMatt Evans 			  uint32_t nret, target_ulong rets)
325f17e5a37SMatt Evans {
32642ac24f9SSasha Levin 	struct ics_state *ics = vcpu->kvm->arch.icp->ics;
327f17e5a37SMatt Evans 	uint32_t nr, server, priority;
328f17e5a37SMatt Evans 
329f17e5a37SMatt Evans 	if ((nargs != 3) || (nret != 1)) {
330f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
331f17e5a37SMatt Evans 		return;
332f17e5a37SMatt Evans 	}
333f17e5a37SMatt Evans 
334f17e5a37SMatt Evans 	nr = rtas_ld(vcpu->kvm, args, 0);
335f17e5a37SMatt Evans 	server = rtas_ld(vcpu->kvm, args, 1);
336f17e5a37SMatt Evans 	priority = rtas_ld(vcpu->kvm, args, 2);
337f17e5a37SMatt Evans 
338f17e5a37SMatt Evans 	xics_dprintf("rtas_set_xive(%x,%x,%x)\n", nr, server, priority);
339f17e5a37SMatt Evans 	if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
340f17e5a37SMatt Evans 	    || (priority > 0xff)) {
341f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
342f17e5a37SMatt Evans 		return;
343f17e5a37SMatt Evans 	}
344f17e5a37SMatt Evans 
345f17e5a37SMatt Evans 	ics_write_xive_msi(ics, nr, server, priority);
346f17e5a37SMatt Evans 
347f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
348f17e5a37SMatt Evans }
349f17e5a37SMatt Evans 
rtas_get_xive(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)350f17e5a37SMatt Evans static void rtas_get_xive(struct kvm_cpu *vcpu, uint32_t token,
351f17e5a37SMatt Evans 			  uint32_t nargs, target_ulong args,
352f17e5a37SMatt Evans 			  uint32_t nret, target_ulong rets)
353f17e5a37SMatt Evans {
35442ac24f9SSasha Levin 	struct ics_state *ics = vcpu->kvm->arch.icp->ics;
355f17e5a37SMatt Evans 	uint32_t nr;
356f17e5a37SMatt Evans 
357f17e5a37SMatt Evans 	if ((nargs != 1) || (nret != 3)) {
358f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
359f17e5a37SMatt Evans 		return;
360f17e5a37SMatt Evans 	}
361f17e5a37SMatt Evans 
362f17e5a37SMatt Evans 	nr = rtas_ld(vcpu->kvm, args, 0);
363f17e5a37SMatt Evans 
364f17e5a37SMatt Evans 	if (!ics_valid_irq(ics, nr)) {
365f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
366f17e5a37SMatt Evans 		return;
367f17e5a37SMatt Evans 	}
368f17e5a37SMatt Evans 
369f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
370f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 1, ics->irqs[nr - ics->offset].server);
371f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 2, ics->irqs[nr - ics->offset].priority);
372f17e5a37SMatt Evans }
373f17e5a37SMatt Evans 
rtas_int_off(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)374f17e5a37SMatt Evans static void rtas_int_off(struct kvm_cpu *vcpu, uint32_t token,
375f17e5a37SMatt Evans 			 uint32_t nargs, target_ulong args,
376f17e5a37SMatt Evans 			 uint32_t nret, target_ulong rets)
377f17e5a37SMatt Evans {
37842ac24f9SSasha Levin 	struct ics_state *ics = vcpu->kvm->arch.icp->ics;
379f17e5a37SMatt Evans 	uint32_t nr;
380f17e5a37SMatt Evans 
381f17e5a37SMatt Evans 	if ((nargs != 1) || (nret != 1)) {
382f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
383f17e5a37SMatt Evans 		return;
384f17e5a37SMatt Evans 	}
385f17e5a37SMatt Evans 
386f17e5a37SMatt Evans 	nr = rtas_ld(vcpu->kvm, args, 0);
387f17e5a37SMatt Evans 
388f17e5a37SMatt Evans 	if (!ics_valid_irq(ics, nr)) {
389f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
390f17e5a37SMatt Evans 		return;
391f17e5a37SMatt Evans 	}
392f17e5a37SMatt Evans 
393f17e5a37SMatt Evans 	/* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
394f17e5a37SMatt Evans 
395f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
396f17e5a37SMatt Evans }
397f17e5a37SMatt Evans 
rtas_int_on(struct kvm_cpu * vcpu,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)398f17e5a37SMatt Evans static void rtas_int_on(struct kvm_cpu *vcpu, uint32_t token,
399f17e5a37SMatt Evans 			uint32_t nargs, target_ulong args,
400f17e5a37SMatt Evans 			uint32_t nret, target_ulong rets)
401f17e5a37SMatt Evans {
40242ac24f9SSasha Levin 	struct ics_state *ics = vcpu->kvm->arch.icp->ics;
403f17e5a37SMatt Evans 	uint32_t nr;
404f17e5a37SMatt Evans 
405f17e5a37SMatt Evans 	if ((nargs != 1) || (nret != 1)) {
406f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
407f17e5a37SMatt Evans 		return;
408f17e5a37SMatt Evans 	}
409f17e5a37SMatt Evans 
410f17e5a37SMatt Evans 	nr = rtas_ld(vcpu->kvm, args, 0);
411f17e5a37SMatt Evans 
412f17e5a37SMatt Evans 	if (!ics_valid_irq(ics, nr)) {
413f17e5a37SMatt Evans 		rtas_st(vcpu->kvm, rets, 0, -3);
414f17e5a37SMatt Evans 		return;
415f17e5a37SMatt Evans 	}
416f17e5a37SMatt Evans 
417f17e5a37SMatt Evans 	/* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
418f17e5a37SMatt Evans 
419f17e5a37SMatt Evans 	rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
420f17e5a37SMatt Evans }
421f17e5a37SMatt Evans 
xics_init(struct kvm * kvm)422e016c60dSMichael Ellerman static int xics_init(struct kvm *kvm)
423f17e5a37SMatt Evans {
424f17e5a37SMatt Evans 	unsigned int i;
425f17e5a37SMatt Evans 	struct icp_state *icp;
426f17e5a37SMatt Evans 	struct ics_state *ics;
427e016c60dSMichael Ellerman 	int j;
428f17e5a37SMatt Evans 
429f17e5a37SMatt Evans 	icp = malloc(sizeof(*icp));
430e54ababaSMichael Ellerman 	icp->nr_servers = kvm->nrcpus;
431f17e5a37SMatt Evans 	icp->ss = malloc(icp->nr_servers * sizeof(struct icp_server_state));
432f17e5a37SMatt Evans 
433f17e5a37SMatt Evans 	for (i = 0; i < icp->nr_servers; i++) {
434f17e5a37SMatt Evans 		icp->ss[i].xirr = 0;
435f17e5a37SMatt Evans 		icp->ss[i].pending_priority = 0;
436f17e5a37SMatt Evans 		icp->ss[i].cpu = 0;
437f17e5a37SMatt Evans 		icp->ss[i].mfrr = 0xff;
438f17e5a37SMatt Evans 	}
439f17e5a37SMatt Evans 
440f17e5a37SMatt Evans 	/*
441f17e5a37SMatt Evans 	 * icp->ss[env->cpu_index].cpu is set by CPUs calling in to
442f17e5a37SMatt Evans 	 * xics_cpu_register().
443f17e5a37SMatt Evans 	 */
444f17e5a37SMatt Evans 
445f17e5a37SMatt Evans 	ics = malloc(sizeof(*ics));
446e016c60dSMichael Ellerman 	ics->nr_irqs = XICS_NUM_IRQS;
447f17e5a37SMatt Evans 	ics->offset = XICS_IRQ_OFFSET;
448e016c60dSMichael Ellerman 	ics->irqs = malloc(ics->nr_irqs * sizeof(struct ics_irq_state));
449f17e5a37SMatt Evans 
450f17e5a37SMatt Evans 	icp->ics = ics;
451f17e5a37SMatt Evans 	ics->icp = icp;
452f17e5a37SMatt Evans 
453e016c60dSMichael Ellerman 	for (i = 0; i < ics->nr_irqs; i++) {
454f17e5a37SMatt Evans 		ics->irqs[i].server = 0;
455f17e5a37SMatt Evans 		ics->irqs[i].priority = 0xff;
456f17e5a37SMatt Evans 		ics->irqs[i].saved_priority = 0xff;
457f17e5a37SMatt Evans 		ics->irqs[i].rejected = 0;
458f17e5a37SMatt Evans 		ics->irqs[i].masked_pending = 0;
459f17e5a37SMatt Evans 	}
460f17e5a37SMatt Evans 
461f17e5a37SMatt Evans 	spapr_register_hypercall(H_CPPR, h_cppr);
462f17e5a37SMatt Evans 	spapr_register_hypercall(H_IPI, h_ipi);
463f17e5a37SMatt Evans 	spapr_register_hypercall(H_XIRR, h_xirr);
464f17e5a37SMatt Evans 	spapr_register_hypercall(H_EOI, h_eoi);
465f17e5a37SMatt Evans 
466f17e5a37SMatt Evans 	spapr_rtas_register("ibm,set-xive", rtas_set_xive);
467f17e5a37SMatt Evans 	spapr_rtas_register("ibm,get-xive", rtas_get_xive);
468f17e5a37SMatt Evans 	spapr_rtas_register("ibm,int-off", rtas_int_off);
469f17e5a37SMatt Evans 	spapr_rtas_register("ibm,int-on", rtas_int_on);
470f17e5a37SMatt Evans 
471e016c60dSMichael Ellerman 	for (j = 0; j < kvm->nrcpus; j++) {
472e016c60dSMichael Ellerman 		struct kvm_cpu *vcpu = kvm->cpus[j];
473e016c60dSMichael Ellerman 
474e016c60dSMichael Ellerman 		if (vcpu->cpu_id >= icp->nr_servers)
475e016c60dSMichael Ellerman 			die("Invalid server number for cpuid %ld\n", vcpu->cpu_id);
476e016c60dSMichael Ellerman 
477e016c60dSMichael Ellerman 		icp->ss[vcpu->cpu_id].cpu = vcpu;
478f17e5a37SMatt Evans 	}
479f17e5a37SMatt Evans 
480e016c60dSMichael Ellerman 	kvm->arch.icp = icp;
481e016c60dSMichael Ellerman 
482e016c60dSMichael Ellerman 	return 0;
483e016c60dSMichael Ellerman }
48461c003c9SMichael Neuling dev_base_init(xics_init);
485e016c60dSMichael Ellerman 
486e016c60dSMichael Ellerman 
kvm__irq_line(struct kvm * kvm,int irq,int level)487f17e5a37SMatt Evans void kvm__irq_line(struct kvm *kvm, int irq, int level)
488f17e5a37SMatt Evans {
489f17e5a37SMatt Evans 	/*
490f17e5a37SMatt Evans 	 * Route event to ICS, which routes to ICP, which eventually does a
491f17e5a37SMatt Evans 	 * kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1)
492f17e5a37SMatt Evans 	 */
493f17e5a37SMatt Evans 	xics_dprintf("Raising IRQ %d -> %d\n", irq, level);
49442ac24f9SSasha Levin 	ics_set_irq_msi(kvm->arch.icp->ics, irq - kvm->arch.icp->ics->offset, level);
495f17e5a37SMatt Evans }
496