Revision e9df014c hw/openpic.c

b/hw/openpic.c
159 159
    uint32_t pcsr; /* CPU sensitivity register */
160 160
    IRQ_queue_t raised;
161 161
    IRQ_queue_t servicing;
162
    CPUState *env;
162
    qemu_irq *irqs;
163 163
} IRQ_dst_t;
164 164

  
165 165
typedef struct openpic_t {
166 166
    PCIDevice pci_dev;
167
    SetIRQFunc *set_irq;
168 167
    int mem_index;
169 168
    /* Global registers */
170 169
    uint32_t frep; /* Feature reporting register */
171 170
    uint32_t glbc; /* Global configuration register  */
172 171
    uint32_t micr; /* MPIC interrupt configuration register */
173 172
    uint32_t veni; /* Vendor identification register */
173
    uint32_t pint; /* Processor initialization register */
174 174
    uint32_t spve; /* Spurious vector register */
175 175
    uint32_t tifr; /* Timer frequency reporting register */
176 176
    /* Source registers */
......
196 196
	uint32_t mbr;    /* Mailbox register */
197 197
    } mailboxes[MAX_MAILBOXES];
198 198
#endif
199
    /* IRQ out is used when in bypass mode (not implemented) */
200
    qemu_irq irq_out;
199 201
} openpic_t;
200 202

  
201 203
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
......
255 257
    priority = IPVP_PRIORITY(src->ipvp);
256 258
    if (priority <= dst->pctp) {
257 259
	/* Too low priority */
260
        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
261
                __func__, n_IRQ, n_CPU);
258 262
	return;
259 263
    }
260 264
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
261 265
	/* Interrupt miss */
266
        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
267
                __func__, n_IRQ, n_CPU);
262 268
	return;
263 269
    }
264 270
    set_bit(&src->ipvp, IPVP_ACTIVITY);
265 271
    IRQ_setbit(&dst->raised, n_IRQ);
266
    if (priority > dst->raised.priority) {
267
        IRQ_get_next(opp, &dst->raised);
268
        DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env);
269
        opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
272
    if (priority < dst->raised.priority) {
273
        /* An higher priority IRQ is already raised */
274
        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
275
                __func__, n_IRQ, dst->raised.next, n_CPU);
276
        return;
277
    }
278
    IRQ_get_next(opp, &dst->raised);
279
    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
280
        priority < dst->servicing.priority) {
281
        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
282
                __func__, n_IRQ, dst->servicing.next, n_CPU);
283
        /* Already servicing a higher priority IRQ */
284
        return;
270 285
    }
286
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
287
    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
271 288
}
272 289

  
273 290
/* update pic state because registers for n_IRQ have changed value */
......
280 297

  
281 298
    if (!src->pending) {
282 299
        /* no irq pending */
300
        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
283 301
        return;
284 302
    }
285 303
    if (test_bit(&src->ipvp, IPVP_MASK)) {
286 304
	/* Interrupt source is disabled */
305
        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
287 306
	return;
288 307
    }
289 308
    if (IPVP_PRIORITY(src->ipvp) == 0) {
290 309
	/* Priority set to zero */
310
        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
291 311
	return;
292 312
    }
293 313
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
294 314
        /* IRQ already active */
315
        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
295 316
        return;
296 317
    }
297 318
    if (src->ide == 0x00000000) {
298 319
	/* No target */
320
        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
299 321
	return;
300 322
    }
