qemu/hw/openpic.c
<<
>>
Prefs
   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
  76enum {
  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
 133enum 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
 150static inline void set_bit (uint32_t *field, int bit)
 151{
 152    field[bit >> 5] |= 1 << (bit & 0x1F);
 153}
 154
 155static inline void reset_bit (uint32_t *field, int bit)
 156{
 157    field[bit >> 5] &= ~(1 << (bit & 0x1F));
 158}
 159
 160static inline int test_bit (uint32_t *field, int bit)
 161{
 162    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
 163}
 164
 165static int get_current_cpu(void)
 166{
 167  return cpu_single_env->cpu_index;
 168}
 169
 170static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
 171                                          int idx);
 172static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
 173                                       uint32_t val, int idx);
 174
 175enum {
 176    IRQ_EXTERNAL = 0x01,
 177    IRQ_INTERNAL = 0x02,
 178    IRQ_TIMER    = 0x04,
 179    IRQ_SPECIAL  = 0x08,
 180};
 181
 182typedef struct IRQ_queue_t {
 183    uint32_t queue[BF_WIDTH(MAX_IRQ)];
 184    int next;
 185    int priority;
 186} IRQ_queue_t;
 187
 188typedef 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
 196enum 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
 208typedef 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
 217typedef 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
 264static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 265{
 266    set_bit(q->queue, n_IRQ);
 267}
 268
 269static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
 270{
 271    reset_bit(q->queue, n_IRQ);
 272}
 273
 274static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
 275{
 276    return test_bit(q->queue, n_IRQ);
 277}
 278
 279static 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
 300static 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
 310static 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 */
 352static 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
 408static 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
 429static 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
 479static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
 480{
 481    return opp->src[n_IRQ].ide;
 482}
 483
 484static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
 485{
 486    return opp->src[n_IRQ].ipvp;
 487}
 488
 489static 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
 499static 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
 512static 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
 532static 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
 550static 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
 570static 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
 588static 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
 652static 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
 708static 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
 739static 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
 772static 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
 791static 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
 815static 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
 875static 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
 880static 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
 956static 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
 961static 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
 967static 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
 974static 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
 996static 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
1020static 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
1031static 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
1042static const MemoryRegionOps openpic_ops = {
1043    .read = openpic_read,
1044    .write = openpic_write,
1045    .endianness = DEVICE_LITTLE_ENDIAN,
1046};
1047
1048static 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
1059static 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
1112static 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
1123static 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
1179static 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
1184qemu_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
1236static 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
1248static 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
1286static 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
1319static 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
1354static 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
1376static 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
1402static 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
1424static 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
1450static 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
1472static 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
1498static 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}
1519static 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
1545static 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
1559static 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
1573static 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
1587static 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
1601static 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
1615static 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
1629static 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
1643qemu_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}
1694