Statistics
| Branch: | Revision:

root / hw / ppc / xics.c @ 210b580b

History | View | Annotate | Download (15.2 kB)

1 b5cec4c5 David Gibson
/*
2 b5cec4c5 David Gibson
 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
3 b5cec4c5 David Gibson
 *
4 b5cec4c5 David Gibson
 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
5 b5cec4c5 David Gibson
 *
6 b5cec4c5 David Gibson
 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
7 b5cec4c5 David Gibson
 *
8 b5cec4c5 David Gibson
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 b5cec4c5 David Gibson
 * of this software and associated documentation files (the "Software"), to deal
10 b5cec4c5 David Gibson
 * in the Software without restriction, including without limitation the rights
11 b5cec4c5 David Gibson
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 b5cec4c5 David Gibson
 * copies of the Software, and to permit persons to whom the Software is
13 b5cec4c5 David Gibson
 * furnished to do so, subject to the following conditions:
14 b5cec4c5 David Gibson
 *
15 b5cec4c5 David Gibson
 * The above copyright notice and this permission notice shall be included in
16 b5cec4c5 David Gibson
 * all copies or substantial portions of the Software.
17 b5cec4c5 David Gibson
 *
18 b5cec4c5 David Gibson
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 b5cec4c5 David Gibson
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 b5cec4c5 David Gibson
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 b5cec4c5 David Gibson
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 b5cec4c5 David Gibson
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 b5cec4c5 David Gibson
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 b5cec4c5 David Gibson
 * THE SOFTWARE.
25 b5cec4c5 David Gibson
 *
26 b5cec4c5 David Gibson
 */
27 b5cec4c5 David Gibson
28 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
29 500efa23 David Gibson
#include "trace.h"
30 0d09e41a Paolo Bonzini
#include "hw/ppc/spapr.h"
31 0d09e41a Paolo Bonzini
#include "hw/ppc/xics.h"
32 b5cec4c5 David Gibson
33 b5cec4c5 David Gibson
/*
34 b5cec4c5 David Gibson
 * ICP: Presentation layer
35 b5cec4c5 David Gibson
 */
36 b5cec4c5 David Gibson
37 b5cec4c5 David Gibson
struct icp_server_state {
38 b5cec4c5 David Gibson
    uint32_t xirr;
39 b5cec4c5 David Gibson
    uint8_t pending_priority;
40 b5cec4c5 David Gibson
    uint8_t mfrr;
41 b5cec4c5 David Gibson
    qemu_irq output;
42 b5cec4c5 David Gibson
};
43 b5cec4c5 David Gibson
44 b5cec4c5 David Gibson
#define XISR_MASK  0x00ffffff
45 b5cec4c5 David Gibson
#define CPPR_MASK  0xff000000
46 b5cec4c5 David Gibson
47 b5cec4c5 David Gibson
#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
48 b5cec4c5 David Gibson
#define CPPR(ss)   (((ss)->xirr) >> 24)
49 b5cec4c5 David Gibson
50 b5cec4c5 David Gibson
struct ics_state;
51 b5cec4c5 David Gibson
52 b5cec4c5 David Gibson
struct icp_state {
53 b5cec4c5 David Gibson
    long nr_servers;
54 b5cec4c5 David Gibson
    struct icp_server_state *ss;
55 b5cec4c5 David Gibson
    struct ics_state *ics;
56 b5cec4c5 David Gibson
};
57 b5cec4c5 David Gibson
58 b5cec4c5 David Gibson
static void ics_reject(struct ics_state *ics, int nr);
59 b5cec4c5 David Gibson
static void ics_resend(struct ics_state *ics);
60 b5cec4c5 David Gibson
static void ics_eoi(struct ics_state *ics, int nr);
61 b5cec4c5 David Gibson
62 b5cec4c5 David Gibson
static void icp_check_ipi(struct icp_state *icp, int server)
63 b5cec4c5 David Gibson
{
64 b5cec4c5 David Gibson
    struct icp_server_state *ss = icp->ss + server;
65 b5cec4c5 David Gibson
66 b5cec4c5 David Gibson
    if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
67 b5cec4c5 David Gibson
        return;
68 b5cec4c5 David Gibson
    }
69 b5cec4c5 David Gibson
70 500efa23 David Gibson
    trace_xics_icp_check_ipi(server, ss->mfrr);
71 500efa23 David Gibson
72 b5cec4c5 David Gibson
    if (XISR(ss)) {
73 b5cec4c5 David Gibson
        ics_reject(icp->ics, XISR(ss));
74 b5cec4c5 David Gibson
    }
