int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type) { unsigned int src = virq_to_hw(d->irq); unsigned int vecpri, vold, vnew, prio, cpu_dest; unsigned long flags; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; irqd_set_trigger_type(d, flow_type); vecpri = ehv_pic_type_to_vecpri(flow_type); spin_lock_irqsave(&ehv_pic_lock, flags); ev_int_get_config(src, &vold, &prio, &cpu_dest); vnew = vold & ~(EHV_PIC_INFO(VECPRI_POLARITY_MASK) | EHV_PIC_INFO(VECPRI_SENSE_MASK)); vnew |= vecpri; /* * TODO : Add specific interface call for platform to set * individual interrupt priorities. * platform currently using static/default priority for all ints */ prio = 8; ev_int_set_config(src, vecpri, prio, cpu_dest); spin_unlock_irqrestore(&ehv_pic_lock, flags); return IRQ_SET_MASK_OK_NOCOPY; }
static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id) { struct pseries_errorlog *pseries_log; struct pseries_hp_errorlog *hp_elog; spin_lock(&ras_log_buf_lock); rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq), RTAS_HOTPLUG_EVENTS, 0, __pa(&ras_log_buf), rtas_get_error_log_max()); pseries_log = get_pseries_errorlog((struct rtas_error_log *)ras_log_buf, PSERIES_ELOG_SECT_ID_HOTPLUG); hp_elog = (struct pseries_hp_errorlog *)pseries_log->data; /* * Since PCI hotplug is not currently supported on pseries, put PCI * hotplug events on the ras_log_buf to be handled by rtas_errd. */ if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM || hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU || hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM) queue_hotplug_event(hp_elog); else log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
int ps3_connect_event_irq(const struct ps3_device_id *did, unsigned int interrupt_id, unsigned int *virq) { int result; result = ps3_alloc_event_irq(virq); if (result) return result; result = lv1_connect_interrupt_event_receive_port(did->bus_id, did->dev_id, virq_to_hw(*virq), interrupt_id); if (result) { pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_free_event_irq(*virq); *virq = NO_IRQ; return result; } pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, interrupt_id, *virq); return 0; }
int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, unsigned int virq) { /* */ int result; DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, dev->interrupt_id, virq); result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, dev->dev_id, virq_to_hw(virq), dev->interrupt_id); if (result) FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); result = ps3_event_receive_port_destroy(virq); BUG_ON(result); /* */ result = ps3_virq_destroy(virq); BUG_ON(result); DBG(" <- %s:%d\n", __func__, __LINE__); return result; }
int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, unsigned int virq) { /* this should go in system-bus.c */ int result; pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, dev->interrupt_id, virq); result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, dev->dev_id, virq_to_hw(virq), dev->interrupt_id); if (result) pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); result = ps3_event_receive_port_destroy(virq); BUG_ON(result); /* * ps3_event_receive_port_destroy() destroys the IRQ plug, * so don't call ps3_irq_plug_destroy() here. */ result = ps3_virq_destroy(virq); BUG_ON(result); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; }
/* * The interrupt controller is setup such that it doesn't work well with * the level interrupt handler in the kernel because the handler acks the * interrupt before calling the application interrupt handler. To deal with * that, we use 2 different irq chips so that different functions can be * used for level and edge type interrupts. * * IRQ Chip common (across level and edge) operations */ static void xilinx_intc_mask(unsigned int virq) { int irq = virq_to_hw(virq); void * regs = get_irq_chip_data(virq); pr_debug("mask: %d\n", irq); out_be32(regs + XINTC_CIE, 1 << irq); }
/* Handle environmental and power warning (EPOW) interrupts. */ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) { int status; int state; int critical; status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state); if (state > 3) critical = 1; /* Time Critical */ else critical = 0; spin_lock(&ras_log_buf_lock); status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq), RTAS_EPOW_WARNING, critical, __pa(&ras_log_buf), rtas_get_error_log_max()); log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf); spin_unlock(&ras_log_buf_lock); return IRQ_HANDLED; }
static void xilinx_intc_edge_ack(unsigned int virq) { int irq = virq_to_hw(virq); void * regs = get_irq_chip_data(virq); pr_debug("ack: %d\n", irq); out_be32(regs + XINTC_IAR, 1 << irq); }
int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, enum ps3_cpu_binding cpu, unsigned int *virq) { /* this should go in system-bus.c */ int result; result = ps3_event_receive_port_setup(cpu, virq); if (result) return result; result = lv1_connect_interrupt_event_receive_port(dev->bus_id, dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); if (result) { pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_event_receive_port_destroy(*virq); *virq = NO_IRQ; return result; } pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, dev->interrupt_id, *virq); return 0; }
static void flipper_pic_unmask(unsigned int virq) { int irq = virq_to_hw(virq); void __iomem *io_base = get_irq_chip_data(virq); setbits32(io_base + FLIPPER_IMR, 1 << irq); }
static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) { unsigned int src = virq_to_hw(virq); struct irq_desc *desc = irq_to_desc(virq); unsigned int vold, vnew, edibit; /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or * IRQ_TYPE_EDGE_BOTH (default). All others are IRQ_TYPE_EDGE_FALLING * or IRQ_TYPE_LEVEL_LOW (default) */ if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) { if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_EDGE_BOTH; if (flow_type != IRQ_TYPE_EDGE_BOTH && flow_type != IRQ_TYPE_EDGE_FALLING) goto err_sense; } else { if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) goto err_sense; } desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; if (flow_type & IRQ_TYPE_LEVEL_LOW) { desc->status |= IRQ_LEVEL; desc->handle_irq = handle_level_irq; } else desc->handle_irq = handle_edge_irq; /* internal IRQ senses are LEVEL_LOW * EXT IRQ and Port C IRQ senses are programmable */ if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7) edibit = (14 - (src - CPM2_IRQ_EXT1)); else if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) edibit = (31 - (CPM2_IRQ_PORTC0 - src)); else return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; vold = in_be32(&cpm2_intctl->ic_siexr); if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) vnew = vold | (1 << edibit); else vnew = vold & ~(1 << edibit); if (vold != vnew) out_be32(&cpm2_intctl->ic_siexr, vnew); return 0; err_sense: pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type); return -EINVAL; }
static void flipper_pic_ack(unsigned int virq) { int irq = virq_to_hw(virq); void __iomem *io_base = get_irq_chip_data(virq); /* this is at least needed for RSW */ out_be32(io_base + FLIPPER_ICR, 1 << irq); }
static irqreturn_t opal_interrupt(int irq, void *data) { uint64_t events; opal_handle_interrupt(virq_to_hw(irq), &events); /* XXX TODO: Do something with the events */ return IRQ_HANDLED; }
static void flipper_pic_mask_and_ack(unsigned int virq) { int irq = virq_to_hw(virq); void __iomem *io_base = get_irq_chip_data(virq); u32 mask = 1 << irq; clrbits32(io_base + FLIPPER_IMR, mask); /* this is at least needed for RSW */ out_be32(io_base + FLIPPER_ICR, mask); }
static irqreturn_t opal_interrupt(int irq, void *data) { __be64 events; opal_handle_interrupt(virq_to_hw(irq), &events); opal_do_notifier(events); return IRQ_HANDLED; }
static void cpm2_ack(unsigned int virq) { int bit, word; unsigned int irq_nr = virq_to_hw(virq); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); }
static irqreturn_t opal_interrupt(int irq, void *data) { __be64 events; opal_handle_interrupt(virq_to_hw(irq), &events); last_outstanding_events = be64_to_cpu(events); if (opal_have_pending_events()) opal_wake_poller(); return IRQ_HANDLED; }
static void cpm2_unmask_irq(unsigned int virq) { int bit, word; unsigned int irq_nr = virq_to_hw(virq); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; ppc_cached_irq_mask[word] |= 1 << bit; out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); }
/* * IRQ Chip level operations */ static void xilinx_intc_level_unmask(unsigned int virq) { int irq = virq_to_hw(virq); void * regs = get_irq_chip_data(virq); pr_debug("unmask: %d\n", irq); out_be32(regs + XINTC_SIE, 1 << irq); /* ack level irqs because they can't be acked during * ack function since the handle_level_irq function * acks the irq before calling the inerrupt handler */ out_be32(regs + XINTC_IAR, 1 << irq); }
static void pq2ads_pci_unmask_irq(unsigned int virq) { struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); int irq = NUM_IRQS - virq_to_hw(virq) - 1; if (irq != -1) { unsigned long flags; spin_lock_irqsave(&pci_pic_lock, flags); clrbits32(&priv->regs->mask, 1 << irq); spin_unlock_irqrestore(&pci_pic_lock, flags); } }
int ps3_free_io_irq(unsigned int virq) { int result; result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); if (result) pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); irq_dispose_mapping(virq); return result; }
int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest, bool force) { unsigned int src = virq_to_hw(d->irq); unsigned int config, prio, cpu_dest; int cpuid = irq_choose_cpu(dest); unsigned long flags; spin_lock_irqsave(&ehv_pic_lock, flags); ev_int_get_config(src, &config, &prio, &cpu_dest); ev_int_set_config(src, config, prio, cpuid); spin_unlock_irqrestore(&ehv_pic_lock, flags); return IRQ_SET_MASK_OK; }
int ps3_io_irq_destroy(unsigned int virq) { int result; result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); if (result) pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", __func__, __LINE__, ps3_result(result)); result = ps3_irq_plug_destroy(virq); BUG_ON(result); return result; }
int ps3_free_event_irq(unsigned int virq) { int result; pr_debug(" -> %s:%d\n", __func__, __LINE__); result = lv1_destruct_event_receive_port(virq_to_hw(virq)); if (result) pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); irq_dispose_mapping(virq); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; }
static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) { unsigned int src = virq_to_hw(virq); struct irq_desc *desc = get_irq_desc(virq); unsigned int vold, vnew, edibit; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; if (flow_type & IRQ_TYPE_EDGE_RISING) { printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n", flow_type); return -EINVAL; } desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; if (flow_type & IRQ_TYPE_LEVEL_LOW) { desc->status |= IRQ_LEVEL; desc->handle_irq = handle_level_irq; } else desc->handle_irq = handle_edge_irq; /* internal IRQ senses are LEVEL_LOW * EXT IRQ and Port C IRQ senses are programmable */ if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7) edibit = (14 - (src - CPM2_IRQ_EXT1)); else if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) edibit = (31 - (src - CPM2_IRQ_PORTC15)); else return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; vold = in_be32(&cpm2_intctl->ic_siexr); if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) vnew = vold | (1 << edibit); else vnew = vold & ~(1 << edibit); if (vold != vnew) out_be32(&cpm2_intctl->ic_siexr, vnew); return 0; }
static int ics_rtas_map(struct ics *ics, unsigned int virq) { unsigned int hw_irq = (unsigned int)virq_to_hw(virq); int status[2]; int rc; if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) return -EINVAL; /* Check if RTAS knows about this interrupt */ rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq); if (rc) return -ENXIO; irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq); irq_set_chip_data(virq, &ics_rtas); return 0; }
static void cpm2_end_irq(unsigned int virq) { struct irq_desc *desc; int bit, word; unsigned int irq_nr = virq_to_hw(virq); desc = irq_to_desc(irq_nr); if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)) && desc->action) { bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; ppc_cached_irq_mask[word] |= 1 << bit; out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); mb(); } }
static int ics_opal_map(struct ics *ics, unsigned int virq) { unsigned int hw_irq = (unsigned int)virq_to_hw(virq); int64_t rc; int16_t server; int8_t priority; if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) return -EINVAL; rc = opal_get_xive(hw_irq, &server, &priority); if (rc != OPAL_SUCCESS) return -ENXIO; irq_set_chip_and_handler(virq, &ics_opal_irq_chip, handle_fasteoi_irq); irq_set_chip_data(virq, &ics_hal); return 0; }
static void cpm2_end_irq(unsigned int virq) { int bit, word; unsigned int irq_nr = virq_to_hw(virq); if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq_nr].action) { bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; ppc_cached_irq_mask[word] |= 1 << bit; out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); /* * Work around large numbers of spurious IRQs on PowerPC 82xx * systems. */ mb(); } }
int ps3_disconnect_event_irq(const struct ps3_device_id *did, unsigned int interrupt_id, unsigned int virq) { int result; pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, interrupt_id, virq); result = lv1_disconnect_interrupt_event_receive_port(did->bus_id, did->dev_id, virq_to_hw(virq), interrupt_id); if (result) pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_free_event_irq(virq); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; }