xref: /openbmc/qemu/hw/intc/xics.c (revision 9ccff2a4d604d31f01398190758072253dc3c188)
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/hw.h"
29 #include "trace.h"
30 #include "hw/ppc/spapr.h"
31 #include "hw/ppc/xics.h"
32 #include "qemu/error-report.h"
33 
34 void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
35 {
36     CPUState *cs = CPU(cpu);
37     CPUPPCState *env = &cpu->env;
38     ICPState *ss = &icp->ss[cs->cpu_index];
39 
40     assert(cs->cpu_index < icp->nr_servers);
41 
42     switch (PPC_INPUT(env)) {
43     case PPC_FLAGS_INPUT_POWER7:
44         ss->output = env->irq_inputs[POWER7_INPUT_INT];
45         break;
46 
47     case PPC_FLAGS_INPUT_970:
48         ss->output = env->irq_inputs[PPC970_INPUT_INT];
49         break;
50 
51     default:
52         error_report("XICS interrupt controller does not support this CPU "
53                      "bus model");
54         abort();
55     }
56 }
57 
58 static void xics_reset(DeviceState *d)
59 {
60     XICSState *icp = XICS(d);
61     int i;
62 
63     for (i = 0; i < icp->nr_servers; i++) {
64         device_reset(DEVICE(&icp->ss[i]));
65     }
66 
67     device_reset(DEVICE(icp->ics));
68 }
69 
70 /*
71  * ICP: Presentation layer
72  */
73 
74 #define XISR_MASK  0x00ffffff
75 #define CPPR_MASK  0xff000000
76 
77 #define XISR(ss)   (((ss)->xirr) & XISR_MASK)
78 #define CPPR(ss)   (((ss)->xirr) >> 24)
79 
80 static void ics_reject(ICSState *ics, int nr);
81 static void ics_resend(ICSState *ics);
82 static void ics_eoi(ICSState *ics, int nr);
83 
84 static void icp_check_ipi(XICSState *icp, int server)
85 {
86     ICPState *ss = icp->ss + server;
87 
88     if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
89         return;
90     }
91 
92     trace_xics_icp_check_ipi(server, ss->mfrr);
93 
94     if (XISR(ss)) {
95         ics_reject(icp->ics, XISR(ss));
96     }
97 
98     ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
99     ss->pending_priority = ss->mfrr;
100     qemu_irq_raise(ss->output);
101 }
102 
103 static void icp_resend(XICSState *icp, int server)
104 {
105     ICPState *ss = icp->ss + server;
106 
107     if (ss->mfrr < CPPR(ss)) {
108         icp_check_ipi(icp, server);
109     }
110     ics_resend(icp->ics);
111 }
112 
113 static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr)
114 {
115     ICPState *ss = icp->ss + server;
116     uint8_t old_cppr;
117     uint32_t old_xisr;
118 
119     old_cppr = CPPR(ss);
120     ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
121 
122     if (cppr < old_cppr) {
123         if (XISR(ss) && (cppr <= ss->pending_priority)) {
124             old_xisr = XISR(ss);
125             ss->xirr &= ~XISR_MASK; /* Clear XISR */
126             ss->pending_priority = 0xff;
127             qemu_irq_lower(ss->output);
128             ics_reject(icp->ics, old_xisr);
129         }
130     } else {
131         if (!XISR(ss)) {
132             icp_resend(icp, server);
133         }
134     }
135 }
136 
137 static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr)
138 {
139     ICPState *ss = icp->ss + server;
140 
141     ss->mfrr = mfrr;
142     if (mfrr < CPPR(ss)) {
143         icp_check_ipi(icp, server);
144     }
145 }
146 
147 static uint32_t icp_accept(ICPState *ss)
148 {
149     uint32_t xirr = ss->xirr;
150 
151     qemu_irq_lower(ss->output);
152     ss->xirr = ss->pending_priority << 24;
153     ss->pending_priority = 0xff;
154 
155     trace_xics_icp_accept(xirr, ss->xirr);
156 
157     return xirr;
158 }
159 
160 static void icp_eoi(XICSState *icp, int server, uint32_t xirr)
161 {
162     ICPState *ss = icp->ss + server;
163 
164     /* Send EOI -> ICS */
165     ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
166     trace_xics_icp_eoi(server, xirr, ss->xirr);
167     ics_eoi(icp->ics, xirr & XISR_MASK);
168     if (!XISR(ss)) {
169         icp_resend(icp, server);
170     }
171 }
172 
173 static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority)
174 {
175     ICPState *ss = icp->ss + server;
176 
177     trace_xics_icp_irq(server, nr, priority);
178 
179     if ((priority >= CPPR(ss))
180         || (XISR(ss) && (ss->pending_priority <= priority))) {
181         ics_reject(icp->ics, nr);
182     } else {
183         if (XISR(ss)) {
184             ics_reject(icp->ics, XISR(ss));
185         }
186         ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
187         ss->pending_priority = priority;
188         trace_xics_icp_raise(ss->xirr, ss->pending_priority);
189         qemu_irq_raise(ss->output);
190     }
191 }
192 
193 static const VMStateDescription vmstate_icp_server = {
194     .name = "icp/server",
195     .version_id = 1,
196     .minimum_version_id = 1,
197     .minimum_version_id_old = 1,
198     .fields      = (VMStateField []) {
199         /* Sanity check */
200         VMSTATE_UINT32(xirr, ICPState),
201         VMSTATE_UINT8(pending_priority, ICPState),
202         VMSTATE_UINT8(mfrr, ICPState),
203         VMSTATE_END_OF_LIST()
204     },
205 };
206 
207 static void icp_reset(DeviceState *dev)
208 {
209     ICPState *icp = ICP(dev);
210 
211     icp->xirr = 0;
212     icp->pending_priority = 0xff;
213     icp->mfrr = 0xff;
214 
215     /* Make all outputs are deasserted */
216     qemu_set_irq(icp->output, 0);
217 }
218 
219 static void icp_class_init(ObjectClass *klass, void *data)
220 {
221     DeviceClass *dc = DEVICE_CLASS(klass);
222 
223     dc->reset = icp_reset;
224     dc->vmsd = &vmstate_icp_server;
225 }
226 
227 static TypeInfo icp_info = {
228     .name = TYPE_ICP,
229     .parent = TYPE_DEVICE,
230     .instance_size = sizeof(ICPState),
231     .class_init = icp_class_init,
232 };
233 
234 /*
235  * ICS: Source layer
236  */
237 static int ics_valid_irq(ICSState *ics, uint32_t nr)
238 {
239     return (nr >= ics->offset)
240         && (nr < (ics->offset + ics->nr_irqs));
241 }
242 
243 static void resend_msi(ICSState *ics, int srcno)
244 {
245     ICSIRQState *irq = ics->irqs + srcno;
246 
247     /* FIXME: filter by server#? */
248     if (irq->status & XICS_STATUS_REJECTED) {
249         irq->status &= ~XICS_STATUS_REJECTED;
250         if (irq->priority != 0xff) {
251             icp_irq(ics->icp, irq->server, srcno + ics->offset,
252                     irq->priority);
253         }
254     }
255 }
256 
257 static void resend_lsi(ICSState *ics, int srcno)
258 {
259     ICSIRQState *irq = ics->irqs + srcno;
260 
261     if ((irq->priority != 0xff)
262         && (irq->status & XICS_STATUS_ASSERTED)
263         && !(irq->status & XICS_STATUS_SENT)) {
264         irq->status |= XICS_STATUS_SENT;
265         icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
266     }
267 }
268 
269 static void set_irq_msi(ICSState *ics, int srcno, int val)
270 {
271     ICSIRQState *irq = ics->irqs + srcno;
272 
273     trace_xics_set_irq_msi(srcno, srcno + ics->offset);
274 
275     if (val) {
276         if (irq->priority == 0xff) {
277             irq->status |= XICS_STATUS_MASKED_PENDING;
278             trace_xics_masked_pending();
279         } else  {
280             icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
281         }
282     }
283 }
284 
285 static void set_irq_lsi(ICSState *ics, int srcno, int val)
286 {
287     ICSIRQState *irq = ics->irqs + srcno;
288 
289     trace_xics_set_irq_lsi(srcno, srcno + ics->offset);
290     if (val) {
291         irq->status |= XICS_STATUS_ASSERTED;
292     } else {
293         irq->status &= ~XICS_STATUS_ASSERTED;
294     }
295     resend_lsi(ics, srcno);
296 }
297 
298 static void ics_set_irq(void *opaque, int srcno, int val)
299 {
300     ICSState *ics = (ICSState *)opaque;
301 
302     if (ics->islsi[srcno]) {
303         set_irq_lsi(ics, srcno, val);
304     } else {
305         set_irq_msi(ics, srcno, val);
306     }
307 }
308 
309 static void write_xive_msi(ICSState *ics, int srcno)
310 {
311     ICSIRQState *irq = ics->irqs + srcno;
312 
313     if (!(irq->status & XICS_STATUS_MASKED_PENDING)
314         || (irq->priority == 0xff)) {
315         return;
316     }
317 
318     irq->status &= ~XICS_STATUS_MASKED_PENDING;
319     icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
320 }
321 
322 static void write_xive_lsi(ICSState *ics, int srcno)
323 {
324     resend_lsi(ics, srcno);
325 }
326 
327 static void ics_write_xive(ICSState *ics, int nr, int server,
328                            uint8_t priority, uint8_t saved_priority)
329 {
330     int srcno = nr - ics->offset;
331     ICSIRQState *irq = ics->irqs + srcno;
332 
333     irq->server = server;
334     irq->priority = priority;
335     irq->saved_priority = saved_priority;
336 
337     trace_xics_ics_write_xive(nr, srcno, server, priority);
338 
339     if (ics->islsi[srcno]) {
340         write_xive_lsi(ics, srcno);
341     } else {
342         write_xive_msi(ics, srcno);
343     }
344 }
345 
346 static void ics_reject(ICSState *ics, int nr)
347 {
348     ICSIRQState *irq = ics->irqs + nr - ics->offset;
349 
350     trace_xics_ics_reject(nr, nr - ics->offset);
351     irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */
352     irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */
353 }
354 
355 static void ics_resend(ICSState *ics)
356 {
357     int i;
358 
359     for (i = 0; i < ics->nr_irqs; i++) {
360         /* FIXME: filter by server#? */
361         if (ics->islsi[i]) {
362             resend_lsi(ics, i);
363         } else {
364             resend_msi(ics, i);
365         }
366     }
367 }
368 
369 static void ics_eoi(ICSState *ics, int nr)
370 {
371     int srcno = nr - ics->offset;
372     ICSIRQState *irq = ics->irqs + srcno;
373 
374     trace_xics_ics_eoi(nr);
375 
376     if (ics->islsi[srcno]) {
377         irq->status &= ~XICS_STATUS_SENT;
378     }
379 }
380 
381 static void ics_reset(DeviceState *dev)
382 {
383     ICSState *ics = ICS(dev);
384     int i;
385 
386     memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
387     for (i = 0; i < ics->nr_irqs; i++) {
388         ics->irqs[i].priority = 0xff;
389         ics->irqs[i].saved_priority = 0xff;
390     }
391 }
392 
393 static int ics_post_load(void *opaque, int version_id)
394 {
395     int i;
396     ICSState *ics = opaque;
397 
398     for (i = 0; i < ics->icp->nr_servers; i++) {
399         icp_resend(ics->icp, i);
400     }
401 
402     return 0;
403 }
404 
405 static const VMStateDescription vmstate_ics_irq = {
406     .name = "ics/irq",
407     .version_id = 1,
408     .minimum_version_id = 1,
409     .minimum_version_id_old = 1,
410     .fields      = (VMStateField []) {
411         VMSTATE_UINT32(server, ICSIRQState),
412         VMSTATE_UINT8(priority, ICSIRQState),
413         VMSTATE_UINT8(saved_priority, ICSIRQState),
414         VMSTATE_UINT8(status, ICSIRQState),
415         VMSTATE_END_OF_LIST()
416     },
417 };
418 
419 static const VMStateDescription vmstate_ics = {
420     .name = "ics",
421     .version_id = 1,
422     .minimum_version_id = 1,
423     .minimum_version_id_old = 1,
424     .post_load = ics_post_load,
425     .fields      = (VMStateField []) {
426         /* Sanity check */
427         VMSTATE_UINT32_EQUAL(nr_irqs, ICSState),
428 
429         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
430                                              vmstate_ics_irq, ICSIRQState),
431         VMSTATE_END_OF_LIST()
432     },
433 };
434 
435 static int ics_realize(DeviceState *dev)
436 {
437     ICSState *ics = ICS(dev);
438 
439     ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
440     ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool));
441     ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
442 
443     return 0;
444 }
445 
446 static void ics_class_init(ObjectClass *klass, void *data)
447 {
448     DeviceClass *dc = DEVICE_CLASS(klass);
449 
450     dc->init = ics_realize;
451     dc->vmsd = &vmstate_ics;
452     dc->reset = ics_reset;
453 }
454 
455 static TypeInfo ics_info = {
456     .name = TYPE_ICS,
457     .parent = TYPE_DEVICE,
458     .instance_size = sizeof(ICSState),
459     .class_init = ics_class_init,
460 };
461 
462 /*
463  * Exported functions
464  */
465 
466 qemu_irq xics_get_qirq(XICSState *icp, int irq)
467 {
468     if (!ics_valid_irq(icp->ics, irq)) {
469         return NULL;
470     }
471 
472     return icp->ics->qirqs[irq - icp->ics->offset];
473 }
474 
475 void xics_set_irq_type(XICSState *icp, int irq, bool lsi)
476 {
477     assert(ics_valid_irq(icp->ics, irq));
478 
479     icp->ics->islsi[irq - icp->ics->offset] = lsi;
480 }
481 
482 /*
483  * Guest interfaces
484  */
485 
486 static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
487                            target_ulong opcode, target_ulong *args)
488 {
489     CPUState *cs = CPU(cpu);
490     target_ulong cppr = args[0];
491 
492     icp_set_cppr(spapr->icp, cs->cpu_index, cppr);
493     return H_SUCCESS;
494 }
495 
496 static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
497                           target_ulong opcode, target_ulong *args)
498 {
499     target_ulong server = args[0];
500     target_ulong mfrr = args[1];
501 
502     if (server >= spapr->icp->nr_servers) {
503         return H_PARAMETER;
504     }
505 
506     icp_set_mfrr(spapr->icp, server, mfrr);
507     return H_SUCCESS;
508 }
509 
510 static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
511                            target_ulong opcode, target_ulong *args)
512 {
513     CPUState *cs = CPU(cpu);
514     uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index);
515 
516     args[0] = xirr;
517     return H_SUCCESS;
518 }
519 
520 static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
521                           target_ulong opcode, target_ulong *args)
522 {
523     CPUState *cs = CPU(cpu);
524     target_ulong xirr = args[0];
525 
526     icp_eoi(spapr->icp, cs->cpu_index, xirr);
527     return H_SUCCESS;
528 }
529 
530 static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
531                           uint32_t token,
532                           uint32_t nargs, target_ulong args,
533                           uint32_t nret, target_ulong rets)
534 {
535     ICSState *ics = spapr->icp->ics;
536     uint32_t nr, server, priority;
537 
538     if ((nargs != 3) || (nret != 1)) {
539         rtas_st(rets, 0, -3);
540         return;
541     }
542 
543     nr = rtas_ld(args, 0);
544     server = rtas_ld(args, 1);
545     priority = rtas_ld(args, 2);
546 
547     if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
548         || (priority > 0xff)) {
549         rtas_st(rets, 0, -3);
550         return;
551     }
552 
553     ics_write_xive(ics, nr, server, priority, priority);
554 
555     rtas_st(rets, 0, 0); /* Success */
556 }
557 
558 static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
559                           uint32_t token,
560                           uint32_t nargs, target_ulong args,
561                           uint32_t nret, target_ulong rets)
562 {
563     ICSState *ics = spapr->icp->ics;
564     uint32_t nr;
565 
566     if ((nargs != 1) || (nret != 3)) {
567         rtas_st(rets, 0, -3);
568         return;
569     }
570 
571     nr = rtas_ld(args, 0);
572 
573     if (!ics_valid_irq(ics, nr)) {
574         rtas_st(rets, 0, -3);
575         return;
576     }
577 
578     rtas_st(rets, 0, 0); /* Success */
579     rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
580     rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
581 }
582 
583 static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
584                          uint32_t token,
585                          uint32_t nargs, target_ulong args,
586                          uint32_t nret, target_ulong rets)
587 {
588     ICSState *ics = spapr->icp->ics;
589     uint32_t nr;
590 
591     if ((nargs != 1) || (nret != 1)) {
592         rtas_st(rets, 0, -3);
593         return;
594     }
595 
596     nr = rtas_ld(args, 0);
597 
598     if (!ics_valid_irq(ics, nr)) {
599         rtas_st(rets, 0, -3);
600         return;
601     }
602 
603     ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff,
604                    ics->irqs[nr - ics->offset].priority);
605 
606     rtas_st(rets, 0, 0); /* Success */
607 }
608 
609 static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr,
610                         uint32_t token,
611                         uint32_t nargs, target_ulong args,
612                         uint32_t nret, target_ulong rets)
613 {
614     ICSState *ics = spapr->icp->ics;
615     uint32_t nr;
616 
617     if ((nargs != 1) || (nret != 1)) {
618         rtas_st(rets, 0, -3);
619         return;
620     }
621 
622     nr = rtas_ld(args, 0);
623 
624     if (!ics_valid_irq(ics, nr)) {
625         rtas_st(rets, 0, -3);
626         return;
627     }
628 
629     ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server,
630                    ics->irqs[nr - ics->offset].saved_priority,
631                    ics->irqs[nr - ics->offset].saved_priority);
632 
633     rtas_st(rets, 0, 0); /* Success */
634 }
635 
636 /*
637  * XICS
638  */
639 
640 static void xics_realize(DeviceState *dev, Error **errp)
641 {
642     XICSState *icp = XICS(dev);
643     ICSState *ics = icp->ics;
644     int i;
645 
646     /* Registration of global state belongs into realize */
647     spapr_rtas_register("ibm,set-xive", rtas_set_xive);
648     spapr_rtas_register("ibm,get-xive", rtas_get_xive);
649     spapr_rtas_register("ibm,int-off", rtas_int_off);
650     spapr_rtas_register("ibm,int-on", rtas_int_on);
651 
652     spapr_register_hypercall(H_CPPR, h_cppr);
653     spapr_register_hypercall(H_IPI, h_ipi);
654     spapr_register_hypercall(H_XIRR, h_xirr);
655     spapr_register_hypercall(H_EOI, h_eoi);
656 
657     ics->nr_irqs = icp->nr_irqs;
658     ics->offset = XICS_IRQ_BASE;
659     ics->icp = icp;
660     qdev_init_nofail(DEVICE(ics));
661 
662     icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState));
663     for (i = 0; i < icp->nr_servers; i++) {
664         char buffer[32];
665         object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP);
666         snprintf(buffer, sizeof(buffer), "icp[%d]", i);
667         object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL);
668         qdev_init_nofail(DEVICE(&icp->ss[i]));
669     }
670 }
671 
672 static void xics_initfn(Object *obj)
673 {
674     XICSState *xics = XICS(obj);
675 
676     xics->ics = ICS(object_new(TYPE_ICS));
677     object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL);
678 }
679 
680 static Property xics_properties[] = {
681     DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1),
682     DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1),
683     DEFINE_PROP_END_OF_LIST(),
684 };
685 
686 static void xics_class_init(ObjectClass *oc, void *data)
687 {
688     DeviceClass *dc = DEVICE_CLASS(oc);
689 
690     dc->realize = xics_realize;
691     dc->props = xics_properties;
692     dc->reset = xics_reset;
693 }
694 
695 static const TypeInfo xics_info = {
696     .name          = TYPE_XICS,
697     .parent        = TYPE_SYS_BUS_DEVICE,
698     .instance_size = sizeof(XICSState),
699     .class_init    = xics_class_init,
700     .instance_init = xics_initfn,
701 };
702 
703 static void xics_register_types(void)
704 {
705     type_register_static(&xics_info);
706     type_register_static(&ics_info);
707     type_register_static(&icp_info);
708 }
709 
710 type_init(xics_register_types)
711