301 323

  
302
    if (!test_bit(&src->ipvp, IPVP_MODE) ||
303
        src->ide == (1 << src->last_cpu)) {
324
    if (src->ide == (1 << src->last_cpu)) {
325
        /* Only one CPU is allowed to receive this IRQ */
326
        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
327
    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
304 328
        /* Directed delivery mode */
305 329
        for (i = 0; i < opp->nb_cpus; i++) {
306 330
            if (test_bit(&src->ide, i))
......
308 332
        }
309 333
    } else {
310 334
        /* Distributed delivery mode */
311
        /* XXX: incorrect code */
312
        for (i = src->last_cpu; i < src->last_cpu; i++) {
313
            if (i == MAX_IRQ)
335
        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
336
            if (i == opp->nb_cpus)
314 337
                i = 0;
315 338
            if (test_bit(&src->ide, i)) {
316 339
                IRQ_local_pipe(opp, i, n_IRQ);
......
350 373
    /* Initialise controller registers */
351 374
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
352 375
    opp->veni = VENI;
376
    opp->pint = 0x00000000;
353 377
    opp->spve = 0x000000FF;
354 378
    opp->tifr = 0x003F7A00;
355 379
    /* ? */
......
360 384
	opp->src[i].ide  = 0x00000000;
361 385
    }
362 386
    /* Initialise IRQ destinations */
363
    for (i = 0; i < opp->nb_cpus; i++) {
387
    for (i = 0; i < MAX_CPU; i++) {
364 388
	opp->dst[i].pctp      = 0x0000000F;
365 389
	opp->dst[i].pcsr      = 0x00000000;
366 390
	memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
......
511 535
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
512 536
{
513 537
    openpic_t *opp = opaque;
538
    IRQ_dst_t *dst;
539
    int idx;
514 540

  
515 541
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
516 542
    if (addr & 0xF)
......
530 556
    case 0x80: /* VENI */
531 557
	break;
532 558
    case 0x90: /* PINT */
533
        /* XXX: Should be able to reset any CPU */
534
        if (val & 1) {
535
            DPRINTF("Reset CPU IRQ\n");
536
            //                opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1);
559
        for (idx = 0; idx < opp->nb_cpus; idx++) {
560
            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
561
                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
562
                dst = &opp->dst[idx];
563
                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
564
            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
565
                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
566
                dst = &opp->dst[idx];
567
                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
568
            }
537 569
        }
570
        opp->pint = val;
538 571
	break;
539 572
#if MAX_IPI > 0
540 573
    case 0xA0: /* IPI_IPVP */
......
735 768
    openpic_t *opp = opaque;
736 769
    IRQ_src_t *src;
737 770
    IRQ_dst_t *dst;
738
    int idx, n_IRQ;
771
    int idx, s_IRQ, n_IRQ;
739 772

  
740 773
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
741 774
    if (addr & 0xF)
......
770 803
	break;
771 804
    case 0xB0: /* PEOI */
772 805
        DPRINTF("PEOI\n");
773
	n_IRQ = IRQ_get_next(opp, &dst->servicing);
774
	IRQ_resetbit(&dst->servicing, n_IRQ);
806
	s_IRQ = IRQ_get_next(opp, &dst->servicing);
807
	IRQ_resetbit(&dst->servicing, s_IRQ);
775 808
	dst->servicing.next = -1;
776
	src = &opp->src[n_IRQ];
777 809
	/* Set up next servicing IRQ */
778
	IRQ_get_next(opp, &dst->servicing);
779
	/* Check queued interrupts. */
780
	n_IRQ = IRQ_get_next(opp, &dst->raised);
781
	if (n_IRQ != -1) {
782
	    src = &opp->src[n_IRQ];
783
	    if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
784
                DPRINTF("Raise CPU IRQ\n");
785
                opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
786
            }
787
	}
810
	s_IRQ = IRQ_get_next(opp, &dst->servicing);
811
        /* Check queued interrupts. */
812
        n_IRQ = IRQ_get_next(opp, &dst->raised);
813
        src = &opp->src[n_IRQ];
814
        if (n_IRQ != -1 &&
815
            (s_IRQ == -1 ||
816
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
817
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
818
                    idx, n_IRQ);
819
            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
820
        }
788 821
	break;
789 822
    default:
790 823
        break;
......
815 848
	retval = idx;
816 849
	break;
817 850
    case 0xA0: /* PIAC */
851
        DPRINTF("Lower OpenPIC INT output\n");
852
        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
818 853
	n_IRQ = IRQ_get_next(opp, &dst->raised);
819 854
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
820 855
	if (n_IRQ == -1) {
821 856
	    /* No more interrupt pending */
822
            retval = opp->spve;
857
            retval = IPVP_VECTOR(opp->spve);
823 858
	} else {
824 859
	    src = &opp->src[n_IRQ];
825 860
	    if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
......
964 999
#endif
965 1000
}
966 1001

  
967
qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
968
                         int *pmem_index, int nb_cpus, CPUState **envp)
1002
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1003
                        qemu_irq **irqs, qemu_irq irq_out)
969 1004
{
970 1005
    openpic_t *opp;
971 1006
    uint8_t *pci_conf;
......
995 1030
    } else {
996 1031
        opp = qemu_mallocz(sizeof(openpic_t));
997 1032
    }
998
    opp->set_irq = set_irq;
999 1033
    opp->mem_index = cpu_register_io_memory(0, openpic_read,
1000 1034
                                            openpic_write, opp);
1001 1035
    
......
1020 1054
        opp->src[i].type = IRQ_INTERNAL;
1021 1055
    }
1022 1056
    for (i = 0; i < nb_cpus; i++)
1023
        opp->dst[i].env = envp[i];
1057
        opp->dst[i].irqs = irqs[i];
1058
    opp->irq_out = irq_out;
1024 1059
    openpic_reset(opp);
1025 1060
    if (pmem_index)
1026 1061
        *pmem_index = opp->mem_index;
1062

  
1027 1063
    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
1028 1064
}

Also available in: Unified diff