]> Git Repo - qemu.git/blob - hw/ppc/spapr_irq.c
spapr: introduce a spapr_irq_init() routine
[qemu.git] / hw / ppc / spapr_irq.c
1 /*
2  * QEMU PowerPC sPAPR IRQ interface
3  *
4  * Copyright (c) 2018, IBM Corporation.
5  *
6  * This code is licensed under the GPL version 2 or later. See the
7  * COPYING file in the top-level directory.
8  */
9
10 #include "qemu/osdep.h"
11 #include "qemu/log.h"
12 #include "qemu/error-report.h"
13 #include "qapi/error.h"
14 #include "hw/ppc/spapr.h"
15 #include "hw/ppc/xics.h"
16 #include "sysemu/kvm.h"
17
18 #include "trace.h"
19
20 void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis)
21 {
22     spapr->irq_map_nr = nr_msis;
23     spapr->irq_map = bitmap_new(spapr->irq_map_nr);
24 }
25
26 int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
27                         Error **errp)
28 {
29     int irq;
30
31     /*
32      * The 'align_mask' parameter of bitmap_find_next_zero_area()
33      * should be one less than a power of 2; 0 means no
34      * alignment. Adapt the 'align' value of the former allocator
35      * to fit the requirements of bitmap_find_next_zero_area()
36      */
37     align -= 1;
38
39     irq = bitmap_find_next_zero_area(spapr->irq_map, spapr->irq_map_nr, 0, num,
40                                      align);
41     if (irq == spapr->irq_map_nr) {
42         error_setg(errp, "can't find a free %d-IRQ block", num);
43         return -1;
44     }
45
46     bitmap_set(spapr->irq_map, irq, num);
47
48     return irq + SPAPR_IRQ_MSI;
49 }
50
51 void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num)
52 {
53     bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
54 }
55
56 void spapr_irq_msi_reset(sPAPRMachineState *spapr)
57 {
58     bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
59 }
60
61
62 /*
63  * XICS IRQ backend.
64  */
65
66 static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
67                                   const char *type_ics,
68                                   int nr_irqs, Error **errp)
69 {
70     Error *local_err = NULL;
71     Object *obj;
72
73     obj = object_new(type_ics);
74     object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
75     object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
76                                    &error_abort);
77     object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err);
78     if (local_err) {
79         goto error;
80     }
81     object_property_set_bool(obj, true, "realized", &local_err);
82     if (local_err) {
83         goto error;
84     }
85
86     return ICS_BASE(obj);
87
88 error:
89     error_propagate(errp, local_err);
90     return NULL;
91 }
92
93 static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp)
94 {
95     MachineState *machine = MACHINE(spapr);
96     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
97     int nr_irqs = smc->irq->nr_irqs;
98     Error *local_err = NULL;
99
100     if (kvm_enabled()) {
101         if (machine_kernel_irqchip_allowed(machine) &&
102             !xics_kvm_init(spapr, &local_err)) {
103             spapr->icp_type = TYPE_KVM_ICP;
104             spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
105                                           &local_err);
106         }
107         if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
108             error_prepend(&local_err,
109                           "kernel_irqchip requested but unavailable: ");
110             goto error;
111         }
112         error_free(local_err);
113         local_err = NULL;
114     }
115
116     if (!spapr->ics) {
117         xics_spapr_init(spapr);
118         spapr->icp_type = TYPE_ICP;
119         spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
120                                       &local_err);
121     }
122
123 error:
124     error_propagate(errp, local_err);
125 }
126
127 #define ICS_IRQ_FREE(ics, srcno)   \
128     (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
129
130 static int spapr_irq_claim_xics(sPAPRMachineState *spapr, int irq, bool lsi,
131                                 Error **errp)
132 {
133     ICSState *ics = spapr->ics;
134
135     assert(ics);
136
137     if (!ics_valid_irq(ics, irq)) {
138         error_setg(errp, "IRQ %d is invalid", irq);
139         return -1;
140     }
141
142     if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
143         error_setg(errp, "IRQ %d is not free", irq);
144         return -1;
145     }
146
147     ics_set_irq_type(ics, irq - ics->offset, lsi);
148     return 0;
149 }
150
151 static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num)
152 {
153     ICSState *ics = spapr->ics;
154     uint32_t srcno = irq - ics->offset;
155     int i;
156
157     if (ics_valid_irq(ics, irq)) {
158         trace_spapr_irq_free(0, irq, num);
159         for (i = srcno; i < srcno + num; ++i) {
160             if (ICS_IRQ_FREE(ics, i)) {
161                 trace_spapr_irq_free_warn(0, i);
162             }
163             memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
164         }
165     }
166 }
167
168 static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
169 {
170     ICSState *ics = spapr->ics;
171     uint32_t srcno = irq - ics->offset;
172
173     if (ics_valid_irq(ics, irq)) {
174         return ics->qirqs[srcno];
175     }
176
177     return NULL;
178 }
179
180 static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
181 {
182     CPUState *cs;
183
184     CPU_FOREACH(cs) {
185         PowerPCCPU *cpu = POWERPC_CPU(cs);
186
187         icp_pic_print_info(ICP(cpu->intc), mon);
188     }
189
190     ics_pic_print_info(spapr->ics, mon);
191 }
192
193 #define SPAPR_IRQ_XICS_NR_IRQS     0x1000
194 #define SPAPR_IRQ_XICS_NR_MSIS     \
195     (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
196
197 sPAPRIrq spapr_irq_xics = {
198     .nr_irqs     = SPAPR_IRQ_XICS_NR_IRQS,
199     .nr_msis     = SPAPR_IRQ_XICS_NR_MSIS,
200
201     .init        = spapr_irq_init_xics,
202     .claim       = spapr_irq_claim_xics,
203     .free        = spapr_irq_free_xics,
204     .qirq        = spapr_qirq_xics,
205     .print_info  = spapr_irq_print_info_xics,
206 };
207
208 /*
209  * sPAPR IRQ frontend routines for devices
210  */
211 void spapr_irq_init(sPAPRMachineState *spapr, Error **errp)
212 {
213     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
214
215     /* Initialize the MSI IRQ allocator. */
216     if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
217         spapr_irq_msi_init(spapr, smc->irq->nr_msis);
218     }
219
220     smc->irq->init(spapr, errp);
221 }
222
223 int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
224 {
225     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
226
227     return smc->irq->claim(spapr, irq, lsi, errp);
228 }
229
230 void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
231 {
232     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
233
234     smc->irq->free(spapr, irq, num);
235 }
236
237 qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
238 {
239     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
240
241     return smc->irq->qirq(spapr, irq);
242 }
243
244 /*
245  * XICS legacy routines - to deprecate one day
246  */
247
248 static int ics_find_free_block(ICSState *ics, int num, int alignnum)
249 {
250     int first, i;
251
252     for (first = 0; first < ics->nr_irqs; first += alignnum) {
253         if (num > (ics->nr_irqs - first)) {
254             return -1;
255         }
256         for (i = first; i < first + num; ++i) {
257             if (!ICS_IRQ_FREE(ics, i)) {
258                 break;
259             }
260         }
261         if (i == (first + num)) {
262             return first;
263         }
264     }
265
266     return -1;
267 }
268
269 int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
270 {
271     ICSState *ics = spapr->ics;
272     int first = -1;
273
274     assert(ics);
275
276     /*
277      * MSIMesage::data is used for storing VIRQ so
278      * it has to be aligned to num to support multiple
279      * MSI vectors. MSI-X is not affected by this.
280      * The hint is used for the first IRQ, the rest should
281      * be allocated continuously.
282      */
283     if (align) {
284         assert((num == 1) || (num == 2) || (num == 4) ||
285                (num == 8) || (num == 16) || (num == 32));
286         first = ics_find_free_block(ics, num, num);
287     } else {
288         first = ics_find_free_block(ics, num, 1);
289     }
290
291     if (first < 0) {
292         error_setg(errp, "can't find a free %d-IRQ block", num);
293         return -1;
294     }
295
296     return first + ics->offset;
297 }
298
299 #define SPAPR_IRQ_XICS_LEGACY_NR_IRQS     0x400
300
301 sPAPRIrq spapr_irq_xics_legacy = {
302     .nr_irqs     = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
303     .nr_msis     = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
304
305     .init        = spapr_irq_init_xics,
306     .claim       = spapr_irq_claim_xics,
307     .free        = spapr_irq_free_xics,
308     .qirq        = spapr_qirq_xics,
309     .print_info  = spapr_irq_print_info_xics,
310 };
This page took 0.041216 seconds and 4 git commands to generate.