|
|
1.1 root 1: /*
2: * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
3: *
4: * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
5: *
6: * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
7: *
8: * Permission is hereby granted, free of charge, to any person obtaining a copy
9: * of this software and associated documentation files (the "Software"), to deal
10: * in the Software without restriction, including without limitation the rights
11: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12: * copies of the Software, and to permit persons to whom the Software is
13: * furnished to do so, subject to the following conditions:
14: *
15: * The above copyright notice and this permission notice shall be included in
16: * all copies or substantial portions of the Software.
17: *
18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24: * THE SOFTWARE.
25: *
26: */
27:
28: #include "hw.h"
29: #include "hw/spapr.h"
30: #include "hw/xics.h"
31:
32: /*
33: * ICP: Presentation layer
34: */
35:
36: struct icp_server_state {
37: uint32_t xirr;
38: uint8_t pending_priority;
39: uint8_t mfrr;
40: qemu_irq output;
41: };
42:
43: #define XISR_MASK 0x00ffffff
44: #define CPPR_MASK 0xff000000
45:
46: #define XISR(ss) (((ss)->xirr) & XISR_MASK)
47: #define CPPR(ss) (((ss)->xirr) >> 24)
48:
49: struct ics_state;
50:
51: struct icp_state {
52: long nr_servers;
53: struct icp_server_state *ss;
54: struct ics_state *ics;
55: };
56:
57: static void ics_reject(struct ics_state *ics, int nr);
58: static void ics_resend(struct ics_state *ics);
59: static void ics_eoi(struct ics_state *ics, int nr);
60:
61: static void icp_check_ipi(struct icp_state *icp, int server)
62: {
63: struct icp_server_state *ss = icp->ss + server;
64:
65: if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
66: return;
67: }
68:
69: if (XISR(ss)) {
70: ics_reject(icp->ics, XISR(ss));
71: }
72:
73: ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
74: ss->pending_priority = ss->mfrr;
75: qemu_irq_raise(ss->output);
76: }
77:
78: static void icp_resend(struct icp_state *icp, int server)
79: {
80: struct icp_server_state *ss = icp->ss + server;
81:
82: if (ss->mfrr < CPPR(ss)) {
83: icp_check_ipi(icp, server);
84: }
85: ics_resend(icp->ics);
86: }
87:
88: static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
89: {
90: struct icp_server_state *ss = icp->ss + server;
91: uint8_t old_cppr;
92: uint32_t old_xisr;
93:
94: old_cppr = CPPR(ss);
95: ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
96:
97: if (cppr < old_cppr) {
98: if (XISR(ss) && (cppr <= ss->pending_priority)) {
99: old_xisr = XISR(ss);
100: ss->xirr &= ~XISR_MASK; /* Clear XISR */
101: qemu_irq_lower(ss->output);
102: ics_reject(icp->ics, old_xisr);
103: }
104: } else {
105: if (!XISR(ss)) {
106: icp_resend(icp, server);
107: }
108: }
109: }
110:
111: static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
112: {
113: struct icp_server_state *ss = icp->ss + nr;
114:
115: ss->mfrr = mfrr;
116: if (mfrr < CPPR(ss)) {
117: icp_check_ipi(icp, nr);
118: }
119: }
120:
121: static uint32_t icp_accept(struct icp_server_state *ss)
122: {
123: uint32_t xirr;
124:
125: qemu_irq_lower(ss->output);
126: xirr = ss->xirr;
127: ss->xirr = ss->pending_priority << 24;
128: return xirr;
129: }
130:
131: static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
132: {
133: struct icp_server_state *ss = icp->ss + server;
134:
135: ics_eoi(icp->ics, xirr & XISR_MASK);
136: /* Send EOI -> ICS */
137: ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
138: if (!XISR(ss)) {
139: icp_resend(icp, server);
140: }
141: }
142:
143: static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
144: {
145: struct icp_server_state *ss = icp->ss + server;
146:
147: if ((priority >= CPPR(ss))
148: || (XISR(ss) && (ss->pending_priority <= priority))) {
149: ics_reject(icp->ics, nr);
150: } else {
151: if (XISR(ss)) {
152: ics_reject(icp->ics, XISR(ss));
153: }
154: ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
155: ss->pending_priority = priority;
156: qemu_irq_raise(ss->output);
157: }
158: }
159:
160: /*
161: * ICS: Source layer
162: */
163:
164: struct ics_irq_state {
165: int server;
166: uint8_t priority;
167: uint8_t saved_priority;
168: /* int pending:1; */
169: /* int presented:1; */
170: int rejected:1;
171: int masked_pending:1;
172: };
173:
174: struct ics_state {
175: int nr_irqs;
176: int offset;
177: qemu_irq *qirqs;
178: struct ics_irq_state *irqs;
179: struct icp_state *icp;
180: };
181:
182: static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
183: {
184: return (nr >= ics->offset)
185: && (nr < (ics->offset + ics->nr_irqs));
186: }
187:
1.1.1.2 ! root 188: static void ics_set_irq_msi(void *opaque, int srcno, int val)
1.1 root 189: {
190: struct ics_state *ics = (struct ics_state *)opaque;
1.1.1.2 ! root 191: struct ics_irq_state *irq = ics->irqs + srcno;
1.1 root 192:
193: if (val) {
194: if (irq->priority == 0xff) {
195: irq->masked_pending = 1;
196: /* masked pending */ ;
197: } else {
1.1.1.2 ! root 198: icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
1.1 root 199: }
200: }
201: }
202:
203: static void ics_reject_msi(struct ics_state *ics, int nr)
204: {
205: struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
206:
207: irq->rejected = 1;
208: }
209:
210: static void ics_resend_msi(struct ics_state *ics)
211: {
212: int i;
213:
214: for (i = 0; i < ics->nr_irqs; i++) {
215: struct ics_irq_state *irq = ics->irqs + i;
216:
217: /* FIXME: filter by server#? */
218: if (irq->rejected) {
219: irq->rejected = 0;
220: if (irq->priority != 0xff) {
221: icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
222: }
223: }
224: }
225: }
226:
227: static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
228: uint8_t priority)
229: {
1.1.1.2 ! root 230: struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
1.1 root 231:
232: irq->server = server;
233: irq->priority = priority;
234:
235: if (!irq->masked_pending || (priority == 0xff)) {
236: return;
237: }
238:
239: irq->masked_pending = 0;
1.1.1.2 ! root 240: icp_irq(ics->icp, server, nr, priority);
1.1 root 241: }
242:
243: static void ics_reject(struct ics_state *ics, int nr)
244: {
245: ics_reject_msi(ics, nr);
246: }
247:
248: static void ics_resend(struct ics_state *ics)
249: {
250: ics_resend_msi(ics);
251: }
252:
253: static void ics_eoi(struct ics_state *ics, int nr)
254: {
255: }
256:
257: /*
258: * Exported functions
259: */
260:
261: qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
262: {
263: if ((irq < icp->ics->offset)
264: || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
265: return NULL;
266: }
267:
268: return icp->ics->qirqs[irq - icp->ics->offset];
269: }
270:
271: static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr,
272: target_ulong opcode, target_ulong *args)
273: {
274: target_ulong cppr = args[0];
275:
276: icp_set_cppr(spapr->icp, env->cpu_index, cppr);
277: return H_SUCCESS;
278: }
279:
280: static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr,
281: target_ulong opcode, target_ulong *args)
282: {
283: target_ulong server = args[0];
284: target_ulong mfrr = args[1];
285:
286: if (server >= spapr->icp->nr_servers) {
287: return H_PARAMETER;
288: }
289:
290: icp_set_mfrr(spapr->icp, server, mfrr);
291: return H_SUCCESS;
292:
293: }
294:
295: static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr,
296: target_ulong opcode, target_ulong *args)
297: {
298: uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index);
299:
300: args[0] = xirr;
301: return H_SUCCESS;
302: }
303:
304: static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr,
305: target_ulong opcode, target_ulong *args)
306: {
307: target_ulong xirr = args[0];
308:
309: icp_eoi(spapr->icp, env->cpu_index, xirr);
310: return H_SUCCESS;
311: }
312:
313: static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
314: uint32_t nargs, target_ulong args,
315: uint32_t nret, target_ulong rets)
316: {
317: struct ics_state *ics = spapr->icp->ics;
318: uint32_t nr, server, priority;
319:
320: if ((nargs != 3) || (nret != 1)) {
321: rtas_st(rets, 0, -3);
322: return;
323: }
324:
325: nr = rtas_ld(args, 0);
326: server = rtas_ld(args, 1);
327: priority = rtas_ld(args, 2);
328:
329: if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
330: || (priority > 0xff)) {
331: rtas_st(rets, 0, -3);
332: return;
333: }
334:
1.1.1.2 ! root 335: ics_write_xive_msi(ics, nr, server, priority);
1.1 root 336:
337: rtas_st(rets, 0, 0); /* Success */
338: }
339:
340: static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
341: uint32_t nargs, target_ulong args,
342: uint32_t nret, target_ulong rets)
343: {
344: struct ics_state *ics = spapr->icp->ics;
345: uint32_t nr;
346:
347: if ((nargs != 1) || (nret != 3)) {
348: rtas_st(rets, 0, -3);
349: return;
350: }
351:
352: nr = rtas_ld(args, 0);
353:
354: if (!ics_valid_irq(ics, nr)) {
355: rtas_st(rets, 0, -3);
356: return;
357: }
358:
359: rtas_st(rets, 0, 0); /* Success */
360: rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
361: rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
362: }
363:
364: static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
365: uint32_t nargs, target_ulong args,
366: uint32_t nret, target_ulong rets)
367: {
368: struct ics_state *ics = spapr->icp->ics;
369: uint32_t nr;
370:
371: if ((nargs != 1) || (nret != 1)) {
372: rtas_st(rets, 0, -3);
373: return;
374: }
375:
376: nr = rtas_ld(args, 0);
377:
378: if (!ics_valid_irq(ics, nr)) {
379: rtas_st(rets, 0, -3);
380: return;
381: }
382:
383: /* This is a NOP for now, since the described PAPR semantics don't
384: * seem to gel with what Linux does */
385: #if 0
386: struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
387:
388: irq->saved_priority = irq->priority;
1.1.1.2 ! root 389: ics_write_xive_msi(xics, nr, irq->server, 0xff);
1.1 root 390: #endif
391:
392: rtas_st(rets, 0, 0); /* Success */
393: }
394:
395: static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
396: uint32_t nargs, target_ulong args,
397: uint32_t nret, target_ulong rets)
398: {
399: struct ics_state *ics = spapr->icp->ics;
400: uint32_t nr;
401:
402: if ((nargs != 1) || (nret != 1)) {
403: rtas_st(rets, 0, -3);
404: return;
405: }
406:
407: nr = rtas_ld(args, 0);
408:
409: if (!ics_valid_irq(ics, nr)) {
410: rtas_st(rets, 0, -3);
411: return;
412: }
413:
414: /* This is a NOP for now, since the described PAPR semantics don't
415: * seem to gel with what Linux does */
416: #if 0
417: struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
418:
1.1.1.2 ! root 419: ics_write_xive_msi(xics, nr, irq->server, irq->saved_priority);
1.1 root 420: #endif
421:
422: rtas_st(rets, 0, 0); /* Success */
423: }
424:
425: struct icp_state *xics_system_init(int nr_irqs)
426: {
427: CPUState *env;
428: int max_server_num;
429: int i;
430: struct icp_state *icp;
431: struct ics_state *ics;
432:
433: max_server_num = -1;
434: for (env = first_cpu; env != NULL; env = env->next_cpu) {
435: if (env->cpu_index > max_server_num) {
436: max_server_num = env->cpu_index;
437: }
438: }
439:
1.1.1.2 ! root 440: icp = g_malloc0(sizeof(*icp));
1.1 root 441: icp->nr_servers = max_server_num + 1;
1.1.1.2 ! root 442: icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
1.1 root 443:
444: for (i = 0; i < icp->nr_servers; i++) {
445: icp->ss[i].mfrr = 0xff;
446: }
447:
448: for (env = first_cpu; env != NULL; env = env->next_cpu) {
449: struct icp_server_state *ss = &icp->ss[env->cpu_index];
450:
451: switch (PPC_INPUT(env)) {
452: case PPC_FLAGS_INPUT_POWER7:
453: ss->output = env->irq_inputs[POWER7_INPUT_INT];
454: break;
455:
456: case PPC_FLAGS_INPUT_970:
457: ss->output = env->irq_inputs[PPC970_INPUT_INT];
458: break;
459:
460: default:
461: hw_error("XICS interrupt model does not support this CPU bus "
462: "model\n");
463: exit(1);
464: }
465: }
466:
1.1.1.2 ! root 467: ics = g_malloc0(sizeof(*ics));
1.1 root 468: ics->nr_irqs = nr_irqs;
469: ics->offset = 16;
1.1.1.2 ! root 470: ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
1.1 root 471:
472: icp->ics = ics;
473: ics->icp = icp;
474:
475: for (i = 0; i < nr_irqs; i++) {
476: ics->irqs[i].priority = 0xff;
477: ics->irqs[i].saved_priority = 0xff;
478: }
479:
480: ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
481:
482: spapr_register_hypercall(H_CPPR, h_cppr);
483: spapr_register_hypercall(H_IPI, h_ipi);
484: spapr_register_hypercall(H_XIRR, h_xirr);
485: spapr_register_hypercall(H_EOI, h_eoi);
486:
487: spapr_rtas_register("ibm,set-xive", rtas_set_xive);
488: spapr_rtas_register("ibm,get-xive", rtas_get_xive);
489: spapr_rtas_register("ibm,int-off", rtas_int_off);
490: spapr_rtas_register("ibm,int-on", rtas_int_on);
491:
492: return icp;
493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.