Annotation of qemu/hw/xics.c, revision 1.1

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: #include <pthread.h>
        !            33: 
        !            34: /*
        !            35:  * ICP: Presentation layer
        !            36:  */
        !            37: 
        !            38: struct icp_server_state {
        !            39:     uint32_t xirr;
        !            40:     uint8_t pending_priority;
        !            41:     uint8_t mfrr;
        !            42:     qemu_irq output;
        !            43: };
        !            44: 
        !            45: #define XISR_MASK  0x00ffffff
        !            46: #define CPPR_MASK  0xff000000
        !            47: 
        !            48: #define XISR(ss)   (((ss)->xirr) & XISR_MASK)
        !            49: #define CPPR(ss)   (((ss)->xirr) >> 24)
        !            50: 
        !            51: struct ics_state;
        !            52: 
        !            53: struct icp_state {
        !            54:     long nr_servers;
        !            55:     struct icp_server_state *ss;
        !            56:     struct ics_state *ics;
        !            57: };
        !            58: 
        !            59: static void ics_reject(struct ics_state *ics, int nr);
        !            60: static void ics_resend(struct ics_state *ics);
        !            61: static void ics_eoi(struct ics_state *ics, int nr);
        !            62: 
        !            63: static void icp_check_ipi(struct icp_state *icp, int server)
        !            64: {
        !            65:     struct icp_server_state *ss = icp->ss + server;
        !            66: 
        !            67:     if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
        !            68:         return;
        !            69:     }
        !            70: 
        !            71:     if (XISR(ss)) {
        !            72:         ics_reject(icp->ics, XISR(ss));
        !            73:     }
        !            74: 
        !            75:     ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
        !            76:     ss->pending_priority = ss->mfrr;
        !            77:     qemu_irq_raise(ss->output);
        !            78: }
        !            79: 
        !            80: static void icp_resend(struct icp_state *icp, int server)
        !            81: {
        !            82:     struct icp_server_state *ss = icp->ss + server;
        !            83: 
        !            84:     if (ss->mfrr < CPPR(ss)) {
        !            85:         icp_check_ipi(icp, server);
        !            86:     }
        !            87:     ics_resend(icp->ics);
        !            88: }
        !            89: 
        !            90: static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
        !            91: {
        !            92:     struct icp_server_state *ss = icp->ss + server;
        !            93:     uint8_t old_cppr;
        !            94:     uint32_t old_xisr;
        !            95: 
        !            96:     old_cppr = CPPR(ss);
        !            97:     ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
        !            98: 
        !            99:     if (cppr < old_cppr) {
        !           100:         if (XISR(ss) && (cppr <= ss->pending_priority)) {
        !           101:             old_xisr = XISR(ss);
        !           102:             ss->xirr &= ~XISR_MASK; /* Clear XISR */
        !           103:             qemu_irq_lower(ss->output);
        !           104:             ics_reject(icp->ics, old_xisr);
        !           105:         }
        !           106:     } else {
        !           107:         if (!XISR(ss)) {
        !           108:             icp_resend(icp, server);
        !           109:         }
        !           110:     }
        !           111: }
        !           112: 
        !           113: static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
        !           114: {
        !           115:     struct icp_server_state *ss = icp->ss + nr;
        !           116: 
        !           117:     ss->mfrr = mfrr;
        !           118:     if (mfrr < CPPR(ss)) {
        !           119:         icp_check_ipi(icp, nr);
        !           120:     }
        !           121: }
        !           122: 
        !           123: static uint32_t icp_accept(struct icp_server_state *ss)
        !           124: {
        !           125:     uint32_t xirr;
        !           126: 
        !           127:     qemu_irq_lower(ss->output);
        !           128:     xirr = ss->xirr;
        !           129:     ss->xirr = ss->pending_priority << 24;
        !           130:     return xirr;
        !           131: }
        !           132: 
        !           133: static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
        !           134: {
        !           135:     struct icp_server_state *ss = icp->ss + server;
        !           136: 
        !           137:     ics_eoi(icp->ics, xirr & XISR_MASK);
        !           138:     /* Send EOI -> ICS */
        !           139:     ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
        !           140:     if (!XISR(ss)) {
        !           141:         icp_resend(icp, server);
        !           142:     }
        !           143: }
        !           144: 
        !           145: static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
        !           146: {
        !           147:     struct icp_server_state *ss = icp->ss + server;
        !           148: 
        !           149:     if ((priority >= CPPR(ss))
        !           150:         || (XISR(ss) && (ss->pending_priority <= priority))) {
        !           151:         ics_reject(icp->ics, nr);
        !           152:     } else {
        !           153:         if (XISR(ss)) {
        !           154:             ics_reject(icp->ics, XISR(ss));
        !           155:         }
        !           156:         ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
        !           157:         ss->pending_priority = priority;
        !           158:         qemu_irq_raise(ss->output);
        !           159:     }
        !           160: }
        !           161: 
        !           162: /*
        !           163:  * ICS: Source layer
        !           164:  */
        !           165: 
        !           166: struct ics_irq_state {
        !           167:     int server;
        !           168:     uint8_t priority;
        !           169:     uint8_t saved_priority;
        !           170:     /* int pending:1; */
        !           171:     /* int presented:1; */
        !           172:     int rejected:1;
        !           173:     int masked_pending:1;
        !           174: };
        !           175: 
        !           176: struct ics_state {
        !           177:     int nr_irqs;
        !           178:     int offset;
        !           179:     qemu_irq *qirqs;
        !           180:     struct ics_irq_state *irqs;
        !           181:     struct icp_state *icp;
        !           182: };
        !           183: 
        !           184: static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
        !           185: {
        !           186:     return (nr >= ics->offset)
        !           187:         && (nr < (ics->offset + ics->nr_irqs));
        !           188: }
        !           189: 
        !           190: static void ics_set_irq_msi(void *opaque, int nr, int val)
        !           191: {
        !           192:     struct ics_state *ics = (struct ics_state *)opaque;
        !           193:     struct ics_irq_state *irq = ics->irqs + nr;
        !           194: 
        !           195:     if (val) {
        !           196:         if (irq->priority == 0xff) {
        !           197:             irq->masked_pending = 1;
        !           198:             /* masked pending */ ;
        !           199:         } else  {
        !           200:             icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority);
        !           201:         }
        !           202:     }
        !           203: }
        !           204: 
        !           205: static void ics_reject_msi(struct ics_state *ics, int nr)
        !           206: {
        !           207:     struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
        !           208: 
        !           209:     irq->rejected = 1;
        !           210: }
        !           211: 
        !           212: static void ics_resend_msi(struct ics_state *ics)
        !           213: {
        !           214:     int i;
        !           215: 
        !           216:     for (i = 0; i < ics->nr_irqs; i++) {
        !           217:         struct ics_irq_state *irq = ics->irqs + i;
        !           218: 
        !           219:         /* FIXME: filter by server#? */
        !           220:         if (irq->rejected) {
        !           221:             irq->rejected = 0;
        !           222:             if (irq->priority != 0xff) {
        !           223:                 icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
        !           224:             }
        !           225:         }
        !           226:     }
        !           227: }
        !           228: 
        !           229: static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
        !           230:                                uint8_t priority)
        !           231: {
        !           232:     struct ics_irq_state *irq = ics->irqs + nr;
        !           233: 
        !           234:     irq->server = server;
        !           235:     irq->priority = priority;
        !           236: 
        !           237:     if (!irq->masked_pending || (priority == 0xff)) {
        !           238:         return;
        !           239:     }
        !           240: 
        !           241:     irq->masked_pending = 0;
        !           242:     icp_irq(ics->icp, server, nr + ics->offset, priority);
        !           243: }
        !           244: 
        !           245: static void ics_reject(struct ics_state *ics, int nr)
        !           246: {
        !           247:     ics_reject_msi(ics, nr);
        !           248: }
        !           249: 
        !           250: static void ics_resend(struct ics_state *ics)
        !           251: {
        !           252:     ics_resend_msi(ics);
        !           253: }
        !           254: 
        !           255: static void ics_eoi(struct ics_state *ics, int nr)
        !           256: {
        !           257: }
        !           258: 
        !           259: /*
        !           260:  * Exported functions
        !           261:  */
        !           262: 
        !           263: qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
        !           264: {
        !           265:     if ((irq < icp->ics->offset)
        !           266:         || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
        !           267:         return NULL;
        !           268:     }
        !           269: 
        !           270:     return icp->ics->qirqs[irq - icp->ics->offset];
        !           271: }
        !           272: 
        !           273: static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr,
        !           274:                            target_ulong opcode, target_ulong *args)
        !           275: {
        !           276:     target_ulong cppr = args[0];
        !           277: 
        !           278:     icp_set_cppr(spapr->icp, env->cpu_index, cppr);
        !           279:     return H_SUCCESS;
        !           280: }
        !           281: 
        !           282: static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr,
        !           283:                           target_ulong opcode, target_ulong *args)
        !           284: {
        !           285:     target_ulong server = args[0];
        !           286:     target_ulong mfrr = args[1];
        !           287: 
        !           288:     if (server >= spapr->icp->nr_servers) {
        !           289:         return H_PARAMETER;
        !           290:     }
        !           291: 
        !           292:     icp_set_mfrr(spapr->icp, server, mfrr);
        !           293:     return H_SUCCESS;
        !           294: 
        !           295: }
        !           296: 
        !           297: static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr,
        !           298:                            target_ulong opcode, target_ulong *args)
        !           299: {
        !           300:     uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index);
        !           301: 
        !           302:     args[0] = xirr;
        !           303:     return H_SUCCESS;
        !           304: }
        !           305: 
        !           306: static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr,
        !           307:                           target_ulong opcode, target_ulong *args)
        !           308: {
        !           309:     target_ulong xirr = args[0];
        !           310: 
        !           311:     icp_eoi(spapr->icp, env->cpu_index, xirr);
        !           312:     return H_SUCCESS;
        !           313: }
        !           314: 
        !           315: static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
        !           316:                           uint32_t nargs, target_ulong args,
        !           317:                           uint32_t nret, target_ulong rets)
        !           318: {
        !           319:     struct ics_state *ics = spapr->icp->ics;
        !           320:     uint32_t nr, server, priority;
        !           321: 
        !           322:     if ((nargs != 3) || (nret != 1)) {
        !           323:         rtas_st(rets, 0, -3);
        !           324:         return;
        !           325:     }
        !           326: 
        !           327:     nr = rtas_ld(args, 0);
        !           328:     server = rtas_ld(args, 1);
        !           329:     priority = rtas_ld(args, 2);
        !           330: 
        !           331:     if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
        !           332:         || (priority > 0xff)) {
        !           333:         rtas_st(rets, 0, -3);
        !           334:         return;
        !           335:     }
        !           336: 
        !           337:     ics_write_xive_msi(ics, nr - ics->offset, server, priority);
        !           338: 
        !           339:     rtas_st(rets, 0, 0); /* Success */
        !           340: }
        !           341: 
        !           342: static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
        !           343:                           uint32_t nargs, target_ulong args,
        !           344:                           uint32_t nret, target_ulong rets)
        !           345: {
        !           346:     struct ics_state *ics = spapr->icp->ics;
        !           347:     uint32_t nr;
        !           348: 
        !           349:     if ((nargs != 1) || (nret != 3)) {
        !           350:         rtas_st(rets, 0, -3);
        !           351:         return;
        !           352:     }
        !           353: 
        !           354:     nr = rtas_ld(args, 0);
        !           355: 
        !           356:     if (!ics_valid_irq(ics, nr)) {
        !           357:         rtas_st(rets, 0, -3);
        !           358:         return;
        !           359:     }
        !           360: 
        !           361:     rtas_st(rets, 0, 0); /* Success */
        !           362:     rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
        !           363:     rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
        !           364: }
        !           365: 
        !           366: static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
        !           367:                          uint32_t nargs, target_ulong args,
        !           368:                          uint32_t nret, target_ulong rets)
        !           369: {
        !           370:     struct ics_state *ics = spapr->icp->ics;
        !           371:     uint32_t nr;
        !           372: 
        !           373:     if ((nargs != 1) || (nret != 1)) {
        !           374:         rtas_st(rets, 0, -3);
        !           375:         return;
        !           376:     }
        !           377: 
        !           378:     nr = rtas_ld(args, 0);
        !           379: 
        !           380:     if (!ics_valid_irq(ics, nr)) {
        !           381:         rtas_st(rets, 0, -3);
        !           382:         return;
        !           383:     }
        !           384: 
        !           385:     /* This is a NOP for now, since the described PAPR semantics don't
        !           386:      * seem to gel with what Linux does */
        !           387: #if 0
        !           388:     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
        !           389: 
        !           390:     irq->saved_priority = irq->priority;
        !           391:     ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff);
        !           392: #endif
        !           393: 
        !           394:     rtas_st(rets, 0, 0); /* Success */
        !           395: }
        !           396: 
        !           397: static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
        !           398:                         uint32_t nargs, target_ulong args,
        !           399:                         uint32_t nret, target_ulong rets)
        !           400: {
        !           401:     struct ics_state *ics = spapr->icp->ics;
        !           402:     uint32_t nr;
        !           403: 
        !           404:     if ((nargs != 1) || (nret != 1)) {
        !           405:         rtas_st(rets, 0, -3);
        !           406:         return;
        !           407:     }
        !           408: 
        !           409:     nr = rtas_ld(args, 0);
        !           410: 
        !           411:     if (!ics_valid_irq(ics, nr)) {
        !           412:         rtas_st(rets, 0, -3);
        !           413:         return;
        !           414:     }
        !           415: 
        !           416:     /* This is a NOP for now, since the described PAPR semantics don't
        !           417:      * seem to gel with what Linux does */
        !           418: #if 0
        !           419:     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
        !           420: 
        !           421:     ics_write_xive_msi(xics, nr - xics->offset,
        !           422:                        irq->server, irq->saved_priority);
        !           423: #endif
        !           424: 
        !           425:     rtas_st(rets, 0, 0); /* Success */
        !           426: }
        !           427: 
        !           428: struct icp_state *xics_system_init(int nr_irqs)
        !           429: {
        !           430:     CPUState *env;
        !           431:     int max_server_num;
        !           432:     int i;
        !           433:     struct icp_state *icp;
        !           434:     struct ics_state *ics;
        !           435: 
        !           436:     max_server_num = -1;
        !           437:     for (env = first_cpu; env != NULL; env = env->next_cpu) {
        !           438:         if (env->cpu_index > max_server_num) {
        !           439:             max_server_num = env->cpu_index;
        !           440:         }
        !           441:     }
        !           442: 
        !           443:     icp = qemu_mallocz(sizeof(*icp));
        !           444:     icp->nr_servers = max_server_num + 1;
        !           445:     icp->ss = qemu_mallocz(icp->nr_servers*sizeof(struct icp_server_state));
        !           446: 
        !           447:     for (i = 0; i < icp->nr_servers; i++) {
        !           448:         icp->ss[i].mfrr = 0xff;
        !           449:     }
        !           450: 
        !           451:     for (env = first_cpu; env != NULL; env = env->next_cpu) {
        !           452:         struct icp_server_state *ss = &icp->ss[env->cpu_index];
        !           453: 
        !           454:         switch (PPC_INPUT(env)) {
        !           455:         case PPC_FLAGS_INPUT_POWER7:
        !           456:             ss->output = env->irq_inputs[POWER7_INPUT_INT];
        !           457:             break;
        !           458: 
        !           459:         case PPC_FLAGS_INPUT_970:
        !           460:             ss->output = env->irq_inputs[PPC970_INPUT_INT];
        !           461:             break;
        !           462: 
        !           463:         default:
        !           464:             hw_error("XICS interrupt model does not support this CPU bus "
        !           465:                      "model\n");
        !           466:             exit(1);
        !           467:         }
        !           468:     }
        !           469: 
        !           470:     ics = qemu_mallocz(sizeof(*ics));
        !           471:     ics->nr_irqs = nr_irqs;
        !           472:     ics->offset = 16;
        !           473:     ics->irqs = qemu_mallocz(nr_irqs * sizeof(struct ics_irq_state));
        !           474: 
        !           475:     icp->ics = ics;
        !           476:     ics->icp = icp;
        !           477: 
        !           478:     for (i = 0; i < nr_irqs; i++) {
        !           479:         ics->irqs[i].priority = 0xff;
        !           480:         ics->irqs[i].saved_priority = 0xff;
        !           481:     }
        !           482: 
        !           483:     ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
        !           484: 
        !           485:     spapr_register_hypercall(H_CPPR, h_cppr);
        !           486:     spapr_register_hypercall(H_IPI, h_ipi);
        !           487:     spapr_register_hypercall(H_XIRR, h_xirr);
        !           488:     spapr_register_hypercall(H_EOI, h_eoi);
        !           489: 
        !           490:     spapr_rtas_register("ibm,set-xive", rtas_set_xive);
        !           491:     spapr_rtas_register("ibm,get-xive", rtas_get_xive);
        !           492:     spapr_rtas_register("ibm,int-off", rtas_int_off);
        !           493:     spapr_rtas_register("ibm,int-on", rtas_int_on);
        !           494: 
        !           495:     return icp;
        !           496: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.