75 b5cec4c5 David Gibson
76 b5cec4c5 David Gibson
    ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
77 b5cec4c5 David Gibson
    ss->pending_priority = ss->mfrr;
78 b5cec4c5 David Gibson
    qemu_irq_raise(ss->output);
79 b5cec4c5 David Gibson
}
80 b5cec4c5 David Gibson
81 b5cec4c5 David Gibson
static void icp_resend(struct icp_state *icp, int server)
82 b5cec4c5 David Gibson
{
83 b5cec4c5 David Gibson
    struct icp_server_state *ss = icp->ss + server;
84 b5cec4c5 David Gibson
85 b5cec4c5 David Gibson
    if (ss->mfrr < CPPR(ss)) {
86 b5cec4c5 David Gibson
        icp_check_ipi(icp, server);
87 b5cec4c5 David Gibson
    }
88 b5cec4c5 David Gibson
    ics_resend(icp->ics);
89 b5cec4c5 David Gibson
}
90 b5cec4c5 David Gibson
91 b5cec4c5 David Gibson
static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
92 b5cec4c5 David Gibson
{
93 b5cec4c5 David Gibson
    struct icp_server_state *ss = icp->ss + server;
94 b5cec4c5 David Gibson
    uint8_t old_cppr;
95 b5cec4c5 David Gibson
    uint32_t old_xisr;
96 b5cec4c5 David Gibson
97 b5cec4c5 David Gibson
    old_cppr = CPPR(ss);
98 b5cec4c5 David Gibson
    ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
99 b5cec4c5 David Gibson
100 b5cec4c5 David Gibson
    if (cppr < old_cppr) {
101 b5cec4c5 David Gibson
        if (XISR(ss) && (cppr <= ss->pending_priority)) {
102 b5cec4c5 David Gibson
            old_xisr = XISR(ss);
103 b5cec4c5 David Gibson
            ss->xirr &= ~XISR_MASK; /* Clear XISR */
104 e03c902c David Gibson
            ss->pending_priority = 0xff;
105 b5cec4c5 David Gibson
            qemu_irq_lower(ss->output);
106 b5cec4c5 David Gibson
            ics_reject(icp->ics, old_xisr);
107 b5cec4c5 David Gibson
        }
108 b5cec4c5 David Gibson
    } else {
109 b5cec4c5 David Gibson
        if (!XISR(ss)) {
110 b5cec4c5 David Gibson
            icp_resend(icp, server);
111 b5cec4c5 David Gibson
        }
112 b5cec4c5 David Gibson
    }
113 b5cec4c5 David Gibson
}
114 b5cec4c5 David Gibson
115 bf0175de David Gibson
static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr)
116 b5cec4c5 David Gibson
{
117 bf0175de David Gibson
    struct icp_server_state *ss = icp->ss + server;
118 b5cec4c5 David Gibson
119 b5cec4c5 David Gibson
    ss->mfrr = mfrr;
120 b5cec4c5 David Gibson
    if (mfrr < CPPR(ss)) {
121 bf0175de David Gibson
        icp_check_ipi(icp, server);
122 b5cec4c5 David Gibson
    }
123 b5cec4c5 David Gibson
}
124 b5cec4c5 David Gibson
125 b5cec4c5 David Gibson
static uint32_t icp_accept(struct icp_server_state *ss)
126 b5cec4c5 David Gibson
{
127 500efa23 David Gibson
    uint32_t xirr = ss->xirr;
128 b5cec4c5 David Gibson
129 b5cec4c5 David Gibson
    qemu_irq_lower(ss->output);
130 b5cec4c5 David Gibson
    ss->xirr = ss->pending_priority << 24;
131 e03c902c David Gibson
    ss->pending_priority = 0xff;
132 500efa23 David Gibson
133 500efa23 David Gibson
    trace_xics_icp_accept(xirr, ss->xirr);
134 500efa23 David Gibson
135 b5cec4c5 David Gibson
    return xirr;
136 b5cec4c5 David Gibson
}
137 b5cec4c5 David Gibson
138 b5cec4c5 David Gibson
static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
139 b5cec4c5 David Gibson
{
140 b5cec4c5 David Gibson
    struct icp_server_state *ss = icp->ss + server;
141 b5cec4c5 David Gibson
142 b5cec4c5 David Gibson
    /* Send EOI -> ICS */
143 b5cec4c5 David Gibson
    ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
144 500efa23 David Gibson
    trace_xics_icp_eoi(server, xirr, ss->xirr);
145 d07fee7e David Gibson
    ics_eoi(icp->ics, xirr & XISR_MASK);
146 b5cec4c5 David Gibson
    if (!XISR(ss)) {
147 b5cec4c5 David Gibson
        icp_resend(icp, server);
148 b5cec4c5 David Gibson
    }
149 b5cec4c5 David Gibson
}
150 b5cec4c5 David Gibson
151 b5cec4c5 David Gibson
static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
152 b5cec4c5 David Gibson
{
153 b5cec4c5 David Gibson
    struct icp_server_state *ss = icp->ss + server;
154 b5cec4c5 David Gibson
155 500efa23 David Gibson
    trace_xics_icp_irq(server, nr, priority);
156 500efa23 David Gibson
157 b5cec4c5 David Gibson
    if ((priority >= CPPR(ss))
158 b5cec4c5 David Gibson
        || (XISR(ss) && (ss->pending_priority <= priority))) {
159 b5cec4c5 David Gibson
        ics_reject(icp->ics, nr);
160 b5cec4c5 David Gibson
    } else {
161 b5cec4c5 David Gibson
        if (XISR(ss)) {
162 b5cec4c5 David Gibson
            ics_reject(icp->ics, XISR(ss));
163 b5cec4c5 David Gibson
        }
164 b5cec4c5 David Gibson
        ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
165 b5cec4c5 David Gibson
        ss->pending_priority = priority;
166 500efa23 David Gibson
        trace_xics_icp_raise(ss->xirr, ss->pending_priority);
167 b5cec4c5 David Gibson
        qemu_irq_raise(ss->output);
168 b5cec4c5 David Gibson
    }
169 b5cec4c5 David Gibson
}
170 b5cec4c5 David Gibson
171 b5cec4c5 David Gibson
/*
172 b5cec4c5 David Gibson
 * ICS: Source layer
173 b5cec4c5 David Gibson
 */
