Diff for /qemu/hw/openpic.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2018/04/24 16:39:08 version 1.1.1.3, 2018/04/24 16:48:21
Line 1 Line 1
 /*  /*
  * OpenPIC emulation   * OpenPIC emulation
  *    *
  * Copyright (c) 2004 Jocelyn Mayer   * Copyright (c) 2004 Jocelyn Mayer
  *    *
  * Permission is hereby granted, free of charge, to any person obtaining a copy   * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal   * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
Line 30 Line 30
  * - Motorola Harrier programmer manuel   * - Motorola Harrier programmer manuel
  *   *
  * Serial interrupts, as implemented in Raven chipset are not supported yet.   * Serial interrupts, as implemented in Raven chipset are not supported yet.
  *    *
  */   */
 #include "vl.h"  #include "hw.h"
   #include "ppc_mac.h"
   #include "pci.h"
   
 //#define DEBUG_OPENPIC  //#define DEBUG_OPENPIC
   
Line 159  typedef struct IRQ_dst_t { Line 161  typedef struct IRQ_dst_t {
     uint32_t pcsr; /* CPU sensitivity register */      uint32_t pcsr; /* CPU sensitivity register */
     IRQ_queue_t raised;      IRQ_queue_t raised;
     IRQ_queue_t servicing;      IRQ_queue_t servicing;
     CPUState *env;      qemu_irq *irqs;
 } IRQ_dst_t;  } IRQ_dst_t;
   
 struct openpic_t {  typedef struct openpic_t {
     PCIDevice pci_dev;      PCIDevice pci_dev;
     int mem_index;      int mem_index;
     /* Global registers */      /* Global registers */
Line 170  struct openpic_t { Line 172  struct openpic_t {
     uint32_t glbc; /* Global configuration register  */      uint32_t glbc; /* Global configuration register  */
     uint32_t micr; /* MPIC interrupt configuration register */      uint32_t micr; /* MPIC interrupt configuration register */
     uint32_t veni; /* Vendor identification register */      uint32_t veni; /* Vendor identification register */
       uint32_t pint; /* Processor initialization register */
     uint32_t spve; /* Spurious vector register */      uint32_t spve; /* Spurious vector register */
     uint32_t tifr; /* Timer frequency reporting register */      uint32_t tifr; /* Timer frequency reporting register */
     /* Source registers */      /* Source registers */
Line 195  struct openpic_t { Line 198  struct openpic_t {
         uint32_t mbr;    /* Mailbox register */          uint32_t mbr;    /* Mailbox register */
     } mailboxes[MAX_MAILBOXES];      } mailboxes[MAX_MAILBOXES];
 #endif  #endif
 };      /* IRQ out is used when in bypass mode (not implemented) */
       qemu_irq irq_out;
   } openpic_t;
   
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)  static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 {  {
Line 221  static void IRQ_check (openpic_t *opp, I Line 226  static void IRQ_check (openpic_t *opp, I
     priority = -1;      priority = -1;
     for (i = 0; i < MAX_IRQ; i++) {      for (i = 0; i < MAX_IRQ; i++) {
         if (IRQ_testbit(q, i)) {          if (IRQ_testbit(q, i)) {
             DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",               DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
                     i, IPVP_PRIORITY(opp->src[i].ipvp), priority);                      i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
             if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {              if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
                 next = i;                  next = i;
Line 254  static void IRQ_local_pipe (openpic_t *o Line 259  static void IRQ_local_pipe (openpic_t *o
     priority = IPVP_PRIORITY(src->ipvp);      priority = IPVP_PRIORITY(src->ipvp);
     if (priority <= dst->pctp) {      if (priority <= dst->pctp) {
         /* Too low priority */          /* Too low priority */
           DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
                   __func__, n_IRQ, n_CPU);
         return;          return;
     }      }
     if (IRQ_testbit(&dst->raised, n_IRQ)) {      if (IRQ_testbit(&dst->raised, n_IRQ)) {
         /* Interrupt miss */          /* Interrupt miss */
           DPRINTF("%s: IRQ %d was missed on CPU %d\n",
                   __func__, n_IRQ, n_CPU);
         return;          return;
     }      }
     set_bit(&src->ipvp, IPVP_ACTIVITY);      set_bit(&src->ipvp, IPVP_ACTIVITY);
     IRQ_setbit(&dst->raised, n_IRQ);      IRQ_setbit(&dst->raised, n_IRQ);
     if (priority > dst->raised.priority) {      if (priority < dst->raised.priority) {
         IRQ_get_next(opp, &dst->raised);          /* An higher priority IRQ is already raised */
         DPRINTF("Raise CPU IRQ\n");          DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
         cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);                  __func__, n_IRQ, dst->raised.next, n_CPU);
           return;
       }
       IRQ_get_next(opp, &dst->raised);
       if (IRQ_get_next(opp, &dst->servicing) != -1 &&
           priority < dst->servicing.priority) {
           DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
                   __func__, n_IRQ, dst->servicing.next, n_CPU);
           /* Already servicing a higher priority IRQ */
           return;
     }      }
       DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
       qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
 }  }
   
 /* update pic state because registers for n_IRQ have changed value */  /* update pic state because registers for n_IRQ have changed value */
Line 279  static void openpic_update_irq(openpic_t Line 299  static void openpic_update_irq(openpic_t
   
     if (!src->pending) {      if (!src->pending) {
         /* no irq pending */          /* no irq pending */
           DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
         return;          return;
     }      }
     if (test_bit(&src->ipvp, IPVP_MASK)) {      if (test_bit(&src->ipvp, IPVP_MASK)) {
         /* Interrupt source is disabled */          /* Interrupt source is disabled */
           DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
         return;          return;
     }      }
     if (IPVP_PRIORITY(src->ipvp) == 0) {      if (IPVP_PRIORITY(src->ipvp) == 0) {
         /* Priority set to zero */          /* Priority set to zero */
           DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
         return;          return;
     }      }
     if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {      if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
         /* IRQ already active */          /* IRQ already active */
           DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
         return;          return;
     }      }
     if (src->ide == 0x00000000) {      if (src->ide == 0x00000000) {
         /* No target */          /* No target */
           DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
         return;          return;
     }      }
   
     if (!test_bit(&src->ipvp, IPVP_MODE) ||      if (src->ide == (1 << src->last_cpu)) {
         src->ide == (1 << src->last_cpu)) {          /* Only one CPU is allowed to receive this IRQ */
           IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
       } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
         /* Directed delivery mode */          /* Directed delivery mode */
         for (i = 0; i < opp->nb_cpus; i++) {          for (i = 0; i < opp->nb_cpus; i++) {
             if (test_bit(&src->ide, i))              if (test_bit(&src->ide, i))
Line 307  static void openpic_update_irq(openpic_t Line 334  static void openpic_update_irq(openpic_t
         }          }
     } else {      } else {
         /* Distributed delivery mode */          /* Distributed delivery mode */
         /* XXX: incorrect code */          for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
         for (i = src->last_cpu; i < src->last_cpu; i++) {              if (i == opp->nb_cpus)
             if (i == MAX_IRQ)  
                 i = 0;                  i = 0;
             if (test_bit(&src->ide, i)) {              if (test_bit(&src->ide, i)) {
                 IRQ_local_pipe(opp, i, n_IRQ);                  IRQ_local_pipe(opp, i, n_IRQ);
Line 320  static void openpic_update_irq(openpic_t Line 346  static void openpic_update_irq(openpic_t
     }      }
 }  }
   
 void openpic_set_irq(void *opaque, int n_IRQ, int level)  static void openpic_set_irq(void *opaque, int n_IRQ, int level)
 {  {
     openpic_t *opp = opaque;      openpic_t *opp = opaque;
     IRQ_src_t *src;      IRQ_src_t *src;
   
     src = &opp->src[n_IRQ];      src = &opp->src[n_IRQ];
     DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",       DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
             n_IRQ, level, src->ipvp);              n_IRQ, level, src->ipvp);
     if (test_bit(&src->ipvp, IPVP_SENSE)) {      if (test_bit(&src->ipvp, IPVP_SENSE)) {
         /* level-sensitive irq */          /* level-sensitive irq */
Line 349  static void openpic_reset (openpic_t *op Line 375  static void openpic_reset (openpic_t *op
     /* Initialise controller registers */      /* Initialise controller registers */
     opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;      opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
     opp->veni = VENI;      opp->veni = VENI;
       opp->pint = 0x00000000;
     opp->spve = 0x000000FF;      opp->spve = 0x000000FF;
     opp->tifr = 0x003F7A00;      opp->tifr = 0x003F7A00;
     /* ? */      /* ? */
Line 359  static void openpic_reset (openpic_t *op Line 386  static void openpic_reset (openpic_t *op
         opp->src[i].ide  = 0x00000000;          opp->src[i].ide  = 0x00000000;
     }      }
     /* Initialise IRQ destinations */      /* Initialise IRQ destinations */
     for (i = 0; i < opp->nb_cpus; i++) {      for (i = 0; i < MAX_CPU; i++) {
         opp->dst[i].pctp      = 0x0000000F;          opp->dst[i].pctp      = 0x0000000F;
         opp->dst[i].pcsr      = 0x00000000;          opp->dst[i].pcsr      = 0x00000000;
         memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));          memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
Line 413  static inline void write_IRQreg (openpic Line 440  static inline void write_IRQreg (openpic
         /* NOTE: not fully accurate for special IRQs, but simple and          /* NOTE: not fully accurate for special IRQs, but simple and
            sufficient */             sufficient */
         /* ACTIVITY bit is read-only */          /* ACTIVITY bit is read-only */
         opp->src[n_IRQ].ipvp =           opp->src[n_IRQ].ipvp =
             (opp->src[n_IRQ].ipvp & 0x40000000) |              (opp->src[n_IRQ].ipvp & 0x40000000) |
             (val & 0x800F00FF);              (val & 0x800F00FF);
         openpic_update_irq(opp, n_IRQ);          openpic_update_irq(opp, n_IRQ);
         DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",           DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
                 n_IRQ, val, opp->src[n_IRQ].ipvp);                  n_IRQ, val, opp->src[n_IRQ].ipvp);
         break;          break;
     case IRQ_IDE:      case IRQ_IDE:
Line 450  static uint32_t read_doorbell_register ( Line 477  static uint32_t read_doorbell_register (
   
     return retval;      return retval;
 }  }
        
 static void write_doorbell_register (penpic_t *opp, int n_dbl,  static void write_doorbell_register (penpic_t *opp, int n_dbl,
                                      uint32_t offset, uint32_t value)                                       uint32_t offset, uint32_t value)
 {  {
Line 510  static void write_mailbox_register (open Line 537  static void write_mailbox_register (open
 static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)  static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
 {  {
     openpic_t *opp = opaque;      openpic_t *opp = opaque;
       IRQ_dst_t *dst;
       int idx;
   
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);      DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)      if (addr & 0xF)
Line 529  static void openpic_gbl_write (void *opa Line 558  static void openpic_gbl_write (void *opa
     case 0x80: /* VENI */      case 0x80: /* VENI */
         break;          break;
     case 0x90: /* PINT */      case 0x90: /* PINT */
         /* XXX: Should be able to reset any CPU */          for (idx = 0; idx < opp->nb_cpus; idx++) {
         if (val & 1) {              if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
             DPRINTF("Reset CPU IRQ\n");                  DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
             //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);                  dst = &opp->dst[idx];
                   qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
               } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
                   DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
                   dst = &opp->dst[idx];
                   qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
               }
         }          }
           opp->pint = val;
         break;          break;
 #if MAX_IPI > 0  #if MAX_IPI > 0
     case 0xA0: /* IPI_IPVP */      case 0xA0: /* IPI_IPVP */
Line 734  static void openpic_cpu_write (void *opa Line 770  static void openpic_cpu_write (void *opa
     openpic_t *opp = opaque;      openpic_t *opp = opaque;
     IRQ_src_t *src;      IRQ_src_t *src;
     IRQ_dst_t *dst;      IRQ_dst_t *dst;
     int idx, n_IRQ;      int idx, s_IRQ, n_IRQ;
   
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);      DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)      if (addr & 0xF)
Line 769  static void openpic_cpu_write (void *opa Line 805  static void openpic_cpu_write (void *opa
         break;          break;
     case 0xB0: /* PEOI */      case 0xB0: /* PEOI */
         DPRINTF("PEOI\n");          DPRINTF("PEOI\n");
         n_IRQ = IRQ_get_next(opp, &dst->servicing);          s_IRQ = IRQ_get_next(opp, &dst->servicing);
         IRQ_resetbit(&dst->servicing, n_IRQ);          IRQ_resetbit(&dst->servicing, s_IRQ);
         dst->servicing.next = -1;          dst->servicing.next = -1;
         src = &opp->src[n_IRQ];  
         /* Set up next servicing IRQ */          /* Set up next servicing IRQ */
         IRQ_get_next(opp, &dst->servicing);          s_IRQ = IRQ_get_next(opp, &dst->servicing);
         /* Check queued interrupts. */          /* Check queued interrupts. */
         n_IRQ = IRQ_get_next(opp, &dst->raised);          n_IRQ = IRQ_get_next(opp, &dst->raised);
         if (n_IRQ != -1) {          src = &opp->src[n_IRQ];
             src = &opp->src[n_IRQ];          if (n_IRQ != -1 &&
             if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {              (s_IRQ == -1 ||
                 DPRINTF("Raise CPU IRQ\n");               IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
                 cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);              DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
             }                      idx, n_IRQ);
         }              qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
           }
         break;          break;
     default:      default:
         break;          break;
Line 797  static uint32_t openpic_cpu_read (void * Line 833  static uint32_t openpic_cpu_read (void *
     IRQ_dst_t *dst;      IRQ_dst_t *dst;
     uint32_t retval;      uint32_t retval;
     int idx, n_IRQ;      int idx, n_IRQ;
       
     DPRINTF("%s: addr %08x\n", __func__, addr);      DPRINTF("%s: addr %08x\n", __func__, addr);
     retval = 0xFFFFFFFF;      retval = 0xFFFFFFFF;
     if (addr & 0xF)      if (addr & 0xF)
Line 814  static uint32_t openpic_cpu_read (void * Line 850  static uint32_t openpic_cpu_read (void *
         retval = idx;          retval = idx;
         break;          break;
     case 0xA0: /* PIAC */      case 0xA0: /* PIAC */
           DPRINTF("Lower OpenPIC INT output\n");
           qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
         n_IRQ = IRQ_get_next(opp, &dst->raised);          n_IRQ = IRQ_get_next(opp, &dst->raised);
         DPRINTF("PIAC: irq=%d\n", n_IRQ);          DPRINTF("PIAC: irq=%d\n", n_IRQ);
         if (n_IRQ == -1) {          if (n_IRQ == -1) {
             /* No more interrupt pending */              /* No more interrupt pending */
             retval = opp->spve;              retval = IPVP_VECTOR(opp->spve);
         } else {          } else {
             src = &opp->src[n_IRQ];              src = &opp->src[n_IRQ];
             if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||              if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
Line 935  static CPUReadMemoryFunc *openpic_read[] Line 973  static CPUReadMemoryFunc *openpic_read[]
     &openpic_readl,      &openpic_readl,
 };  };
   
 static void openpic_map(PCIDevice *pci_dev, int region_num,   static void openpic_map(PCIDevice *pci_dev, int region_num,
                         uint32_t addr, uint32_t size, int type)                          uint32_t addr, uint32_t size, int type)
 {  {
     openpic_t *opp;      openpic_t *opp;
Line 963  static void openpic_map(PCIDevice *pci_d Line 1001  static void openpic_map(PCIDevice *pci_d
 #endif  #endif
 }  }
   
 openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,  qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
                          CPUPPCState **envp)                          qemu_irq **irqs, qemu_irq irq_out)
 {  {
     openpic_t *opp;      openpic_t *opp;
     uint8_t *pci_conf;      uint8_t *pci_conf;
     int i, m;      int i, m;
       
     /* XXX: for now, only one CPU is supported */      /* XXX: for now, only one CPU is supported */
     if (nb_cpus != 1)      if (nb_cpus != 1)
         return NULL;          return NULL;
Line 987  openpic_t *openpic_init (PCIBus *bus, in Line 1025  openpic_t *openpic_init (PCIBus *bus, in
         pci_conf[0x0b] = 0x08;          pci_conf[0x0b] = 0x08;
         pci_conf[0x0e] = 0x00; // header_type          pci_conf[0x0e] = 0x00; // header_type
         pci_conf[0x3d] = 0x00; // no interrupt pin          pci_conf[0x3d] = 0x00; // no interrupt pin
           
         /* Register I/O spaces */          /* Register I/O spaces */
         pci_register_io_region((PCIDevice *)opp, 0, 0x40000,          pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
                                PCI_ADDRESS_SPACE_MEM, &openpic_map);                                 PCI_ADDRESS_SPACE_MEM, &openpic_map);
     } else {      } else {
         opp = qemu_mallocz(sizeof(openpic_t));          opp = qemu_mallocz(sizeof(openpic_t));
     }      }
   
     opp->mem_index = cpu_register_io_memory(0, openpic_read,      opp->mem_index = cpu_register_io_memory(0, openpic_read,
                                             openpic_write, opp);                                              openpic_write, opp);
       
     //    isu_base &= 0xFFFC0000;      //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;      opp->nb_cpus = nb_cpus;
     /* Set IRQ types */      /* Set IRQ types */
Line 1019  openpic_t *openpic_init (PCIBus *bus, in Line 1056  openpic_t *openpic_init (PCIBus *bus, in
         opp->src[i].type = IRQ_INTERNAL;          opp->src[i].type = IRQ_INTERNAL;
     }      }
     for (i = 0; i < nb_cpus; i++)      for (i = 0; i < nb_cpus; i++)
         opp->dst[i].env = envp[i];          opp->dst[i].irqs = irqs[i];
       opp->irq_out = irq_out;
     openpic_reset(opp);      openpic_reset(opp);
     if (pmem_index)      if (pmem_index)
         *pmem_index = opp->mem_index;          *pmem_index = opp->mem_index;
     return opp;  
       return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
 }  }

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


unix.superglobalmegacorp.com