File:  [Qemu by Fabrice Bellard] / qemu / hw / openpic.c
Revision 1.1.1.10 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:46:39 2018 UTC (2 years, 6 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    1: /*
    2:  * OpenPIC emulation
    3:  *
    4:  * Copyright (c) 2004 Jocelyn Mayer
    5:  *               2011 Alexander Graf
    6:  *
    7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8:  * of this software and associated documentation files (the "Software"), to deal
    9:  * in the Software without restriction, including without limitation the rights
   10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11:  * copies of the Software, and to permit persons to whom the Software is
   12:  * furnished to do so, subject to the following conditions:
   13:  *
   14:  * The above copyright notice and this permission notice shall be included in
   15:  * all copies or substantial portions of the Software.
   16:  *
   17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   23:  * THE SOFTWARE.
   24:  */
   25: /*
   26:  *
   27:  * Based on OpenPic implementations:
   28:  * - Intel GW80314 I/O companion chip developer's manual
   29:  * - Motorola MPC8245 & MPC8540 user manuals.
   30:  * - Motorola MCP750 (aka Raven) programmer manual.
   31:  * - Motorola Harrier programmer manuel
   32:  *
   33:  * Serial interrupts, as implemented in Raven chipset are not supported yet.
   34:  *
   35:  */
   36: #include "hw.h"
   37: #include "ppc_mac.h"
   38: #include "pci.h"
   39: #include "openpic.h"
   40: 
   41: //#define DEBUG_OPENPIC
   42: 
   43: #ifdef DEBUG_OPENPIC
   44: #define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
   45: #else
   46: #define DPRINTF(fmt, ...) do { } while (0)
   47: #endif
   48: 
   49: #define USE_MPCxxx /* Intel model is broken, for now */
   50: 
   51: #if defined (USE_INTEL_GW80314)
   52: /* Intel GW80314 I/O Companion chip */
   53: 
   54: #define MAX_CPU     4
   55: #define MAX_IRQ    32
   56: #define MAX_DBL     4
   57: #define MAX_MBX     4
   58: #define MAX_TMR     4
   59: #define VECTOR_BITS 8
   60: #define MAX_IPI     4
   61: 
   62: #define VID (0x00000000)
   63: 
   64: #elif defined(USE_MPCxxx)
   65: 
   66: #define MAX_CPU    15
   67: #define MAX_IRQ   128
   68: #define MAX_DBL     0
   69: #define MAX_MBX     0
   70: #define MAX_TMR     4
   71: #define VECTOR_BITS 8
   72: #define MAX_IPI     4
   73: #define VID         0x03 /* MPIC version ID */
   74: #define VENI        0x00000000 /* Vendor ID */
   75: 
   76: enum {
   77:     IRQ_IPVP = 0,
   78:     IRQ_IDE,
   79: };
   80: 
   81: /* OpenPIC */
   82: #define OPENPIC_MAX_CPU      2
   83: #define OPENPIC_MAX_IRQ     64
   84: #define OPENPIC_EXT_IRQ     48
   85: #define OPENPIC_MAX_TMR      MAX_TMR
   86: #define OPENPIC_MAX_IPI      MAX_IPI
   87: 
   88: /* Interrupt definitions */
   89: #define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
   90: #define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
   91: #define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
   92: #if OPENPIC_MAX_IPI > 0
   93: #define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
   94: #define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
   95: #else
   96: #define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
   97: #define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
   98: #endif
   99: 
  100: /* MPIC */
  101: #define MPIC_MAX_CPU      1
  102: #define MPIC_MAX_EXT     12
  103: #define MPIC_MAX_INT     64
  104: #define MPIC_MAX_MSG      4
  105: #define MPIC_MAX_MSI      8
  106: #define MPIC_MAX_TMR      MAX_TMR
  107: #define MPIC_MAX_IPI      MAX_IPI
  108: #define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
  109: 
  110: /* Interrupt definitions */
  111: #define MPIC_EXT_IRQ      0
  112: #define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
  113: #define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
  114: #define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
  115: #define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
  116: #define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
  117: 
  118: #define MPIC_GLB_REG_START        0x0
  119: #define MPIC_GLB_REG_SIZE         0x10F0
  120: #define MPIC_TMR_REG_START        0x10F0
  121: #define MPIC_TMR_REG_SIZE         0x220
  122: #define MPIC_EXT_REG_START        0x10000
  123: #define MPIC_EXT_REG_SIZE         0x180
  124: #define MPIC_INT_REG_START        0x10200
  125: #define MPIC_INT_REG_SIZE         0x800
  126: #define MPIC_MSG_REG_START        0x11600
  127: #define MPIC_MSG_REG_SIZE         0x100
  128: #define MPIC_MSI_REG_START        0x11C00
  129: #define MPIC_MSI_REG_SIZE         0x100
  130: #define MPIC_CPU_REG_START        0x20000
  131: #define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
  132: 
  133: enum mpic_ide_bits {
  134:     IDR_EP     = 31,
  135:     IDR_CI0     = 30,
  136:     IDR_CI1     = 29,
  137:     IDR_P1     = 1,
  138:     IDR_P0     = 0,
  139: };
  140: 
  141: #else
  142: #error "Please select which OpenPic implementation is to be emulated"
  143: #endif
  144: 
  145: #define OPENPIC_PAGE_SIZE 4096
  146: 
  147: #define BF_WIDTH(_bits_) \
  148: (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
  149: 
  150: static inline void set_bit (uint32_t *field, int bit)
  151: {
  152:     field[bit >> 5] |= 1 << (bit & 0x1F);
  153: }
  154: 
  155: static inline void reset_bit (uint32_t *field, int bit)
  156: {
  157:     field[bit >> 5] &= ~(1 << (bit & 0x1F));
  158: }
  159: 
  160: static inline int test_bit (uint32_t *field, int bit)
  161: {
  162:     return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
  163: }
  164: 
  165: static int get_current_cpu(void)
  166: {
  167:   return cpu_single_env->cpu_index;
  168: }
  169: 
  170: static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
  171:                                           int idx);
  172: static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
  173:                                        uint32_t val, int idx);
  174: 
  175: enum {
  176:     IRQ_EXTERNAL = 0x01,
  177:     IRQ_INTERNAL = 0x02,
  178:     IRQ_TIMER    = 0x04,
  179:     IRQ_SPECIAL  = 0x08,
  180: };
  181: 
  182: typedef struct IRQ_queue_t {
  183:     uint32_t queue[BF_WIDTH(MAX_IRQ)];
  184:     int next;
  185:     int priority;
  186: } IRQ_queue_t;
  187: 
  188: typedef struct IRQ_src_t {
  189:     uint32_t ipvp;  /* IRQ vector/priority register */
  190:     uint32_t ide;   /* IRQ destination register */
  191:     int type;
  192:     int last_cpu;
  193:     int pending;    /* TRUE if IRQ is pending */
  194: } IRQ_src_t;
  195: 
  196: enum IPVP_bits {
  197:     IPVP_MASK     = 31,
  198:     IPVP_ACTIVITY = 30,
  199:     IPVP_MODE     = 29,
  200:     IPVP_POLARITY = 23,
  201:     IPVP_SENSE    = 22,
  202: };
  203: #define IPVP_PRIORITY_MASK     (0x1F << 16)
  204: #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
  205: #define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
  206: #define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
  207: 
  208: typedef struct IRQ_dst_t {
  209:     uint32_t tfrr;
  210:     uint32_t pctp; /* CPU current task priority */
  211:     uint32_t pcsr; /* CPU sensitivity register */
  212:     IRQ_queue_t raised;
  213:     IRQ_queue_t servicing;
  214:     qemu_irq *irqs;
  215: } IRQ_dst_t;
  216: 
  217: typedef struct openpic_t {
  218:     PCIDevice pci_dev;
  219:     MemoryRegion mem;
  220: 
  221:     /* Sub-regions */
  222:     MemoryRegion sub_io_mem[7];
  223: 
  224:     /* Global registers */
  225:     uint32_t frep; /* Feature reporting register */
  226:     uint32_t glbc; /* Global configuration register  */
  227:     uint32_t micr; /* MPIC interrupt configuration register */
  228:     uint32_t veni; /* Vendor identification register */
  229:     uint32_t pint; /* Processor initialization register */
  230:     uint32_t spve; /* Spurious vector register */
  231:     uint32_t tifr; /* Timer frequency reporting register */
  232:     /* Source registers */
  233:     IRQ_src_t src[MAX_IRQ];
  234:     /* Local registers per output pin */
  235:     IRQ_dst_t dst[MAX_CPU];
  236:     int nb_cpus;
  237:     /* Timer registers */
  238:     struct {
  239:         uint32_t ticc;  /* Global timer current count register */
  240:         uint32_t tibc;  /* Global timer base count register */
  241:     } timers[MAX_TMR];
  242: #if MAX_DBL > 0
  243:     /* Doorbell registers */
  244:     uint32_t dar;        /* Doorbell activate register */
  245:     struct {
  246:         uint32_t dmr;    /* Doorbell messaging register */
  247:     } doorbells[MAX_DBL];
  248: #endif
  249: #if MAX_MBX > 0
  250:     /* Mailbox registers */
  251:     struct {
  252:         uint32_t mbr;    /* Mailbox register */
  253:     } mailboxes[MAX_MAILBOXES];
  254: #endif
  255:     /* IRQ out is used when in bypass mode (not implemented) */
  256:     qemu_irq irq_out;
  257:     int max_irq;
  258:     int irq_ipi0;
  259:     int irq_tim0;
  260:     void (*reset) (void *);
  261:     void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
  262: } openpic_t;
  263: 
  264: static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
  265: {
  266:     set_bit(q->queue, n_IRQ);
  267: }
  268: 
  269: static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
  270: {
  271:     reset_bit(q->queue, n_IRQ);
  272: }
  273: 
  274: static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
  275: {
  276:     return test_bit(q->queue, n_IRQ);
  277: }
  278: 
  279: static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
  280: {
  281:     int next, i;
  282:     int priority;
  283: 
  284:     next = -1;
  285:     priority = -1;
  286:     for (i = 0; i < opp->max_irq; i++) {
  287:         if (IRQ_testbit(q, i)) {
  288:             DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
  289:                     i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
  290:             if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
  291:                 next = i;
  292:                 priority = IPVP_PRIORITY(opp->src[i].ipvp);
  293:             }
  294:         }
  295:     }
  296:     q->next = next;
  297:     q->priority = priority;
  298: }
  299: 
  300: static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
  301: {
  302:     if (q->next == -1) {
  303:         /* XXX: optimize */
  304:         IRQ_check(opp, q);
  305:     }
  306: 
  307:     return q->next;
  308: }
  309: 
  310: static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
  311: {
  312:     IRQ_dst_t *dst;
  313:     IRQ_src_t *src;
  314:     int priority;
  315: 
  316:     dst = &opp->dst[n_CPU];
  317:     src = &opp->src[n_IRQ];
  318:     priority = IPVP_PRIORITY(src->ipvp);
  319:     if (priority <= dst->pctp) {
  320:         /* Too low priority */
  321:         DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
  322:                 __func__, n_IRQ, n_CPU);
  323:         return;
  324:     }
  325:     if (IRQ_testbit(&dst->raised, n_IRQ)) {
  326:         /* Interrupt miss */
  327:         DPRINTF("%s: IRQ %d was missed on CPU %d\n",
  328:                 __func__, n_IRQ, n_CPU);
  329:         return;
  330:     }
  331:     set_bit(&src->ipvp, IPVP_ACTIVITY);
  332:     IRQ_setbit(&dst->raised, n_IRQ);
  333:     if (priority < dst->raised.priority) {
  334:         /* An higher priority IRQ is already raised */
  335:         DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
  336:                 __func__, n_IRQ, dst->raised.next, n_CPU);
  337:         return;
  338:     }
  339:     IRQ_get_next(opp, &dst->raised);
  340:     if (IRQ_get_next(opp, &dst->servicing) != -1 &&
  341:         priority <= dst->servicing.priority) {
  342:         DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
  343:                 __func__, n_IRQ, dst->servicing.next, n_CPU);
  344:         /* Already servicing a higher priority IRQ */
  345:         return;
  346:     }
  347:     DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
  348:     opp->irq_raise(opp, n_CPU, src);
  349: }
  350: 
  351: /* update pic state because registers for n_IRQ have changed value */
  352: static void openpic_update_irq(openpic_t *opp, int n_IRQ)
  353: {
  354:     IRQ_src_t *src;
  355:     int i;
  356: 
  357:     src = &opp->src[n_IRQ];
  358: 
  359:     if (!src->pending) {
  360:         /* no irq pending */
  361:         DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
  362:         return;
  363:     }
  364:     if (test_bit(&src->ipvp, IPVP_MASK)) {
  365:         /* Interrupt source is disabled */
  366:         DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
  367:         return;
  368:     }
  369:     if (IPVP_PRIORITY(src->ipvp) == 0) {
  370:         /* Priority set to zero */
  371:         DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
  372:         return;
  373:     }
  374:     if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
  375:         /* IRQ already active */
  376:         DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
  377:         return;
  378:     }
  379:     if (src->ide == 0x00000000) {
  380:         /* No target */
  381:         DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
  382:         return;
  383:     }
  384: 
  385:     if (src->ide == (1 << src->last_cpu)) {
  386:         /* Only one CPU is allowed to receive this IRQ */
  387:         IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
  388:     } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
  389:         /* Directed delivery mode */
  390:         for (i = 0; i < opp->nb_cpus; i++) {
  391:             if (test_bit(&src->ide, i))
  392:                 IRQ_local_pipe(opp, i, n_IRQ);
  393:         }
  394:     } else {
  395:         /* Distributed delivery mode */
  396:         for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
  397:             if (i == opp->nb_cpus)
  398:                 i = 0;
  399:             if (test_bit(&src->ide, i)) {
  400:                 IRQ_local_pipe(opp, i, n_IRQ);
  401:                 src->last_cpu = i;
  402:                 break;
  403:             }
  404:         }
  405:     }
  406: }
  407: 
  408: static void openpic_set_irq(void *opaque, int n_IRQ, int level)
  409: {
  410:     openpic_t *opp = opaque;
  411:     IRQ_src_t *src;
  412: 
  413:     src = &opp->src[n_IRQ];
  414:     DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
  415:             n_IRQ, level, src->ipvp);
  416:     if (test_bit(&src->ipvp, IPVP_SENSE)) {
  417:         /* level-sensitive irq */
  418:         src->pending = level;
  419:         if (!level)
  420:             reset_bit(&src->ipvp, IPVP_ACTIVITY);
  421:     } else {
  422:         /* edge-sensitive irq */
  423:         if (level)
  424:             src->pending = 1;
  425:     }
  426:     openpic_update_irq(opp, n_IRQ);
  427: }
  428: 
  429: static void openpic_reset (void *opaque)
  430: {
  431:     openpic_t *opp = (openpic_t *)opaque;
  432:     int i;
  433: 
  434:     opp->glbc = 0x80000000;
  435:     /* Initialise controller registers */
  436:     opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
  437:     opp->veni = VENI;
  438:     opp->pint = 0x00000000;
  439:     opp->spve = 0x000000FF;
  440:     opp->tifr = 0x003F7A00;
  441:     /* ? */
  442:     opp->micr = 0x00000000;
  443:     /* Initialise IRQ sources */
  444:     for (i = 0; i < opp->max_irq; i++) {
  445:         opp->src[i].ipvp = 0xA0000000;
  446:         opp->src[i].ide  = 0x00000000;
  447:     }
  448:     /* Initialise IRQ destinations */
  449:     for (i = 0; i < MAX_CPU; i++) {
  450:         opp->dst[i].pctp      = 0x0000000F;
  451:         opp->dst[i].pcsr      = 0x00000000;
  452:         memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
  453:         opp->dst[i].raised.next = -1;
  454:         memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
  455:         opp->dst[i].servicing.next = -1;
  456:     }
  457:     /* Initialise timers */
  458:     for (i = 0; i < MAX_TMR; i++) {
  459:         opp->timers[i].ticc = 0x00000000;
  460:         opp->timers[i].tibc = 0x80000000;
  461:     }
  462:     /* Initialise doorbells */
  463: #if MAX_DBL > 0
  464:     opp->dar = 0x00000000;
  465:     for (i = 0; i < MAX_DBL; i++) {
  466:         opp->doorbells[i].dmr  = 0x00000000;
  467:     }
  468: #endif
  469:     /* Initialise mailboxes */
  470: #if MAX_MBX > 0
  471:     for (i = 0; i < MAX_MBX; i++) { /* ? */
  472:         opp->mailboxes[i].mbr   = 0x00000000;
  473:     }
  474: #endif
  475:     /* Go out of RESET state */
  476:     opp->glbc = 0x00000000;
  477: }
  478: 
  479: static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
  480: {
  481:     return opp->src[n_IRQ].ide;
  482: }
  483: 
  484: static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
  485: {
  486:     return opp->src[n_IRQ].ipvp;
  487: }
  488: 
  489: static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
  490: {
  491:     uint32_t tmp;
  492: 
  493:     tmp = val & 0xC0000000;
  494:     tmp |= val & ((1ULL << MAX_CPU) - 1);
  495:     opp->src[n_IRQ].ide = tmp;
  496:     DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
  497: }
  498: 
  499: static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
  500: {
  501:     /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
  502:     /* ACTIVITY bit is read-only */
  503:     opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
  504:                          | (val & 0x800F00FF);
  505:     openpic_update_irq(opp, n_IRQ);
  506:     DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
  507:             opp->src[n_IRQ].ipvp);
  508: }
  509: 
  510: #if 0 // Code provision for Intel model
  511: #if MAX_DBL > 0
  512: static uint32_t read_doorbell_register (openpic_t *opp,
  513:                                         int n_dbl, uint32_t offset)
  514: {
  515:     uint32_t retval;
  516: 
  517:     switch (offset) {
  518:     case DBL_IPVP_OFFSET:
  519:         retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl);
  520:         break;
  521:     case DBL_IDE_OFFSET:
  522:         retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl);
  523:         break;
  524:     case DBL_DMR_OFFSET:
  525:         retval = opp->doorbells[n_dbl].dmr;
  526:         break;
  527:     }
  528: 
  529:     return retval;
  530: }
  531: 
  532: static void write_doorbell_register (penpic_t *opp, int n_dbl,
  533:                                      uint32_t offset, uint32_t value)
  534: {
  535:     switch (offset) {
  536:     case DBL_IVPR_OFFSET:
  537:         write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value);
  538:         break;
  539:     case DBL_IDE_OFFSET:
  540:         write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value);
  541:         break;
  542:     case DBL_DMR_OFFSET:
  543:         opp->doorbells[n_dbl].dmr = value;
  544:         break;
  545:     }
  546: }
  547: #endif
  548: 
  549: #if MAX_MBX > 0
  550: static uint32_t read_mailbox_register (openpic_t *opp,
  551:                                        int n_mbx, uint32_t offset)
  552: {
  553:     uint32_t retval;
  554: 
  555:     switch (offset) {
  556:     case MBX_MBR_OFFSET:
  557:         retval = opp->mailboxes[n_mbx].mbr;
  558:         break;
  559:     case MBX_IVPR_OFFSET:
  560:         retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx);
  561:         break;
  562:     case MBX_DMR_OFFSET:
  563:         retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx);
  564:         break;
  565:     }
  566: 
  567:     return retval;
  568: }
  569: 
  570: static void write_mailbox_register (openpic_t *opp, int n_mbx,
  571:                                     uint32_t address, uint32_t value)
  572: {
  573:     switch (offset) {
  574:     case MBX_MBR_OFFSET:
  575:         opp->mailboxes[n_mbx].mbr = value;
  576:         break;
  577:     case MBX_IVPR_OFFSET:
  578:         write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value);
  579:         break;
  580:     case MBX_DMR_OFFSET:
  581:         write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value);
  582:         break;
  583:     }
  584: }
  585: #endif
  586: #endif /* 0 : Code provision for Intel model */
  587: 
  588: static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val)
  589: {
  590:     openpic_t *opp = opaque;
  591:     IRQ_dst_t *dst;
  592:     int idx;
  593: 
  594:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
  595:     if (addr & 0xF)
  596:         return;
  597:     switch (addr) {
  598:     case 0x40:
  599:     case 0x50:
  600:     case 0x60:
  601:     case 0x70:
  602:     case 0x80:
  603:     case 0x90:
  604:     case 0xA0:
  605:     case 0xB0:
  606:         openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
  607:         break;
  608:     case 0x1000: /* FREP */
  609:         break;
  610:     case 0x1020: /* GLBC */
  611:         if (val & 0x80000000 && opp->reset)
  612:             opp->reset(opp);
  613:         opp->glbc = val & ~0x80000000;
  614:         break;
  615:     case 0x1080: /* VENI */
  616:         break;
  617:     case 0x1090: /* PINT */
  618:         for (idx = 0; idx < opp->nb_cpus; idx++) {
  619:             if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
  620:                 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
  621:                 dst = &opp->dst[idx];
  622:                 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
  623:             } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
  624:                 DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
  625:                 dst = &opp->dst[idx];
  626:                 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
  627:             }
  628:         }
  629:         opp->pint = val;
  630:         break;
  631:     case 0x10A0: /* IPI_IPVP */
  632:     case 0x10B0:
  633:     case 0x10C0:
  634:     case 0x10D0:
  635:         {
  636:             int idx;
  637:             idx = (addr - 0x10A0) >> 4;
  638:             write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
  639:         }
  640:         break;
  641:     case 0x10E0: /* SPVE */
  642:         opp->spve = val & 0x000000FF;
  643:         break;
  644:     case 0x10F0: /* TIFR */
  645:         opp->tifr = val;
  646:         break;
  647:     default:
  648:         break;
  649:     }
  650: }
  651: 
  652: static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
  653: {
  654:     openpic_t *opp = opaque;
  655:     uint32_t retval;
  656: 
  657:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
  658:     retval = 0xFFFFFFFF;
  659:     if (addr & 0xF)
  660:         return retval;
  661:     switch (addr) {
  662:     case 0x1000: /* FREP */
  663:         retval = opp->frep;
  664:         break;
  665:     case 0x1020: /* GLBC */
  666:         retval = opp->glbc;
  667:         break;
  668:     case 0x1080: /* VENI */
  669:         retval = opp->veni;
  670:         break;
  671:     case 0x1090: /* PINT */
  672:         retval = 0x00000000;
  673:         break;
  674:     case 0x40:
  675:     case 0x50:
  676:     case 0x60:
  677:     case 0x70:
  678:     case 0x80:
  679:     case 0x90:
  680:     case 0xA0:
  681:     case 0xB0:
  682:         retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
  683:         break;
  684:     case 0x10A0: /* IPI_IPVP */
  685:     case 0x10B0:
  686:     case 0x10C0:
  687:     case 0x10D0:
  688:         {
  689:             int idx;
  690:             idx = (addr - 0x10A0) >> 4;
  691:             retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
  692:         }
  693:         break;
  694:     case 0x10E0: /* SPVE */
  695:         retval = opp->spve;
  696:         break;
  697:     case 0x10F0: /* TIFR */
  698:         retval = opp->tifr;
  699:         break;
  700:     default:
  701:         break;
  702:     }
  703:     DPRINTF("%s: => %08x\n", __func__, retval);
  704: 
  705:     return retval;
  706: }
  707: 
  708: static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
  709: {
  710:     openpic_t *opp = opaque;
  711:     int idx;
  712: 
  713:     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
  714:     if (addr & 0xF)
  715:         return;
  716:     addr -= 0x10;
  717:     addr &= 0xFFFF;
  718:     idx = (addr & 0xFFF0) >> 6;
  719:     addr = addr & 0x30;
  720:     switch (addr) {
  721:     case 0x00: /* TICC */
  722:         break;
  723:     case 0x10: /* TIBC */
  724:         if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
  725:             (val & 0x80000000) == 0 &&
  726:             (opp->timers[idx].tibc & 0x80000000) != 0)
  727:             opp->timers[idx].ticc &= ~0x80000000;
  728:         opp->timers[idx].tibc = val;
  729:         break;
  730:     case 0x20: /* TIVP */
  731:         write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
  732:         break;
  733:     case 0x30: /* TIDE */
  734:         write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
  735:         break;
  736:     }
  737: }
  738: 
  739: static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
  740: {
  741:     openpic_t *opp = opaque;
  742:     uint32_t retval;
  743:     int idx;
  744: 
  745:     DPRINTF("%s: addr %08x\n", __func__, addr);
  746:     retval = 0xFFFFFFFF;
  747:     if (addr & 0xF)
  748:         return retval;
  749:     addr -= 0x10;
  750:     addr &= 0xFFFF;
  751:     idx = (addr & 0xFFF0) >> 6;
  752:     addr = addr & 0x30;
  753:     switch (addr) {
  754:     case 0x00: /* TICC */
  755:         retval = opp->timers[idx].ticc;
  756:         break;
  757:     case 0x10: /* TIBC */
  758:         retval = opp->timers[idx].tibc;
  759:         break;
  760:     case 0x20: /* TIPV */
  761:         retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
  762:         break;
  763:     case 0x30: /* TIDE */
  764:         retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
  765:         break;
  766:     }
  767:     DPRINTF("%s: => %08x\n", __func__, retval);
  768: 
  769:     return retval;
  770: }
  771: 
  772: static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
  773: {
  774:     openpic_t *opp = opaque;
  775:     int idx;
  776: 
  777:     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
  778:     if (addr & 0xF)
  779:         return;
  780:     addr = addr & 0xFFF0;
  781:     idx = addr >> 5;
  782:     if (addr & 0x10) {
  783:         /* EXDE / IFEDE / IEEDE */
  784:         write_IRQreg_ide(opp, idx, val);
  785:     } else {
  786:         /* EXVP / IFEVP / IEEVP */
  787:         write_IRQreg_ipvp(opp, idx, val);
  788:     }
  789: }
  790: 
  791: static uint32_t openpic_src_read (void *opaque, uint32_t addr)
  792: {
  793:     openpic_t *opp = opaque;
  794:     uint32_t retval;
  795:     int idx;
  796: 
  797:     DPRINTF("%s: addr %08x\n", __func__, addr);
  798:     retval = 0xFFFFFFFF;
  799:     if (addr & 0xF)
  800:         return retval;
  801:     addr = addr & 0xFFF0;
  802:     idx = addr >> 5;
  803:     if (addr & 0x10) {
  804:         /* EXDE / IFEDE / IEEDE */
  805:         retval = read_IRQreg_ide(opp, idx);
  806:     } else {
  807:         /* EXVP / IFEVP / IEEVP */
  808:         retval = read_IRQreg_ipvp(opp, idx);
  809:     }
  810:     DPRINTF("%s: => %08x\n", __func__, retval);
  811: 
  812:     return retval;
  813: }
  814: 
  815: static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
  816:                                        uint32_t val, int idx)
  817: {
  818:     openpic_t *opp = opaque;
  819:     IRQ_src_t *src;
  820:     IRQ_dst_t *dst;
  821:     int s_IRQ, n_IRQ;
  822: 
  823:     DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
  824:             addr, val);
  825:     if (addr & 0xF)
  826:         return;
  827:     dst = &opp->dst[idx];
  828:     addr &= 0xFF0;
  829:     switch (addr) {
  830: #if MAX_IPI > 0
  831:     case 0x40: /* IPIDR */
  832:     case 0x50:
  833:     case 0x60:
  834:     case 0x70:
  835:         idx = (addr - 0x40) >> 4;
  836:         /* we use IDE as mask which CPUs to deliver the IPI to still. */
  837:         write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
  838:                          opp->src[opp->irq_ipi0 + idx].ide | val);
  839:         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
  840:         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
  841:         break;
  842: #endif
  843:     case 0x80: /* PCTP */
  844:         dst->pctp = val & 0x0000000F;
  845:         break;
  846:     case 0x90: /* WHOAMI */
  847:         /* Read-only register */
  848:         break;
  849:     case 0xA0: /* PIAC */
  850:         /* Read-only register */
  851:         break;
  852:     case 0xB0: /* PEOI */
  853:         DPRINTF("PEOI\n");
  854:         s_IRQ = IRQ_get_next(opp, &dst->servicing);
  855:         IRQ_resetbit(&dst->servicing, s_IRQ);
  856:         dst->servicing.next = -1;
  857:         /* Set up next servicing IRQ */
  858:         s_IRQ = IRQ_get_next(opp, &dst->servicing);
  859:         /* Check queued interrupts. */
  860:         n_IRQ = IRQ_get_next(opp, &dst->raised);
  861:         src = &opp->src[n_IRQ];
  862:         if (n_IRQ != -1 &&
  863:             (s_IRQ == -1 ||
  864:              IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
  865:             DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
  866:                     idx, n_IRQ);
  867:             opp->irq_raise(opp, idx, src);
  868:         }
  869:         break;
  870:     default:
  871:         break;
  872:     }
  873: }
  874: 
  875: static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val)
  876: {
  877:     openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
  878: }
  879: 
  880: static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
  881:                                           int idx)
  882: {
  883:     openpic_t *opp = opaque;
  884:     IRQ_src_t *src;
  885:     IRQ_dst_t *dst;
  886:     uint32_t retval;
  887:     int n_IRQ;
  888: 
  889:     DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
  890:     retval = 0xFFFFFFFF;
  891:     if (addr & 0xF)
  892:         return retval;
  893:     dst = &opp->dst[idx];
  894:     addr &= 0xFF0;
  895:     switch (addr) {
  896:     case 0x80: /* PCTP */
  897:         retval = dst->pctp;
  898:         break;
  899:     case 0x90: /* WHOAMI */
  900:         retval = idx;
  901:         break;
  902:     case 0xA0: /* PIAC */
  903:         DPRINTF("Lower OpenPIC INT output\n");
  904:         qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
  905:         n_IRQ = IRQ_get_next(opp, &dst->raised);
  906:         DPRINTF("PIAC: irq=%d\n", n_IRQ);
  907:         if (n_IRQ == -1) {
  908:             /* No more interrupt pending */
  909:             retval = IPVP_VECTOR(opp->spve);
  910:         } else {
  911:             src = &opp->src[n_IRQ];
  912:             if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
  913:                 !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
  914:                 /* - Spurious level-sensitive IRQ
  915:                  * - Priorities has been changed
  916:                  *   and the pending IRQ isn't allowed anymore
  917:                  */
  918:                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
  919:                 retval = IPVP_VECTOR(opp->spve);
  920:             } else {
  921:                 /* IRQ enter servicing state */
  922:                 IRQ_setbit(&dst->servicing, n_IRQ);
  923:                 retval = IPVP_VECTOR(src->ipvp);
  924:             }
  925:             IRQ_resetbit(&dst->raised, n_IRQ);
  926:             dst->raised.next = -1;
  927:             if (!test_bit(&src->ipvp, IPVP_SENSE)) {
  928:                 /* edge-sensitive IRQ */
  929:                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
  930:                 src->pending = 0;
  931:             }
  932: 
  933:             if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
  934:                 src->ide &= ~(1 << idx);
  935:                 if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
  936:                     /* trigger on CPUs that didn't know about it yet */
  937:                     openpic_set_irq(opp, n_IRQ, 1);
  938:                     openpic_set_irq(opp, n_IRQ, 0);
  939:                     /* if all CPUs knew about it, set active bit again */
  940:                     set_bit(&src->ipvp, IPVP_ACTIVITY);
  941:                 }
  942:             }
  943:         }
  944:         break;
  945:     case 0xB0: /* PEOI */
  946:         retval = 0;
  947:         break;
  948:     default:
  949:         break;
  950:     }
  951:     DPRINTF("%s: => %08x\n", __func__, retval);
  952: 
  953:     return retval;
  954: }
  955: 
  956: static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr)
  957: {
  958:     return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
  959: }
  960: 
  961: static void openpic_buggy_write (void *opaque,
  962:                                  target_phys_addr_t addr, uint32_t val)
  963: {
  964:     printf("Invalid OPENPIC write access !\n");
  965: }
  966: 
  967: static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
  968: {
  969:     printf("Invalid OPENPIC read access !\n");
  970: 
  971:     return -1;
  972: }
  973: 
  974: static void openpic_writel (void *opaque,
  975:                             target_phys_addr_t addr, uint32_t val)
  976: {
  977:     openpic_t *opp = opaque;
  978: 
  979:     addr &= 0x3FFFF;
  980:     DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
  981:     if (addr < 0x1100) {
  982:         /* Global registers */
  983:         openpic_gbl_write(opp, addr, val);
  984:     } else if (addr < 0x10000) {
  985:         /* Timers registers */
  986:         openpic_timer_write(opp, addr, val);
  987:     } else if (addr < 0x20000) {
  988:         /* Source registers */
  989:         openpic_src_write(opp, addr, val);
  990:     } else {
  991:         /* CPU registers */
  992:         openpic_cpu_write(opp, addr, val);
  993:     }
  994: }
  995: 
  996: static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
  997: {
  998:     openpic_t *opp = opaque;
  999:     uint32_t retval;
 1000: 
 1001:     addr &= 0x3FFFF;
 1002:     DPRINTF("%s: offset %08x\n", __func__, (int)addr);
 1003:     if (addr < 0x1100) {
 1004:         /* Global registers */
 1005:         retval = openpic_gbl_read(opp, addr);
 1006:     } else if (addr < 0x10000) {
 1007:         /* Timers registers */
 1008:         retval = openpic_timer_read(opp, addr);
 1009:     } else if (addr < 0x20000) {
 1010:         /* Source registers */
 1011:         retval = openpic_src_read(opp, addr);
 1012:     } else {
 1013:         /* CPU registers */
 1014:         retval = openpic_cpu_read(opp, addr);
 1015:     }
 1016: 
 1017:     return retval;
 1018: }
 1019: 
 1020: static uint64_t openpic_read(void *opaque, target_phys_addr_t addr,
 1021:                              unsigned size)
 1022: {
 1023:     openpic_t *opp = opaque;
 1024: 
 1025:     switch (size) {
 1026:     case 4: return openpic_readl(opp, addr);
 1027:     default: return openpic_buggy_read(opp, addr);
 1028:     }
 1029: }
 1030: 
 1031: static void openpic_write(void *opaque, target_phys_addr_t addr,
 1032:                           uint64_t data, unsigned size)
 1033: {
 1034:     openpic_t *opp = opaque;
 1035: 
 1036:     switch (size) {
 1037:     case 4: return openpic_writel(opp, addr, data);
 1038:     default: return openpic_buggy_write(opp, addr, data);
 1039:     }
 1040: }
 1041: 
 1042: static const MemoryRegionOps openpic_ops = {
 1043:     .read = openpic_read,
 1044:     .write = openpic_write,
 1045:     .endianness = DEVICE_LITTLE_ENDIAN,
 1046: };
 1047: 
 1048: static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 1049: {
 1050:     unsigned int i;
 1051: 
 1052:     for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
 1053:         qemu_put_be32s(f, &q->queue[i]);
 1054: 
 1055:     qemu_put_sbe32s(f, &q->next);
 1056:     qemu_put_sbe32s(f, &q->priority);
 1057: }
 1058: 
 1059: static void openpic_save(QEMUFile* f, void *opaque)
 1060: {
 1061:     openpic_t *opp = (openpic_t *)opaque;
 1062:     unsigned int i;
 1063: 
 1064:     qemu_put_be32s(f, &opp->frep);
 1065:     qemu_put_be32s(f, &opp->glbc);
 1066:     qemu_put_be32s(f, &opp->micr);
 1067:     qemu_put_be32s(f, &opp->veni);
 1068:     qemu_put_be32s(f, &opp->pint);
 1069:     qemu_put_be32s(f, &opp->spve);
 1070:     qemu_put_be32s(f, &opp->tifr);
 1071: 
 1072:     for (i = 0; i < opp->max_irq; i++) {
 1073:         qemu_put_be32s(f, &opp->src[i].ipvp);
 1074:         qemu_put_be32s(f, &opp->src[i].ide);
 1075:         qemu_put_sbe32s(f, &opp->src[i].type);
 1076:         qemu_put_sbe32s(f, &opp->src[i].last_cpu);
 1077:         qemu_put_sbe32s(f, &opp->src[i].pending);
 1078:     }
 1079: 
 1080:     qemu_put_sbe32s(f, &opp->nb_cpus);
 1081: 
 1082:     for (i = 0; i < opp->nb_cpus; i++) {
 1083:         qemu_put_be32s(f, &opp->dst[i].tfrr);
 1084:         qemu_put_be32s(f, &opp->dst[i].pctp);
 1085:         qemu_put_be32s(f, &opp->dst[i].pcsr);
 1086:         openpic_save_IRQ_queue(f, &opp->dst[i].raised);
 1087:         openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
 1088:     }
 1089: 
 1090:     for (i = 0; i < MAX_TMR; i++) {
 1091:         qemu_put_be32s(f, &opp->timers[i].ticc);
 1092:         qemu_put_be32s(f, &opp->timers[i].tibc);
 1093:     }
 1094: 
 1095: #if MAX_DBL > 0
 1096:     qemu_put_be32s(f, &opp->dar);
 1097: 
 1098:     for (i = 0; i < MAX_DBL; i++) {
 1099:         qemu_put_be32s(f, &opp->doorbells[i].dmr);
 1100:     }
 1101: #endif
 1102: 
 1103: #if MAX_MBX > 0
 1104:     for (i = 0; i < MAX_MAILBOXES; i++) {
 1105:         qemu_put_be32s(f, &opp->mailboxes[i].mbr);
 1106:     }
 1107: #endif
 1108: 
 1109:     pci_device_save(&opp->pci_dev, f);
 1110: }
 1111: 
 1112: static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 1113: {
 1114:     unsigned int i;
 1115: 
 1116:     for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
 1117:         qemu_get_be32s(f, &q->queue[i]);
 1118: 
 1119:     qemu_get_sbe32s(f, &q->next);
 1120:     qemu_get_sbe32s(f, &q->priority);
 1121: }
 1122: 
 1123: static int openpic_load(QEMUFile* f, void *opaque, int version_id)
 1124: {
 1125:     openpic_t *opp = (openpic_t *)opaque;
 1126:     unsigned int i;
 1127: 
 1128:     if (version_id != 1)
 1129:         return -EINVAL;
 1130: 
 1131:     qemu_get_be32s(f, &opp->frep);
 1132:     qemu_get_be32s(f, &opp->glbc);
 1133:     qemu_get_be32s(f, &opp->micr);
 1134:     qemu_get_be32s(f, &opp->veni);
 1135:     qemu_get_be32s(f, &opp->pint);
 1136:     qemu_get_be32s(f, &opp->spve);
 1137:     qemu_get_be32s(f, &opp->tifr);
 1138: 
 1139:     for (i = 0; i < opp->max_irq; i++) {
 1140:         qemu_get_be32s(f, &opp->src[i].ipvp);
 1141:         qemu_get_be32s(f, &opp->src[i].ide);
 1142:         qemu_get_sbe32s(f, &opp->src[i].type);
 1143:         qemu_get_sbe32s(f, &opp->src[i].last_cpu);
 1144:         qemu_get_sbe32s(f, &opp->src[i].pending);
 1145:     }
 1146: 
 1147:     qemu_get_sbe32s(f, &opp->nb_cpus);
 1148: 
 1149:     for (i = 0; i < opp->nb_cpus; i++) {
 1150:         qemu_get_be32s(f, &opp->dst[i].tfrr);
 1151:         qemu_get_be32s(f, &opp->dst[i].pctp);
 1152:         qemu_get_be32s(f, &opp->dst[i].pcsr);
 1153:         openpic_load_IRQ_queue(f, &opp->dst[i].raised);
 1154:         openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
 1155:     }
 1156: 
 1157:     for (i = 0; i < MAX_TMR; i++) {
 1158:         qemu_get_be32s(f, &opp->timers[i].ticc);
 1159:         qemu_get_be32s(f, &opp->timers[i].tibc);
 1160:     }
 1161: 
 1162: #if MAX_DBL > 0
 1163:     qemu_get_be32s(f, &opp->dar);
 1164: 
 1165:     for (i = 0; i < MAX_DBL; i++) {
 1166:         qemu_get_be32s(f, &opp->doorbells[i].dmr);
 1167:     }
 1168: #endif
 1169: 
 1170: #if MAX_MBX > 0
 1171:     for (i = 0; i < MAX_MAILBOXES; i++) {
 1172:         qemu_get_be32s(f, &opp->mailboxes[i].mbr);
 1173:     }
 1174: #endif
 1175: 
 1176:     return pci_device_load(&opp->pci_dev, f);
 1177: }
 1178: 
 1179: static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
 1180: {
 1181:     qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 1182: }
 1183: 
 1184: qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
 1185:                         qemu_irq **irqs, qemu_irq irq_out)
 1186: {
 1187:     openpic_t *opp;
 1188:     int i, m;
 1189: 
 1190:     /* XXX: for now, only one CPU is supported */
 1191:     if (nb_cpus != 1)
 1192:         return NULL;
 1193:     opp = g_malloc0(sizeof(openpic_t));
 1194:     memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
 1195: 
 1196:     //    isu_base &= 0xFFFC0000;
 1197:     opp->nb_cpus = nb_cpus;
 1198:     opp->max_irq = OPENPIC_MAX_IRQ;
 1199:     opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
 1200:     opp->irq_tim0 = OPENPIC_IRQ_TIM0;
 1201:     /* Set IRQ types */
 1202:     for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
 1203:         opp->src[i].type = IRQ_EXTERNAL;
 1204:     }
 1205:     for (; i < OPENPIC_IRQ_TIM0; i++) {
 1206:         opp->src[i].type = IRQ_SPECIAL;
 1207:     }
 1208: #if MAX_IPI > 0
 1209:     m = OPENPIC_IRQ_IPI0;
 1210: #else
 1211:     m = OPENPIC_IRQ_DBL0;
 1212: #endif
 1213:     for (; i < m; i++) {
 1214:         opp->src[i].type = IRQ_TIMER;
 1215:     }
 1216:     for (; i < OPENPIC_MAX_IRQ; i++) {
 1217:         opp->src[i].type = IRQ_INTERNAL;
 1218:     }
 1219:     for (i = 0; i < nb_cpus; i++)
 1220:         opp->dst[i].irqs = irqs[i];
 1221:     opp->irq_out = irq_out;
 1222: 
 1223:     register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
 1224:                     openpic_save, openpic_load, opp);
 1225:     qemu_register_reset(openpic_reset, opp);
 1226: 
 1227:     opp->irq_raise = openpic_irq_raise;
 1228:     opp->reset = openpic_reset;
 1229: 
 1230:     if (pmem)
 1231:         *pmem = &opp->mem;
 1232: 
 1233:     return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
 1234: }
 1235: 
 1236: static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
 1237: {
 1238:     int n_ci = IDR_CI0 - n_CPU;
 1239: 
 1240:     if(test_bit(&src->ide, n_ci)) {
 1241:         qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
 1242:     }
 1243:     else {
 1244:         qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 1245:     }
 1246: }
 1247: 
 1248: static void mpic_reset (void *opaque)
 1249: {
 1250:     openpic_t *mpp = (openpic_t *)opaque;
 1251:     int i;
 1252: 
 1253:     mpp->glbc = 0x80000000;
 1254:     /* Initialise controller registers */
 1255:     mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
 1256:     mpp->veni = VENI;
 1257:     mpp->pint = 0x00000000;
 1258:     mpp->spve = 0x0000FFFF;
 1259:     /* Initialise IRQ sources */
 1260:     for (i = 0; i < mpp->max_irq; i++) {
 1261:         mpp->src[i].ipvp = 0x80800000;
 1262:         mpp->src[i].ide  = 0x00000001;
 1263:     }
 1264:     /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
 1265:     for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
 1266:         mpp->src[i].ide = 0;
 1267:     }
 1268:     /* Initialise IRQ destinations */
 1269:     for (i = 0; i < MAX_CPU; i++) {
 1270:         mpp->dst[i].pctp      = 0x0000000F;
 1271:         mpp->dst[i].tfrr      = 0x00000000;
 1272:         memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
 1273:         mpp->dst[i].raised.next = -1;
 1274:         memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
 1275:         mpp->dst[i].servicing.next = -1;
 1276:     }
 1277:     /* Initialise timers */
 1278:     for (i = 0; i < MAX_TMR; i++) {
 1279:         mpp->timers[i].ticc = 0x00000000;
 1280:         mpp->timers[i].tibc = 0x80000000;
 1281:     }
 1282:     /* Go out of RESET state */
 1283:     mpp->glbc = 0x00000000;
 1284: }
 1285: 
 1286: static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val)
 1287: {
 1288:     openpic_t *mpp = opaque;
 1289:     int idx, cpu;
 1290: 
 1291:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 1292:     if (addr & 0xF)
 1293:         return;
 1294:     addr &= 0xFFFF;
 1295:     cpu = addr >> 12;
 1296:     idx = (addr >> 6) & 0x3;
 1297:     switch (addr & 0x30) {
 1298:     case 0x00: /* gtccr */
 1299:         break;
 1300:     case 0x10: /* gtbcr */
 1301:         if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
 1302:             (val & 0x80000000) == 0 &&
 1303:             (mpp->timers[idx].tibc & 0x80000000) != 0)
 1304:             mpp->timers[idx].ticc &= ~0x80000000;
 1305:         mpp->timers[idx].tibc = val;
 1306:         break;
 1307:     case 0x20: /* GTIVPR */
 1308:         write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
 1309:         break;
 1310:     case 0x30: /* GTIDR & TFRR */
 1311:         if ((addr & 0xF0) == 0xF0)
 1312:             mpp->dst[cpu].tfrr = val;
 1313:         else
 1314:             write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
 1315:         break;
 1316:     }
 1317: }
 1318: 
 1319: static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
 1320: {
 1321:     openpic_t *mpp = opaque;
 1322:     uint32_t retval;
 1323:     int idx, cpu;
 1324: 
 1325:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 1326:     retval = 0xFFFFFFFF;
 1327:     if (addr & 0xF)
 1328:         return retval;
 1329:     addr &= 0xFFFF;
 1330:     cpu = addr >> 12;
 1331:     idx = (addr >> 6) & 0x3;
 1332:     switch (addr & 0x30) {
 1333:     case 0x00: /* gtccr */
 1334:         retval = mpp->timers[idx].ticc;
 1335:         break;
 1336:     case 0x10: /* gtbcr */
 1337:         retval = mpp->timers[idx].tibc;
 1338:         break;
 1339:     case 0x20: /* TIPV */
 1340:         retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
 1341:         break;
 1342:     case 0x30: /* TIDR */
 1343:         if ((addr &0xF0) == 0XF0)
 1344:             retval = mpp->dst[cpu].tfrr;
 1345:         else
 1346:             retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
 1347:         break;
 1348:     }
 1349:     DPRINTF("%s: => %08x\n", __func__, retval);
 1350: 
 1351:     return retval;
 1352: }
 1353: 
 1354: static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
 1355:                                 uint32_t val)
 1356: {
 1357:     openpic_t *mpp = opaque;
 1358:     int idx = MPIC_EXT_IRQ;
 1359: 
 1360:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 1361:     if (addr & 0xF)
 1362:         return;
 1363: 
 1364:     if (addr < MPIC_EXT_REG_SIZE) {
 1365:         idx += (addr & 0xFFF0) >> 5;
 1366:         if (addr & 0x10) {
 1367:             /* EXDE / IFEDE / IEEDE */
 1368:             write_IRQreg_ide(mpp, idx, val);
 1369:         } else {
 1370:             /* EXVP / IFEVP / IEEVP */
 1371:             write_IRQreg_ipvp(mpp, idx, val);
 1372:         }
 1373:     }
 1374: }
 1375: 
 1376: static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
 1377: {
 1378:     openpic_t *mpp = opaque;
 1379:     uint32_t retval;
 1380:     int idx = MPIC_EXT_IRQ;
 1381: 
 1382:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 1383:     retval = 0xFFFFFFFF;
 1384:     if (addr & 0xF)
 1385:         return retval;
 1386: 
 1387:     if (addr < MPIC_EXT_REG_SIZE) {
 1388:         idx += (addr & 0xFFF0) >> 5;
 1389:         if (addr & 0x10) {
 1390:             /* EXDE / IFEDE / IEEDE */
 1391:             retval = read_IRQreg_ide(mpp, idx);
 1392:         } else {
 1393:             /* EXVP / IFEVP / IEEVP */
 1394:             retval = read_IRQreg_ipvp(mpp, idx);
 1395:         }
 1396:         DPRINTF("%s: => %08x\n", __func__, retval);
 1397:     }
 1398: 
 1399:     return retval;
 1400: }
 1401: 
 1402: static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
 1403:                                 uint32_t val)
 1404: {
 1405:     openpic_t *mpp = opaque;
 1406:     int idx = MPIC_INT_IRQ;
 1407: 
 1408:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 1409:     if (addr & 0xF)
 1410:         return;
 1411: 
 1412:     if (addr < MPIC_INT_REG_SIZE) {
 1413:         idx += (addr & 0xFFF0) >> 5;
 1414:         if (addr & 0x10) {
 1415:             /* EXDE / IFEDE / IEEDE */
 1416:             write_IRQreg_ide(mpp, idx, val);
 1417:         } else {
 1418:             /* EXVP / IFEVP / IEEVP */
 1419:             write_IRQreg_ipvp(mpp, idx, val);
 1420:         }
 1421:     }
 1422: }
 1423: 
 1424: static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
 1425: {
 1426:     openpic_t *mpp = opaque;
 1427:     uint32_t retval;
 1428:     int idx = MPIC_INT_IRQ;
 1429: 
 1430:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 1431:     retval = 0xFFFFFFFF;
 1432:     if (addr & 0xF)
 1433:         return retval;
 1434: 
 1435:     if (addr < MPIC_INT_REG_SIZE) {
 1436:         idx += (addr & 0xFFF0) >> 5;
 1437:         if (addr & 0x10) {
 1438:             /* EXDE / IFEDE / IEEDE */
 1439:             retval = read_IRQreg_ide(mpp, idx);
 1440:         } else {
 1441:             /* EXVP / IFEVP / IEEVP */
 1442:             retval = read_IRQreg_ipvp(mpp, idx);
 1443:         }
 1444:         DPRINTF("%s: => %08x\n", __func__, retval);
 1445:     }
 1446: 
 1447:     return retval;
 1448: }
 1449: 
 1450: static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
 1451:                                 uint32_t val)
 1452: {
 1453:     openpic_t *mpp = opaque;
 1454:     int idx = MPIC_MSG_IRQ;
 1455: 
 1456:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 1457:     if (addr & 0xF)
 1458:         return;
 1459: 
 1460:     if (addr < MPIC_MSG_REG_SIZE) {
 1461:         idx += (addr & 0xFFF0) >> 5;
 1462:         if (addr & 0x10) {
 1463:             /* EXDE / IFEDE / IEEDE */
 1464:             write_IRQreg_ide(mpp, idx, val);
 1465:         } else {
 1466:             /* EXVP / IFEVP / IEEVP */
 1467:             write_IRQreg_ipvp(mpp, idx, val);
 1468:         }
 1469:     }
 1470: }
 1471: 
 1472: static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
 1473: {
 1474:     openpic_t *mpp = opaque;
 1475:     uint32_t retval;
 1476:     int idx = MPIC_MSG_IRQ;
 1477: 
 1478:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 1479:     retval = 0xFFFFFFFF;
 1480:     if (addr & 0xF)
 1481:         return retval;
 1482: 
 1483:     if (addr < MPIC_MSG_REG_SIZE) {
 1484:         idx += (addr & 0xFFF0) >> 5;
 1485:         if (addr & 0x10) {
 1486:             /* EXDE / IFEDE / IEEDE */
 1487:             retval = read_IRQreg_ide(mpp, idx);
 1488:         } else {
 1489:             /* EXVP / IFEVP / IEEVP */
 1490:             retval = read_IRQreg_ipvp(mpp, idx);
 1491:         }
 1492:         DPRINTF("%s: => %08x\n", __func__, retval);
 1493:     }
 1494: 
 1495:     return retval;
 1496: }
 1497: 
 1498: static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
 1499:                                 uint32_t val)
 1500: {
 1501:     openpic_t *mpp = opaque;
 1502:     int idx = MPIC_MSI_IRQ;
 1503: 
 1504:     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 1505:     if (addr & 0xF)
 1506:         return;
 1507: 
 1508:     if (addr < MPIC_MSI_REG_SIZE) {
 1509:         idx += (addr & 0xFFF0) >> 5;
 1510:         if (addr & 0x10) {
 1511:             /* EXDE / IFEDE / IEEDE */
 1512:             write_IRQreg_ide(mpp, idx, val);
 1513:         } else {
 1514:             /* EXVP / IFEVP / IEEVP */
 1515:             write_IRQreg_ipvp(mpp, idx, val);
 1516:         }
 1517:     }
 1518: }
 1519: static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
 1520: {
 1521:     openpic_t *mpp = opaque;
 1522:     uint32_t retval;
 1523:     int idx = MPIC_MSI_IRQ;
 1524: 
 1525:     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 1526:     retval = 0xFFFFFFFF;
 1527:     if (addr & 0xF)
 1528:         return retval;
 1529: 
 1530:     if (addr < MPIC_MSI_REG_SIZE) {
 1531:         idx += (addr & 0xFFF0) >> 5;
 1532:         if (addr & 0x10) {
 1533:             /* EXDE / IFEDE / IEEDE */
 1534:             retval = read_IRQreg_ide(mpp, idx);
 1535:         } else {
 1536:             /* EXVP / IFEVP / IEEVP */
 1537:             retval = read_IRQreg_ipvp(mpp, idx);
 1538:         }
 1539:         DPRINTF("%s: => %08x\n", __func__, retval);
 1540:     }
 1541: 
 1542:     return retval;
 1543: }
 1544: 
 1545: static const MemoryRegionOps mpic_glb_ops = {
 1546:     .old_mmio = {
 1547:         .write = { openpic_buggy_write,
 1548:                    openpic_buggy_write,
 1549:                    openpic_gbl_write,
 1550:         },
 1551:         .read  = { openpic_buggy_read,
 1552:                    openpic_buggy_read,
 1553:                    openpic_gbl_read,
 1554:         },
 1555:     },
 1556:     .endianness = DEVICE_BIG_ENDIAN,
 1557: };
 1558: 
 1559: static const MemoryRegionOps mpic_tmr_ops = {
 1560:     .old_mmio = {
 1561:         .write = { openpic_buggy_write,
 1562:                    openpic_buggy_write,
 1563:                    mpic_timer_write,
 1564:         },
 1565:         .read  = { openpic_buggy_read,
 1566:                    openpic_buggy_read,
 1567:                    mpic_timer_read,
 1568:         },
 1569:     },
 1570:     .endianness = DEVICE_BIG_ENDIAN,
 1571: };
 1572: 
 1573: static const MemoryRegionOps mpic_cpu_ops = {
 1574:     .old_mmio = {
 1575:         .write = { openpic_buggy_write,
 1576:                    openpic_buggy_write,
 1577:                    openpic_cpu_write,
 1578:         },
 1579:         .read  = { openpic_buggy_read,
 1580:                    openpic_buggy_read,
 1581:                    openpic_cpu_read,
 1582:         },
 1583:     },
 1584:     .endianness = DEVICE_BIG_ENDIAN,
 1585: };
 1586: 
 1587: static const MemoryRegionOps mpic_ext_ops = {
 1588:     .old_mmio = {
 1589:         .write = { openpic_buggy_write,
 1590:                    openpic_buggy_write,
 1591:                    mpic_src_ext_write,
 1592:         },
 1593:         .read  = { openpic_buggy_read,
 1594:                    openpic_buggy_read,
 1595:                    mpic_src_ext_read,
 1596:         },
 1597:     },
 1598:     .endianness = DEVICE_BIG_ENDIAN,
 1599: };
 1600: 
 1601: static const MemoryRegionOps mpic_int_ops = {
 1602:     .old_mmio = {
 1603:         .write = { openpic_buggy_write,
 1604:                    openpic_buggy_write,
 1605:                    mpic_src_int_write,
 1606:         },
 1607:         .read  = { openpic_buggy_read,
 1608:                    openpic_buggy_read,
 1609:                    mpic_src_int_read,
 1610:         },
 1611:     },
 1612:     .endianness = DEVICE_BIG_ENDIAN,
 1613: };
 1614: 
 1615: static const MemoryRegionOps mpic_msg_ops = {
 1616:     .old_mmio = {
 1617:         .write = { openpic_buggy_write,
 1618:                    openpic_buggy_write,
 1619:                    mpic_src_msg_write,
 1620:         },
 1621:         .read  = { openpic_buggy_read,
 1622:                    openpic_buggy_read,
 1623:                    mpic_src_msg_read,
 1624:         },
 1625:     },
 1626:     .endianness = DEVICE_BIG_ENDIAN,
 1627: };
 1628: 
 1629: static const MemoryRegionOps mpic_msi_ops = {
 1630:     .old_mmio = {
 1631:         .write = { openpic_buggy_write,
 1632:                    openpic_buggy_write,
 1633:                    mpic_src_msi_write,
 1634:         },
 1635:         .read  = { openpic_buggy_read,
 1636:                    openpic_buggy_read,
 1637:                    mpic_src_msi_read,
 1638:         },
 1639:     },
 1640:     .endianness = DEVICE_BIG_ENDIAN,
 1641: };
 1642: 
 1643: qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
 1644:                      int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
 1645: {
 1646:     openpic_t    *mpp;
 1647:     int           i;
 1648:     struct {
 1649:         const char             *name;
 1650:         MemoryRegionOps const  *ops;
 1651:         target_phys_addr_t      start_addr;
 1652:         ram_addr_t              size;
 1653:     } const list[] = {
 1654:         {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
 1655:         {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
 1656:         {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
 1657:         {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
 1658:         {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
 1659:         {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
 1660:         {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
 1661:     };
 1662: 
 1663:     mpp = g_malloc0(sizeof(openpic_t));
 1664: 
 1665:     memory_region_init(&mpp->mem, "mpic", 0x40000);
 1666:     memory_region_add_subregion(address_space, base, &mpp->mem);
 1667: 
 1668:     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
 1669: 
 1670:         memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
 1671:                               list[i].name, list[i].size);
 1672: 
 1673:         memory_region_add_subregion(&mpp->mem, list[i].start_addr,
 1674:                                     &mpp->sub_io_mem[i]);
 1675:     }
 1676: 
 1677:     mpp->nb_cpus = nb_cpus;
 1678:     mpp->max_irq = MPIC_MAX_IRQ;
 1679:     mpp->irq_ipi0 = MPIC_IPI_IRQ;
 1680:     mpp->irq_tim0 = MPIC_TMR_IRQ;
 1681: 
 1682:     for (i = 0; i < nb_cpus; i++)
 1683:         mpp->dst[i].irqs = irqs[i];
 1684:     mpp->irq_out = irq_out;
 1685: 
 1686:     mpp->irq_raise = mpic_irq_raise;
 1687:     mpp->reset = mpic_reset;
 1688: 
 1689:     register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
 1690:     qemu_register_reset(mpic_reset, mpp);
 1691: 
 1692:     return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
 1693: }

unix.superglobalmegacorp.com