Commit 611493d96655e9d529d637421713de95939c030f

Authored by bellard
1 parent e1bb04f7

openpic fixes


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@954 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 77 additions and 58 deletions
hw/openpic.c
... ... @@ -34,7 +34,7 @@
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,7 +65,7 @@
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,7 +139,7 @@ typedef struct IRQ_src_t {
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,7 +150,7 @@ 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,7 +162,7 @@ typedef struct IRQ_dst_t {
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,7 +194,7 @@ typedef struct openpic_t {
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,6 +220,8 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
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,10 +235,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
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,13 +268,19 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
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,41 +288,55 @@ void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level)
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,18 +408,15 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
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,8 +752,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
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,8 +834,11 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
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,7 +881,7 @@ static void openpic_writel (void *opaque,
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,7 +903,7 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
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);
... ...