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