174 b5cec4c5 David Gibson
175 b5cec4c5 David Gibson
struct ics_irq_state {
176 b5cec4c5 David Gibson
    int server;
177 b5cec4c5 David Gibson
    uint8_t priority;
178 b5cec4c5 David Gibson
    uint8_t saved_priority;
179 98ca8c02 David Gibson
#define XICS_STATUS_ASSERTED           0x1
180 98ca8c02 David Gibson
#define XICS_STATUS_SENT               0x2
181 98ca8c02 David Gibson
#define XICS_STATUS_REJECTED           0x4
182 98ca8c02 David Gibson
#define XICS_STATUS_MASKED_PENDING     0x8
183 98ca8c02 David Gibson
    uint8_t status;
184 b5cec4c5 David Gibson
};
185 b5cec4c5 David Gibson
186 b5cec4c5 David Gibson
struct ics_state {
187 b5cec4c5 David Gibson
    int nr_irqs;
188 b5cec4c5 David Gibson
    int offset;
189 b5cec4c5 David Gibson
    qemu_irq *qirqs;
190 22a2611c David Gibson
    bool *islsi;
191 b5cec4c5 David Gibson
    struct ics_irq_state *irqs;
192 b5cec4c5 David Gibson
    struct icp_state *icp;
193 b5cec4c5 David Gibson
};
194 b5cec4c5 David Gibson
195 b5cec4c5 David Gibson
static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
196 b5cec4c5 David Gibson
{
197 b5cec4c5 David Gibson
    return (nr >= ics->offset)
198 b5cec4c5 David Gibson
        && (nr < (ics->offset + ics->nr_irqs));
199 b5cec4c5 David Gibson
}
200 b5cec4c5 David Gibson
201 d07fee7e David Gibson
static void resend_msi(struct ics_state *ics, int srcno)
202 d07fee7e David Gibson
{
203 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
204 d07fee7e David Gibson
205 d07fee7e David Gibson
    /* FIXME: filter by server#? */
206 98ca8c02 David Gibson
    if (irq->status & XICS_STATUS_REJECTED) {
207 98ca8c02 David Gibson
        irq->status &= ~XICS_STATUS_REJECTED;
208 d07fee7e David Gibson
        if (irq->priority != 0xff) {
209 d07fee7e David Gibson
            icp_irq(ics->icp, irq->server, srcno + ics->offset,
210 d07fee7e David Gibson
                    irq->priority);
211 d07fee7e David Gibson
        }
212 d07fee7e David Gibson
    }
213 d07fee7e David Gibson
}
214 d07fee7e David Gibson
215 d07fee7e David Gibson
static void resend_lsi(struct ics_state *ics, int srcno)
216 d07fee7e David Gibson
{
217 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
218 d07fee7e David Gibson
219 98ca8c02 David Gibson
    if ((irq->priority != 0xff)
220 98ca8c02 David Gibson
        && (irq->status & XICS_STATUS_ASSERTED)
221 98ca8c02 David Gibson
        && !(irq->status & XICS_STATUS_SENT)) {
222 98ca8c02 David Gibson
        irq->status |= XICS_STATUS_SENT;
223 d07fee7e David Gibson
        icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
224 d07fee7e David Gibson
    }
225 d07fee7e David Gibson
}
226 d07fee7e David Gibson
227 d07fee7e David Gibson
static void set_irq_msi(struct ics_state *ics, int srcno, int val)
228 b5cec4c5 David Gibson
{
229 cc67b9c8 David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
230 b5cec4c5 David Gibson
231 500efa23 David Gibson
    trace_xics_set_irq_msi(srcno, srcno + ics->offset);
232 500efa23 David Gibson
233 b5cec4c5 David Gibson
    if (val) {
234 b5cec4c5 David Gibson
        if (irq->priority == 0xff) {
235 98ca8c02 David Gibson
            irq->status |= XICS_STATUS_MASKED_PENDING;
236 500efa23 David Gibson
            trace_xics_masked_pending();
237 b5cec4c5 David Gibson
        } else  {
238 cc67b9c8 David Gibson
            icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
239 b5cec4c5 David Gibson
        }
240 b5cec4c5 David Gibson
    }
241 b5cec4c5 David Gibson
}
242 b5cec4c5 David Gibson
243 d07fee7e David Gibson
static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
244 b5cec4c5 David Gibson
{
245 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
246 b5cec4c5 David Gibson
247 500efa23 David Gibson
    trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
248 98ca8c02 David Gibson
    if (val) {
249 98ca8c02 David Gibson
        irq->status |= XICS_STATUS_ASSERTED;
250 98ca8c02 David Gibson
    } else {
251 98ca8c02 David Gibson
        irq->status &= ~XICS_STATUS_ASSERTED;
252 98ca8c02 David Gibson
    }
253 d07fee7e David Gibson
    resend_lsi(ics, srcno);
254 b5cec4c5 David Gibson
}
255 b5cec4c5 David Gibson
256 d07fee7e David Gibson
static void ics_set_irq(void *opaque, int srcno, int val)
257 b5cec4c5 David Gibson
{
258 d07fee7e David Gibson
    struct ics_state *ics = (struct ics_state *)opaque;
259 b5cec4c5 David Gibson
260 22a2611c David Gibson
    if (ics->islsi[srcno]) {
261 d07fee7e David Gibson
        set_irq_lsi(ics, srcno, val);
262 d07fee7e David Gibson
    } else {
263 d07fee7e David Gibson
        set_irq_msi(ics, srcno, val);
264 d07fee7e David Gibson
    }
265 d07fee7e David Gibson
}
266 b5cec4c5 David Gibson
267 d07fee7e David Gibson
static void write_xive_msi(struct ics_state *ics, int srcno)
268 d07fee7e David Gibson
{
269 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
270 d07fee7e David Gibson
271 98ca8c02 David Gibson
    if (!(irq->status & XICS_STATUS_MASKED_PENDING)
272 98ca8c02 David Gibson
        || (irq->priority == 0xff)) {
273 d07fee7e David Gibson
        return;
274 b5cec4c5 David Gibson
    }
275 d07fee7e David Gibson
276 98ca8c02 David Gibson
    irq->status &= ~XICS_STATUS_MASKED_PENDING;
277 d07fee7e David Gibson
    icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
278 b5cec4c5 David Gibson
}
279 b5cec4c5 David Gibson
280 d07fee7e David Gibson
static void write_xive_lsi(struct ics_state *ics, int srcno)
281 b5cec4c5 David Gibson
{
282 d07fee7e David Gibson
    resend_lsi(ics, srcno);
283 d07fee7e David Gibson
}
284 d07fee7e David Gibson
285 d07fee7e David Gibson
static void ics_write_xive(struct ics_state *ics, int nr, int server,
286 3fe719f4 David Gibson
                           uint8_t priority, uint8_t saved_priority)
