static int openpic_acknowledge_io_interrupt(void *cookie) { openpic_info *info = (openpic_info*)cookie; int cpu = 0; // Note: We direct all I/O interrupts to CPU 0. We could nevertheless // check against the value of the "Who Am I Register". int irq = openpic_read_irq(info, cpu); if (irq == 255) return -1; // spurious interrupt // signal end of interrupt openpic_eoi(info, cpu); return irq; }
void pmac_do_IRQ(struct pt_regs *regs, int cpu, int isfake) { int irq; unsigned long bits = 0; #ifdef __SMP__ /* IPI's are a hack on the powersurge -- Cort */ if ( cpu != 0 ) { if (!isfake) { #ifdef CONFIG_XMON static int xmon_2nd; if (xmon_2nd) xmon(regs); #endif pmac_smp_message_recv(); goto out; } /* could be here due to a do_fake_interrupt call but we don't mess with the controller from the second cpu -- Cort */ goto out; } { unsigned int loops = MAXCOUNT; while (test_bit(0, &global_irq_lock)) { if (smp_processor_id() == global_irq_holder) { printk("uh oh, interrupt while we hold global irq lock!\n"); #ifdef CONFIG_XMON xmon(0); #endif break; } if (loops-- == 0) { printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); #ifdef CONFIG_XMON xmon(0); #endif } } } #endif /* __SMP__ */ /* Yeah, I know, this could be a separate do_IRQ function */ if (has_openpic) { irq = openpic_irq(0); if (irq == OPENPIC_VEC_SPURIOUS) { /* Spurious interrupts should never be ack'ed */ ppc_spurious_interrupts++; } else { /* Can this happen ? (comes from CHRP code) */ if (irq < 0) { printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", irq, regs->nip); ppc_spurious_interrupts++; } else { if (!irq_desc[irq].level) openpic_eoi(0); ppc_irq_dispatch_handler( regs, irq ); if (irq_desc[irq].level) openpic_eoi(0); } } return; } for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) | ppc_lost_interrupts[i]; if (bits == 0) continue; irq -= cntlzw(bits); break; } if (irq < 0) { printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", irq, regs->nip); ppc_spurious_interrupts++; } else { ppc_irq_dispatch_handler( regs, irq ); } #ifdef CONFIG_SMP out: #endif /* CONFIG_SMP */ } /* This routine will fix some missing interrupt values in the device tree * on the gatwick mac-io controller used by some PowerBooks */ static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) { struct device_node *node; int count; memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); node = gw->child; count = 0; while(node) { /* Fix SCC */ if (strcasecmp(node->name, "escc") == 0) if (node->child) { if (node->child->n_intrs < 3) { node->child->intrs = &gatwick_int_pool[count]; count += 3; } node->child->n_intrs = 3; node->child->intrs[0].line = 15+irq_base; node->child->intrs[1].line = 4+irq_base; node->child->intrs[2].line = 5+irq_base; printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", node->child->intrs[0].line, node->child->intrs[1].line, node->child->intrs[2].line); } /* Fix media-bay & left SWIM */ if (strcasecmp(node->name, "media-bay") == 0) { struct device_node* ya_node; if (node->n_intrs == 0) node->intrs = &gatwick_int_pool[count++]; node->n_intrs = 1; node->intrs[0].line = 29+irq_base; printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", node->intrs[0].line); ya_node = node->child; while(ya_node) { if (strcasecmp(ya_node->name, "floppy") == 0) { if (ya_node->n_intrs < 2) { ya_node->intrs = &gatwick_int_pool[count]; count += 2; } ya_node->n_intrs = 2; ya_node->intrs[0].line = 19+irq_base; ya_node->intrs[1].line = 1+irq_base; printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", ya_node->intrs[0].line, ya_node->intrs[1].line); } if (strcasecmp(ya_node->name, "ata4") == 0) { if (ya_node->n_intrs < 2) { ya_node->intrs = &gatwick_int_pool[count]; count += 2; } ya_node->n_intrs = 2; ya_node->intrs[0].line = 14+irq_base; ya_node->intrs[1].line = 3+irq_base; printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", ya_node->intrs[0].line, ya_node->intrs[1].line); } ya_node = ya_node->sibling; } } node = node->sibling; } if (count > 10) { printk("WARNING !! Gatwick interrupt pool overflow\n"); printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); printk(" requested = %d\n", count); } } /* * The PowerBook 3400/2400/3500 can have a combo ethernet/modem * card which includes an ohare chip that acts as a second interrupt * controller. If we find this second ohare, set it up and fix the * interrupt value in the device tree for the ethernet chip. */ static void __init enable_second_ohare(void) { unsigned char bus, devfn; unsigned short cmd; unsigned long addr; int second_irq; struct device_node *irqctrler = find_devices("pci106b,7"); struct device_node *ether; if (irqctrler == NULL || irqctrler->n_addrs <= 0) return; addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); max_irqs = 64; if (pci_device_loc(irqctrler, &bus, &devfn) == 0) { pmac_pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; cmd &= ~PCI_COMMAND_IO; pmac_pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); } second_irq = irqctrler->intrs[0].line; printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq); request_irq(second_irq, gatwick_action, SA_INTERRUPT, "interrupt cascade", 0 ); /* Fix interrupt for the modem/ethernet combo controller. The number in the device tree (27) is bogus (correct for the ethernet-only board but not the combo ethernet/modem board). The real interrupt is 28 on the second controller -> 28+32 = 60. */ ether = find_devices("pci1011,14"); if (ether && ether->n_intrs > 0) { ether->intrs[0].line = 60; printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", ether->intrs[0].line); } }
/* * High level IRQ handler called from shared_raw_irq_code_entry */ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) { register unsigned int irq; #if BSP_ISA_IRQ_NUMBER > 0 register unsigned isaIntr; /* boolean */ register unsigned oldMask = 0; /* old isa pic masks */ register unsigned newMask; /* new isa pic masks */ #endif if (excNum == ASM_DEC_VECTOR) { bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl); return 0; } #if BSP_PCI_IRQ_NUMBER > 0 if ( OpenPIC ) { irq = openpic_irq(0); if (irq == OPENPIC_VEC_SPURIOUS) { ++BSP_spuriousIntr; return 0; } /* some BSPs might want to use a different numbering... */ irq = irq - OPENPIC_VEC_SOURCE + BSP_PCI_IRQ_LOWEST_OFFSET; } else { #if BSP_ISA_IRQ_NUMBER > 0 #ifdef BSP_PCI_ISA_BRIDGE_IRQ irq = BSP_PCI_ISA_BRIDGE_IRQ; #else #error "Configuration Error -- BSP with ISA + PCI IRQs MUST define BSP_PCI_ISA_BRIDGE_IRQ" #endif #else BSP_panic("MUST have an OpenPIC if BSP has PCI IRQs but no ISA IRQs"); /* BSP_panic() never returns but the 'return' statement silences * a compiler warning about 'irq' possibly being used w/o initialization. */ return -1; #endif } #endif #if BSP_ISA_IRQ_NUMBER > 0 #ifdef BSP_PCI_ISA_BRIDGE_IRQ #if 0 == BSP_PCI_IRQ_NUMBER #error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ" #endif isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ); #else isaIntr = 1; #endif if (isaIntr) { /* * Acknowledge and read 8259 vector */ irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG); /* * store current PIC mask */ oldMask = i8259s_cache; newMask = oldMask | irq_mask_or_tbl [irq]; i8259s_cache = newMask; outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); BSP_irq_ack_at_i8259s (irq); #if BSP_PCI_IRQ_NUMBER > 0 if ( OpenPIC ) openpic_eoi(0); #endif } #endif /* dispatch handlers */ bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl); #if BSP_ISA_IRQ_NUMBER > 0 if (isaIntr) { i8259s_cache = oldMask; outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); } else #endif { #if BSP_PCI_IRQ_NUMBER > 0 #ifdef BSP_PCI_VME_DRIVER_DOES_EOI /* leave it to the VME bridge driver to do EOI, so * it can re-enable the openpic while handling * VME interrupts (-> VME priorities in software) */ if (_BSP_vme_bridge_irq != irq && OpenPIC)
void opic_ack_irq(struct pic_ops *pic, int irq) { openpic_eoi(curcpu()->ci_index); }
static status_t openpic_init(openpic_info *info) { uint32 x = openpic_read(info, OPENPIC_FEATURE); const char *featureVersion; char versionBuffer[64]; switch (x & OPENPIC_FEATURE_VERSION_MASK) { case 1: featureVersion = "1.0"; break; case 2: featureVersion = "1.2"; break; case 3: featureVersion = "1.3"; break; default: snprintf(versionBuffer, sizeof(versionBuffer), "unknown (feature reg: 0x%lx)", x); featureVersion = versionBuffer; break; } info->cpu_count = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; info->irq_count = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; /* * PSIM seems to report 1 too many IRQs */ // if (sc->sc_psim) // sc->sc_nirq--; dprintf("openpic: Version %s, supports %d CPUs and %d irqs\n", featureVersion, info->cpu_count, info->irq_count); /* disable all interrupts */ for (int irq = 0; irq < info->irq_count; irq++) openpic_write(info, OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK); openpic_set_priority(info, 0, 15); /* we don't need 8259 passthrough mode */ x = openpic_read(info, OPENPIC_CONFIG); x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; openpic_write(info, OPENPIC_CONFIG, x); /* send all interrupts to cpu 0 */ for (int irq = 0; irq < info->irq_count; irq++) openpic_write(info, OPENPIC_IDEST(irq), 1 << 0); for (int irq = 0; irq < info->irq_count; irq++) { x = irq; x |= OPENPIC_IMASK; x |= OPENPIC_POLARITY_POSITIVE; x |= OPENPIC_SENSE_LEVEL; x |= 8 << OPENPIC_PRIORITY_SHIFT; openpic_write(info, OPENPIC_SRC_VECTOR(irq), x); } /* XXX IPI */ /* XXX set spurious intr vector */ openpic_set_priority(info, 0, 0); /* clear all pending interrupts */ for (int irq = 0; irq < info->irq_count; irq++) { openpic_read_irq(info, 0); openpic_eoi(info, 0); } return B_OK; }