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,7 +34,7 @@
34 */ 34 */
35 #include "vl.h" 35 #include "vl.h"
36 36
37 -#define DEBUG_OPENPIC 37 +//#define DEBUG_OPENPIC
38 38
39 #ifdef DEBUG_OPENPIC 39 #ifdef DEBUG_OPENPIC
40 #define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) 40 #define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
@@ -65,7 +65,7 @@ @@ -65,7 +65,7 @@
65 65
66 #define MAX_CPU 2 66 #define MAX_CPU 2
67 #define MAX_IRQ 64 67 #define MAX_IRQ 64
68 -#define EXT_IRQ 16 68 +#define EXT_IRQ 48
69 #define MAX_DBL 0 69 #define MAX_DBL 0
70 #define MAX_MBX 0 70 #define MAX_MBX 0
71 #define MAX_TMR 4 71 #define MAX_TMR 4
@@ -139,7 +139,7 @@ typedef struct IRQ_src_t { @@ -139,7 +139,7 @@ typedef struct IRQ_src_t {
139 uint32_t ide; /* IRQ destination register */ 139 uint32_t ide; /* IRQ destination register */
140 int type; 140 int type;
141 int last_cpu; 141 int last_cpu;
142 - int waited_acks; 142 + int pending; /* TRUE if IRQ is pending */
143 } IRQ_src_t; 143 } IRQ_src_t;
144 144
145 enum IPVP_bits { 145 enum IPVP_bits {
@@ -150,7 +150,7 @@ enum IPVP_bits { @@ -150,7 +150,7 @@ enum IPVP_bits {
150 IPVP_SENSE = 22, 150 IPVP_SENSE = 22,
151 }; 151 };
152 #define IPVP_PRIORITY_MASK (0x1F << 16) 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 #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) 154 #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
155 #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) 155 #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
156 156
@@ -162,7 +162,7 @@ typedef struct IRQ_dst_t { @@ -162,7 +162,7 @@ typedef struct IRQ_dst_t {
162 CPUState *env; /* Needed if we did SMP */ 162 CPUState *env; /* Needed if we did SMP */
163 } IRQ_dst_t; 163 } IRQ_dst_t;
164 164
165 -typedef struct openpic_t { 165 +struct openpic_t {
166 PCIDevice pci_dev; 166 PCIDevice pci_dev;
167 /* Global registers */ 167 /* Global registers */
168 uint32_t frep; /* Feature reporting register */ 168 uint32_t frep; /* Feature reporting register */
@@ -194,7 +194,7 @@ typedef struct openpic_t { @@ -194,7 +194,7 @@ typedef struct openpic_t {
194 uint32_t mbr; /* Mailbox register */ 194 uint32_t mbr; /* Mailbox register */
195 } mailboxes[MAX_MAILBOXES]; 195 } mailboxes[MAX_MAILBOXES];
196 #endif 196 #endif
197 -} openpic_t; 197 +};
198 198
199 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) 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,6 +220,8 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
220 priority = -1; 220 priority = -1;
221 for (i = 0; i < MAX_IRQ; i++) { 221 for (i = 0; i < MAX_IRQ; i++) {
222 if (IRQ_testbit(q, i)) { 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 if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { 225 if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
224 next = i; 226 next = i;
225 priority = IPVP_PRIORITY(opp->src[i].ipvp); 227 priority = IPVP_PRIORITY(opp->src[i].ipvp);
@@ -233,10 +235,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) @@ -233,10 +235,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
233 static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) 235 static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
234 { 236 {
235 if (q->next == -1) { 237 if (q->next == -1) {
236 - if (q->queue == 0) {  
237 - /* No more IRQ */  
238 - return -1;  
239 - } 238 + /* XXX: optimize */
240 IRQ_check(opp, q); 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,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 IRQ_src_t *src; 274 IRQ_src_t *src;
275 int i; 275 int i;
276 276
277 src = &opp->src[n_IRQ]; 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 /* Interrupt source is disabled */ 284 /* Interrupt source is disabled */
280 return; 285 return;
281 } 286 }
@@ -283,41 +288,55 @@ void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level) @@ -283,41 +288,55 @@ void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level)
283 /* Priority set to zero */ 288 /* Priority set to zero */
284 return; 289 return;
285 } 290 }
  291 + if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
  292 + /* IRQ already active */
  293 + return;
  294 + }
286 if (src->ide == 0x00000000) { 295 if (src->ide == 0x00000000) {
287 /* No target */ 296 /* No target */
288 return; 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 } else { 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 static void openpic_reset (openpic_t *opp) 342 static void openpic_reset (openpic_t *opp)
@@ -389,18 +408,15 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ, @@ -389,18 +408,15 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
389 408
390 switch (reg) { 409 switch (reg) {
391 case IRQ_IPVP: 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 break; 420 break;
405 case IRQ_IDE: 421 case IRQ_IDE:
406 tmp = val & 0xC0000000; 422 tmp = val & 0xC0000000;
@@ -736,8 +752,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) @@ -736,8 +752,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
736 case 0x70: 752 case 0x70:
737 idx = (addr - 0x40) >> 4; 753 idx = (addr - 0x40) >> 4;
738 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); 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 break; 757 break;
742 #endif 758 #endif
743 case 0x80: /* PCTP */ 759 case 0x80: /* PCTP */
@@ -818,8 +834,11 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) @@ -818,8 +834,11 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
818 } 834 }
819 IRQ_resetbit(&dst->raised, n_IRQ); 835 IRQ_resetbit(&dst->raised, n_IRQ);
820 dst->raised.next = -1; 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 reset_bit(&src->ipvp, IPVP_ACTIVITY); 839 reset_bit(&src->ipvp, IPVP_ACTIVITY);
  840 + src->pending = 0;
  841 + }
823 } 842 }
824 break; 843 break;
825 case 0xB0: /* PEOI */ 844 case 0xB0: /* PEOI */
@@ -862,7 +881,7 @@ static void openpic_writel (void *opaque, @@ -862,7 +881,7 @@ static void openpic_writel (void *opaque,
862 openpic_t *opp = opaque; 881 openpic_t *opp = opaque;
863 882
864 addr &= 0x3FFFF; 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 if (addr < 0x1100) { 885 if (addr < 0x1100) {
867 /* Global registers */ 886 /* Global registers */
868 openpic_gbl_write(opp, addr, val); 887 openpic_gbl_write(opp, addr, val);
@@ -884,7 +903,7 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) @@ -884,7 +903,7 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
884 uint32_t retval; 903 uint32_t retval;
885 904
886 addr &= 0x3FFFF; 905 addr &= 0x3FFFF;
887 - DPRINTF("%s: offset %08lx\n", __func__, addr); 906 + DPRINTF("%s: offset %08x\n", __func__, (int)addr);
888 if (addr < 0x1100) { 907 if (addr < 0x1100) {
889 /* Global registers */ 908 /* Global registers */
890 retval = openpic_gbl_read(opp, addr); 909 retval = openpic_gbl_read(opp, addr);