287 d07fee7e David Gibson
{
288 d07fee7e David Gibson
    int srcno = nr - ics->offset;
289 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
290 b5cec4c5 David Gibson
291 b5cec4c5 David Gibson
    irq->server = server;
292 b5cec4c5 David Gibson
    irq->priority = priority;
293 3fe719f4 David Gibson
    irq->saved_priority = saved_priority;
294 b5cec4c5 David Gibson
295 500efa23 David Gibson
    trace_xics_ics_write_xive(nr, srcno, server, priority);
296 500efa23 David Gibson
297 22a2611c David Gibson
    if (ics->islsi[srcno]) {
298 d07fee7e David Gibson
        write_xive_lsi(ics, srcno);
299 d07fee7e David Gibson
    } else {
300 d07fee7e David Gibson
        write_xive_msi(ics, srcno);
301 b5cec4c5 David Gibson
    }
302 b5cec4c5 David Gibson
}
303 b5cec4c5 David Gibson
304 b5cec4c5 David Gibson
static void ics_reject(struct ics_state *ics, int nr)
305 b5cec4c5 David Gibson
{
306 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
307 d07fee7e David Gibson
308 500efa23 David Gibson
    trace_xics_ics_reject(nr, nr - ics->offset);
309 98ca8c02 David Gibson
    irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
310 98ca8c02 David Gibson
    irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
311 b5cec4c5 David Gibson
}
312 b5cec4c5 David Gibson
313 b5cec4c5 David Gibson
static void ics_resend(struct ics_state *ics)
314 b5cec4c5 David Gibson
{
315 d07fee7e David Gibson
    int i;
316 d07fee7e David Gibson
317 d07fee7e David Gibson
    for (i = 0; i < ics->nr_irqs; i++) {
318 d07fee7e David Gibson
        /* FIXME: filter by server#? */
319 22a2611c David Gibson
        if (ics->islsi[i]) {
320 d07fee7e David Gibson
            resend_lsi(ics, i);
321 d07fee7e David Gibson
        } else {
322 d07fee7e David Gibson
            resend_msi(ics, i);
323 d07fee7e David Gibson
        }
324 d07fee7e David Gibson
    }
325 b5cec4c5 David Gibson
}
326 b5cec4c5 David Gibson
327 b5cec4c5 David Gibson
static void ics_eoi(struct ics_state *ics, int nr)
328 b5cec4c5 David Gibson
{
329 d07fee7e David Gibson
    int srcno = nr - ics->offset;
330 d07fee7e David Gibson
    struct ics_irq_state *irq = ics->irqs + srcno;
331 d07fee7e David Gibson
332 500efa23 David Gibson
    trace_xics_ics_eoi(nr);
333 500efa23 David Gibson
334 22a2611c David Gibson
    if (ics->islsi[srcno]) {
335 98ca8c02 David Gibson
        irq->status &= ~XICS_STATUS_SENT;
336 d07fee7e David Gibson
    }
337 b5cec4c5 David Gibson
}
338 b5cec4c5 David Gibson
339 b5cec4c5 David Gibson
/*
340 b5cec4c5 David Gibson
 * Exported functions
341 b5cec4c5 David Gibson
 */
