Revision 611493d9
b/hw/openpic.c | ||
---|---|---|
34 | 34 |
*/ |
35 | 35 |
#include "vl.h" |
36 | 36 |
|
37 |
#define DEBUG_OPENPIC |
|
37 |
//#define DEBUG_OPENPIC
|
|
38 | 38 |
|
39 | 39 |
#ifdef DEBUG_OPENPIC |
40 | 40 |
#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) |
... | ... | |
65 | 65 |
|
66 | 66 |
#define MAX_CPU 2 |
67 | 67 |
#define MAX_IRQ 64 |
68 |
#define EXT_IRQ 16
|
|
68 |
#define EXT_IRQ 48
|
|
69 | 69 |
#define MAX_DBL 0 |
70 | 70 |
#define MAX_MBX 0 |
71 | 71 |
#define MAX_TMR 4 |
... | ... | |
139 | 139 |
uint32_t ide; /* IRQ destination register */ |
140 | 140 |
int type; |
141 | 141 |
int last_cpu; |
142 |
int waited_acks;
|
|
142 |
int pending; /* TRUE if IRQ is pending */
|
|
143 | 143 |
} IRQ_src_t; |
144 | 144 |
|
145 | 145 |
enum IPVP_bits { |
... | ... | |
150 | 150 |
IPVP_SENSE = 22, |
151 | 151 |
}; |
152 | 152 |
#define IPVP_PRIORITY_MASK (0x1F << 16) |
153 |
#define IPVP_PRIORITY(_ipvpr_) (((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)
|
|
153 |
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
|
|
154 | 154 |
#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) |
155 | 155 |
#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) |
156 | 156 |
|
... | ... | |
162 | 162 |
CPUState *env; /* Needed if we did SMP */ |
163 | 163 |
} IRQ_dst_t; |
164 | 164 |
|
165 |
typedef struct openpic_t {
|
|
165 |
struct openpic_t { |
|
166 | 166 |
PCIDevice pci_dev; |
167 | 167 |
/* Global registers */ |
168 | 168 |
uint32_t frep; /* Feature reporting register */ |
... | ... | |
194 | 194 |
uint32_t mbr; /* Mailbox register */ |
195 | 195 |
} mailboxes[MAX_MAILBOXES]; |
196 | 196 |
#endif |
197 |
} openpic_t;
|
|
197 |
}; |
|
198 | 198 |
|
199 | 199 |
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) |
200 | 200 |
{ |
... | ... | |
220 | 220 |
priority = -1; |
221 | 221 |
for (i = 0; i < MAX_IRQ; i++) { |
222 | 222 |
if (IRQ_testbit(q, i)) { |
223 |
DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", |
|
224 |
i, IPVP_PRIORITY(opp->src[i].ipvp), priority); |
|
223 | 225 |
if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { |
224 | 226 |
next = i; |
225 | 227 |
priority = IPVP_PRIORITY(opp->src[i].ipvp); |
... | ... | |
233 | 235 |
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) |
234 | 236 |
{ |
235 | 237 |
if (q->next == -1) { |
236 |
if (q->queue == 0) { |
|
237 |
/* No more IRQ */ |
|
238 |
return -1; |
|
239 |
} |
|
238 |
/* XXX: optimize */ |
|
240 | 239 |
IRQ_check(opp, q); |
241 | 240 |
} |
242 | 241 |
|
... | ... | |
269 | 268 |
} |
270 | 269 |
} |
271 | 270 |
|
272 |
void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level) |
|
271 |
/* update pic state because registers for n_IRQ have changed value */ |
|
272 |
static void openpic_update_irq(openpic_t *opp, int n_IRQ) |
|
273 | 273 |
{ |
274 | 274 |
IRQ_src_t *src; |
275 | 275 |
int i; |
276 | 276 |
|
277 | 277 |
src = &opp->src[n_IRQ]; |
278 |
if (!test_bit(&src->ipvp, IPVP_MASK)) { |
|
278 |
|
|
279 |
if (!src->pending) { |
|
280 |
/* no irq pending */ |
|
281 |
return; |
|
282 |
} |
|
283 |
if (test_bit(&src->ipvp, IPVP_MASK)) { |
|
279 | 284 |
/* Interrupt source is disabled */ |
280 | 285 |
return; |
281 | 286 |
} |
... | ... | |
283 | 288 |
/* Priority set to zero */ |
284 | 289 |
return; |
285 | 290 |
} |
291 |
if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { |
|
292 |
/* IRQ already active */ |
|
293 |
return; |
|
294 |
} |
|
286 | 295 |
if (src->ide == 0x00000000) { |
287 | 296 |
/* No target */ |
288 | 297 |
return; |
289 | 298 |
} |
290 |
if (level == 0) { |
|
291 |
if (test_bit(&src->ipvp, IPVP_ACTIVITY) && |
|
292 |
test_bit(&src->ipvp, IPVP_SENSE)) { |
|
293 |
/* Inactivate a active level-sensitive IRQ */ |
|
294 |
reset_bit(&src->ipvp, IPVP_ACTIVITY); |
|
295 |
} |
|
299 |
|
|
300 |
if (!test_bit(&src->ipvp, IPVP_MODE) || |
|
301 |
src->ide == (1 << src->last_cpu)) { |
|
302 |
/* Directed delivery mode */ |
|
303 |
for (i = 0; i < opp->nb_cpus; i++) { |
|
304 |
if (test_bit(&src->ide, i)) |
|
305 |
IRQ_local_pipe(opp, i, n_IRQ); |
|
306 |
} |
|
296 | 307 |
} else { |
297 |
if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { |
|
298 |
/* Interrupt already pending */ |
|
299 |
return; |
|
300 |
} |
|
301 |
if (!test_bit(&src->ipvp, IPVP_MODE) || |
|
302 |
src->ide == (1 << src->last_cpu)) { |
|
303 |
/* Directed delivery mode */ |
|
304 |
for (i = 0; i < opp->nb_cpus; i++) { |
|
305 |
if (test_bit(&src->ide, i)) |
|
306 |
IRQ_local_pipe(opp, i, n_IRQ); |
|
307 |
} |
|
308 |
} else { |
|
309 |
/* Distributed delivery mode */ |
|
310 |
for (i = src->last_cpu; i < src->last_cpu; i++) { |
|
311 |
if (i == MAX_IRQ) |
|
312 |
i = 0; |
|
313 |
if (test_bit(&src->ide, i)) { |
|
314 |
IRQ_local_pipe(opp, i, n_IRQ); |
|
315 |
src->last_cpu = i; |
|
316 |
break; |
|
317 |
} |
|
318 |
} |
|
319 |
} |
|
308 |
/* Distributed delivery mode */ |
|
309 |
/* XXX: incorrect code */ |
|
310 |
for (i = src->last_cpu; i < src->last_cpu; i++) { |
|
311 |
if (i == MAX_IRQ) |
|
312 |
i = 0; |
|
313 |
if (test_bit(&src->ide, i)) { |
|
314 |
IRQ_local_pipe(opp, i, n_IRQ); |
|
315 |
src->last_cpu = i; |
|
316 |
break; |
|
317 |
} |
|
318 |
} |
|
319 |
} |
|
320 |
} |
|
321 |
|
|
322 |
void openpic_set_irq(openpic_t *opp, int n_IRQ, int level) |
|
323 |
{ |
|
324 |
IRQ_src_t *src; |
|
325 |
|
|
326 |
src = &opp->src[n_IRQ]; |
|
327 |
DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", |
|
328 |
n_IRQ, level, src->ipvp); |
|
329 |
if (test_bit(&src->ipvp, IPVP_SENSE)) { |
|
330 |
/* level-sensitive irq */ |
|
331 |
src->pending = level; |
|
332 |
if (!level) |
|
333 |
reset_bit(&src->ipvp, IPVP_ACTIVITY); |
|
334 |
} else { |
|
335 |
/* edge-sensitive irq */ |
|
336 |
if (level) |
|
337 |
src->pending = 1; |
|
320 | 338 |
} |
339 |
openpic_update_irq(opp, n_IRQ); |
|
321 | 340 |
} |
322 | 341 |
|
323 | 342 |
static void openpic_reset (openpic_t *opp) |
... | ... | |
389 | 408 |
|
390 | 409 |
switch (reg) { |
391 | 410 |
case IRQ_IPVP: |
392 |
tmp = opp->src[n_IRQ].ipvp & 0x40000000; |
|
393 |
if (tmp == 0) { |
|
394 |
tmp |= val & 0x80000000; |
|
395 |
if ((opp->src[n_IRQ].type & IRQ_EXTERNAL) != 0) |
|
396 |
tmp |= val & 0x40C00000; |
|
397 |
else if ((opp->src[n_IRQ].type & IRQ_TIMER) != 0) |
|
398 |
tmp |= val & 0x00F00000; |
|
399 |
} else { |
|
400 |
tmp |= val & 0x80000000; |
|
401 |
} |
|
402 |
opp->src[n_IRQ].ipvp = tmp | (val & 0x000F00FF); |
|
403 |
DPRINTF("Set IPVP %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ipvp); |
|
411 |
/* NOTE: not fully accurate for special IRQs, but simple and |
|
412 |
sufficient */ |
|
413 |
/* ACTIVITY bit is read-only */ |
|
414 |
opp->src[n_IRQ].ipvp = |
|
415 |
(opp->src[n_IRQ].ipvp & 0x40000000) | |
|
416 |
(val & 0x800F00FF); |
|
417 |
openpic_update_irq(opp, n_IRQ); |
|
418 |
DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", |
|
419 |
n_IRQ, val, opp->src[n_IRQ].ipvp); |
|
404 | 420 |
break; |
405 | 421 |
case IRQ_IDE: |
406 | 422 |
tmp = val & 0xC0000000; |
... | ... | |
736 | 752 |
case 0x70: |
737 | 753 |
idx = (addr - 0x40) >> 4; |
738 | 754 |
write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); |
739 |
openpic_set_IRQ(opp, IRQ_IPI0 + idx, 1);
|
|
740 |
openpic_set_IRQ(opp, IRQ_IPI0 + idx, 0);
|
|
755 |
openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
|
|
756 |
openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
|
|
741 | 757 |
break; |
742 | 758 |
#endif |
743 | 759 |
case 0x80: /* PCTP */ |
... | ... | |
818 | 834 |
} |
819 | 835 |
IRQ_resetbit(&dst->raised, n_IRQ); |
820 | 836 |
dst->raised.next = -1; |
821 |
if (!test_bit(&src->ipvp, IPVP_SENSE)) |
|
837 |
if (!test_bit(&src->ipvp, IPVP_SENSE)) { |
|
838 |
/* edge-sensitive IRQ */ |
|
822 | 839 |
reset_bit(&src->ipvp, IPVP_ACTIVITY); |
840 |
src->pending = 0; |
|
841 |
} |
|
823 | 842 |
} |
824 | 843 |
break; |
825 | 844 |
case 0xB0: /* PEOI */ |
... | ... | |
862 | 881 |
openpic_t *opp = opaque; |
863 | 882 |
|
864 | 883 |
addr &= 0x3FFFF; |
865 |
DPRINTF("%s: offset %08lx val: %08x\n", __func__, addr, val);
|
|
884 |
DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
|
|
866 | 885 |
if (addr < 0x1100) { |
867 | 886 |
/* Global registers */ |
868 | 887 |
openpic_gbl_write(opp, addr, val); |
... | ... | |
884 | 903 |
uint32_t retval; |
885 | 904 |
|
886 | 905 |
addr &= 0x3FFFF; |
887 |
DPRINTF("%s: offset %08lx\n", __func__, addr);
|
|
906 |
DPRINTF("%s: offset %08x\n", __func__, (int)addr);
|
|
888 | 907 |
if (addr < 0x1100) { |
889 | 908 |
/* Global registers */ |
890 | 909 |
retval = openpic_gbl_read(opp, addr); |
Also available in: Unified diff