342 b5cec4c5 David Gibson
343 a307d594 Alexey Kardashevskiy
qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
344 b5cec4c5 David Gibson
{
345 1ecbbab4 David Gibson
    if (!ics_valid_irq(icp->ics, irq)) {
346 b5cec4c5 David Gibson
        return NULL;
347 b5cec4c5 David Gibson
    }
348 b5cec4c5 David Gibson
349 a307d594 Alexey Kardashevskiy
    return icp->ics->qirqs[irq - icp->ics->offset];
350 a307d594 Alexey Kardashevskiy
}
351 a307d594 Alexey Kardashevskiy
352 ff9d2afa David Gibson
void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
353 a307d594 Alexey Kardashevskiy
{
354 1ecbbab4 David Gibson
    assert(ics_valid_irq(icp->ics, irq));
355 d07fee7e David Gibson
356 22a2611c David Gibson
    icp->ics->islsi[irq - icp->ics->offset] = lsi;
357 b5cec4c5 David Gibson
}
358 b5cec4c5 David Gibson
359 b13ce26d Andreas Fรคrber
static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
360 b5cec4c5 David Gibson
                           target_ulong opcode, target_ulong *args)
361 b5cec4c5 David Gibson
{
362 55e5c285 Andreas Fรคrber
    CPUState *cs = CPU(cpu);
363 b5cec4c5 David Gibson
    target_ulong cppr = args[0];
364 b5cec4c5 David Gibson
365 55e5c285 Andreas Fรคrber
    icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
366 b5cec4c5 David Gibson
    return H_SUCCESS;
367 b5cec4c5 David Gibson
}
368 b5cec4c5 David Gibson
369 b13ce26d Andreas Fรคrber
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
370 b5cec4c5 David Gibson
                          target_ulong opcode, target_ulong *args)
371 b5cec4c5 David Gibson
{
372 b5cec4c5 David Gibson
    target_ulong server = args[0];
373 b5cec4c5 David Gibson
    target_ulong mfrr = args[1];
374 b5cec4c5 David Gibson
375 b5cec4c5 David Gibson
    if (server >= spapr->icp->nr_servers) {
376 b5cec4c5 David Gibson
        return H_PARAMETER;
377 b5cec4c5 David Gibson
    }
378 b5cec4c5 David Gibson
379 b5cec4c5 David Gibson
    icp_set_mfrr(spapr->icp, server, mfrr);
380 b5cec4c5 David Gibson
    return H_SUCCESS;
381 b5cec4c5 David Gibson
}
382 b5cec4c5 David Gibson
383 b13ce26d Andreas Fรคrber
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
384 b5cec4c5 David Gibson
                           target_ulong opcode, target_ulong *args)
385 b5cec4c5 David Gibson
{
386 55e5c285 Andreas Fรคrber
    CPUState *cs = CPU(cpu);
387 55e5c285 Andreas Fรคrber
    uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
388 b5cec4c5 David Gibson
389 b5cec4c5 David Gibson
    args[0] = xirr;
390 b5cec4c5 David Gibson
    return H_SUCCESS;
391 b5cec4c5 David Gibson
}
392 b5cec4c5 David Gibson
393 b13ce26d Andreas Fรคrber
static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
394 b5cec4c5 David Gibson
                          target_ulong opcode, target_ulong *args)
395 b5cec4c5 David Gibson
{
396 55e5c285 Andreas Fรคrber
    CPUState *cs = CPU(cpu);
397 b5cec4c5 David Gibson
    target_ulong xirr = args[0];
398 b5cec4c5 David Gibson
399 55e5c285 Andreas Fรคrber
    icp_eoi(spapr->icp, cs->cpu_index, xirr);
400 b5cec4c5 David Gibson
    return H_SUCCESS;
401 b5cec4c5 David Gibson
}
402 b5cec4c5 David Gibson
403 210b580b Anthony Liguori
static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
404 210b580b Anthony Liguori
                          uint32_t token,
405 b5cec4c5 David Gibson
                          uint32_t nargs, target_ulong args,
406 b5cec4c5 David Gibson
                          uint32_t nret, target_ulong rets)
407 b5cec4c5 David Gibson
{
408 b5cec4c5 David Gibson
    struct ics_state *ics = spapr->icp->ics;
409 b5cec4c5 David Gibson
    uint32_t nr, server, priority;
410 b5cec4c5 David Gibson
411 b5cec4c5 David Gibson
    if ((nargs != 3) || (nret != 1)) {
412 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
413 b5cec4c5 David Gibson
        return;
414 b5cec4c5 David Gibson
    }
415 b5cec4c5 David Gibson
416 b5cec4c5 David Gibson
    nr = rtas_ld(args, 0);
417 b5cec4c5 David Gibson
    server = rtas_ld(args, 1);
418 b5cec4c5 David Gibson
    priority = rtas_ld(args, 2);
419 b5cec4c5 David Gibson
420 b5cec4c5 David Gibson
    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
421 b5cec4c5 David Gibson
        || (priority > 0xff)) {
422 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
423 b5cec4c5 David Gibson
        return;
424 b5cec4c5 David Gibson
    }
425 b5cec4c5 David Gibson
426 3fe719f4 David Gibson
    ics_write_xive(ics, nr, server, priority, priority);
427 b5cec4c5 David Gibson
428 b5cec4c5 David Gibson
    rtas_st(rets, 0, 0); /* Success */
429 b5cec4c5 David Gibson
}
430 b5cec4c5 David Gibson
431 210b580b Anthony Liguori
static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
432 210b580b Anthony Liguori
                          uint32_t token,
433 b5cec4c5 David Gibson
                          uint32_t nargs, target_ulong args,
434 b5cec4c5 David Gibson
                          uint32_t nret, target_ulong rets)
435 b5cec4c5 David Gibson
{
436 b5cec4c5 David Gibson
    struct ics_state *ics = spapr->icp->ics;
437 b5cec4c5 David Gibson
    uint32_t nr;
438 b5cec4c5 David Gibson
439 b5cec4c5 David Gibson
    if ((nargs != 1) || (nret != 3)) {
440 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
441 b5cec4c5 David Gibson
        return;
442 b5cec4c5 David Gibson
    }
443 b5cec4c5 David Gibson
444 b5cec4c5 David Gibson
    nr = rtas_ld(args, 0);
445 b5cec4c5 David Gibson
446 b5cec4c5 David Gibson
    if (!ics_valid_irq(ics, nr)) {
447 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
448 b5cec4c5 David Gibson
        return;
449 b5cec4c5 David Gibson
    }
450 b5cec4c5 David Gibson
451 b5cec4c5 David Gibson
    rtas_st(rets, 0, 0); /* Success */
452 b5cec4c5 David Gibson
    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
453 b5cec4c5 David Gibson
    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
454 b5cec4c5 David Gibson
}
455 b5cec4c5 David Gibson
456 210b580b Anthony Liguori
static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
457 210b580b Anthony Liguori
                         uint32_t token,
458 b5cec4c5 David Gibson
                         uint32_t nargs, target_ulong args,
459 b5cec4c5 David Gibson
                         uint32_t nret, target_ulong rets)
460 b5cec4c5 David Gibson
{
461 b5cec4c5 David Gibson
    struct ics_state *ics = spapr->icp->ics;
462 b5cec4c5 David Gibson
    uint32_t nr;
463 b5cec4c5 David Gibson
464 b5cec4c5 David Gibson
    if ((nargs != 1) || (nret != 1)) {
465 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
466 b5cec4c5 David Gibson
        return;
467 b5cec4c5 David Gibson
    }
468 b5cec4c5 David Gibson
469 b5cec4c5 David Gibson
    nr = rtas_ld(args, 0);
470 b5cec4c5 David Gibson
471 b5cec4c5 David Gibson
    if (!ics_valid_irq(ics, nr)) {
472 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
473 b5cec4c5 David Gibson
        return;
474 b5cec4c5 David Gibson
    }
475 b5cec4c5 David Gibson
476 3fe719f4 David Gibson
    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
477 3fe719f4 David Gibson
                   ics->irqs[nr - ics->offset].priority);
478 b5cec4c5 David Gibson
479 b5cec4c5 David Gibson
    rtas_st(rets, 0, 0); /* Success */
480 b5cec4c5 David Gibson
}
481 b5cec4c5 David Gibson
482 210b580b Anthony Liguori
static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
483 210b580b Anthony Liguori
                        uint32_t token,
484 b5cec4c5 David Gibson
                        uint32_t nargs, target_ulong args,
485 b5cec4c5 David Gibson
                        uint32_t nret, target_ulong rets)
486 b5cec4c5 David Gibson
{
487 b5cec4c5 David Gibson
    struct ics_state *ics = spapr->icp->ics;
488 b5cec4c5 David Gibson
    uint32_t nr;
489 b5cec4c5 David Gibson
490 b5cec4c5 David Gibson
    if ((nargs != 1) || (nret != 1)) {
491 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
492 b5cec4c5 David Gibson
        return;
493 b5cec4c5 David Gibson
    }
494 b5cec4c5 David Gibson
495 b5cec4c5 David Gibson
    nr = rtas_ld(args, 0);
496 b5cec4c5 David Gibson
497 b5cec4c5 David Gibson
    if (!ics_valid_irq(ics, nr)) {
498 b5cec4c5 David Gibson
        rtas_st(rets, 0, -3);
499 b5cec4c5 David Gibson
        return;
500 b5cec4c5 David Gibson
    }
501 b5cec4c5 David Gibson
502 3fe719f4 David Gibson
    ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
503 3fe719f4 David Gibson
                   ics->irqs[nr - ics->offset].saved_priority,
504 3fe719f4 David Gibson
                   ics->irqs[nr - ics->offset].saved_priority);
505 b5cec4c5 David Gibson
506 b5cec4c5 David Gibson
    rtas_st(rets, 0, 0); /* Success */
507 b5cec4c5 David Gibson
}
508 b5cec4c5 David Gibson
509 256b408a David Gibson
static void xics_reset(void *opaque)
510 256b408a David Gibson
{
511 256b408a David Gibson
    struct icp_state *icp = (struct icp_state *)opaque;
512 256b408a David Gibson
    struct ics_state *ics = icp->ics;
513 256b408a David Gibson
    int i;
514 256b408a David Gibson
515 256b408a David Gibson
    for (i = 0; i < icp->nr_servers; i++) {
516 256b408a David Gibson
        icp->ss[i].xirr = 0;
517 044f4c8b David Gibson
        icp->ss[i].pending_priority = 0xff;
518 256b408a David Gibson
        icp->ss[i].mfrr = 0xff;
519 256b408a David Gibson
        /* Make all outputs are deasserted */
520 256b408a David Gibson
        qemu_set_irq(icp->ss[i].output, 0);
521 256b408a David Gibson
    }
522 256b408a David Gibson
523 22a2611c David Gibson
    memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs);
524 256b408a David Gibson
    for (i = 0; i < ics->nr_irqs; i++) {
525 256b408a David Gibson
        ics->irqs[i].priority = 0xff;
526 256b408a David Gibson
        ics->irqs[i].saved_priority = 0xff;
527 256b408a David Gibson
    }
528 256b408a David Gibson
}
529 256b408a David Gibson
530 7b565160 David Gibson
void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu)
531 b5cec4c5 David Gibson
{
532 7b565160 David Gibson
    CPUState *cs = CPU(cpu);
533 7b565160 David Gibson
    CPUPPCState *env = &cpu->env;
534 7b565160 David Gibson
    struct icp_server_state *ss = &icp->ss[cs->cpu_index];
535 b5cec4c5 David Gibson
536 7b565160 David Gibson
    assert(cs->cpu_index < icp->nr_servers);
537 c7a5c0c9 David Gibson
538 7b565160 David Gibson
    switch (PPC_INPUT(env)) {
539 7b565160 David Gibson
    case PPC_FLAGS_INPUT_POWER7:
540 7b565160 David Gibson
        ss->output = env->irq_inputs[POWER7_INPUT_INT];
541 7b565160 David Gibson
        break;
542 c7a5c0c9 David Gibson
543 7b565160 David Gibson
    case PPC_FLAGS_INPUT_970:
544 7b565160 David Gibson
        ss->output = env->irq_inputs[PPC970_INPUT_INT];
545 7b565160 David Gibson
        break;
546 b5cec4c5 David Gibson
547 7b565160 David Gibson
    default:
548 7b565160 David Gibson
        fprintf(stderr, "XICS interrupt controller does not support this CPU "
549 7b565160 David Gibson
                "bus model\n");
550 7b565160 David Gibson
        abort();
551 7b565160 David Gibson
    }
552 7b565160 David Gibson
}
553 b5cec4c5 David Gibson
554 7b565160 David Gibson
struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
555 7b565160 David Gibson
{
556 7b565160 David Gibson
    struct icp_state *icp;
557 7b565160 David Gibson
    struct ics_state *ics;
558 b5cec4c5 David Gibson
559 7b565160 David Gibson
    icp = g_malloc0(sizeof(*icp));
560 7b565160 David Gibson
    icp->nr_servers = nr_servers;
561 7b565160 David Gibson
    icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state));
562 b5cec4c5 David Gibson
563 7267c094 Anthony Liguori
    ics = g_malloc0(sizeof(*ics));
564 b5cec4c5 David Gibson
    ics->nr_irqs = nr_irqs;
565 bf3bc4c4 Ben Herrenschmidt
    ics->offset = XICS_IRQ_BASE;
566 7267c094 Anthony Liguori
    ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
567 22a2611c David Gibson
    ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
568 b5cec4c5 David Gibson
569 b5cec4c5 David Gibson
    icp->ics = ics;
570 b5cec4c5 David Gibson
    ics->icp = icp;
571 b5cec4c5 David Gibson
572 d07fee7e David Gibson
    ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs);
573 b5cec4c5 David Gibson
574 b5cec4c5 David Gibson
    spapr_register_hypercall(H_CPPR, h_cppr);
575 b5cec4c5 David Gibson
    spapr_register_hypercall(H_IPI, h_ipi);
576 b5cec4c5 David Gibson
    spapr_register_hypercall(H_XIRR, h_xirr);
577 b5cec4c5 David Gibson
    spapr_register_hypercall(H_EOI, h_eoi);
578 b5cec4c5 David Gibson
579 b5cec4c5 David Gibson
    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
580 b5cec4c5 David Gibson
    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
581 b5cec4c5 David Gibson
    spapr_rtas_register("ibm,int-off", rtas_int_off);
582 b5cec4c5 David Gibson
    spapr_rtas_register("ibm,int-on", rtas_int_on);
583 b5cec4c5 David Gibson
584 256b408a David Gibson
    qemu_register_reset(xics_reset, icp);
585 256b408a David Gibson
586 b5cec4c5 David Gibson
    return icp;
587 b5cec4c5 David Gibson
}