788 lines · 19.8 KB · C
RawDownload
/* * linux/kernel/irq/chip.c * * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar * Copyright (C) 2005-2006, Thomas Gleixner, Russell King * * This file contains the core interrupt handling code, for irq-chip * based architectures. * * Detailed information is available in Documentation/DocBook/genericirq */ #include <linux/irq.h>#include <linux/msi.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/kernel_stat.h> #include <trace/events/irq.h> #include "internals.h" /** *	irq_set_chip - set the irq chip for an irq *	@irq:	irq number *	@chip:	pointer to irq chip description structure */int irq_set_chip(unsigned int irq, struct irq_chip *chip){	unsigned long flags;	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); 	if (!desc)		return -EINVAL; 	if (!chip)		chip = &no_irq_chip; 	desc->irq_data.chip = chip;	irq_put_desc_unlock(desc, flags);	/*	 * For !CONFIG_SPARSE_IRQ make the irq show up in	 * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is	 * already marked, and this call is harmless.	 */	irq_reserve_irq(irq);	return 0;}EXPORT_SYMBOL(irq_set_chip); /** *	irq_set_type - set the irq trigger type for an irq *	@irq:	irq number *	@type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h */int irq_set_irq_type(unsigned int irq, unsigned int type){	unsigned long flags;	struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);	int ret = 0; 	if (!desc)		return -EINVAL; 	type &= IRQ_TYPE_SENSE_MASK;	ret = __irq_set_trigger(desc, irq, type);	irq_put_desc_busunlock(desc, flags);	return ret;}EXPORT_SYMBOL(irq_set_irq_type); /** *	irq_set_handler_data - set irq handler data for an irq *	@irq:	Interrupt number *	@data:	Pointer to interrupt specific data * *	Set the hardware irq controller data for an irq */int irq_set_handler_data(unsigned int irq, void *data){	unsigned long flags;	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); 	if (!desc)		return -EINVAL;	desc->irq_data.handler_data = data;	irq_put_desc_unlock(desc, flags);	return 0;}EXPORT_SYMBOL(irq_set_handler_data); /** *	irq_set_msi_desc_off - set MSI descriptor data for an irq at offset *	@irq_base:	Interrupt number base *	@irq_offset:	Interrupt number offset *	@entry:		Pointer to MSI descriptor data * *	Set the MSI descriptor entry for an irq at offset */int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,			 struct msi_desc *entry){	unsigned long flags;	struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL); 	if (!desc)		return -EINVAL;	desc->irq_data.msi_desc = entry;	if (entry && !irq_offset)		entry->irq = irq_base;	irq_put_desc_unlock(desc, flags);	return 0;} /** *	irq_set_msi_desc - set MSI descriptor data for an irq *	@irq:	Interrupt number *	@entry:	Pointer to MSI descriptor data * *	Set the MSI descriptor entry for an irq */int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry){	return irq_set_msi_desc_off(irq, 0, entry);} /** *	irq_set_chip_data - set irq chip data for an irq *	@irq:	Interrupt number *	@data:	Pointer to chip specific data * *	Set the hardware irq chip data for an irq */int irq_set_chip_data(unsigned int irq, void *data){	unsigned long flags;	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); 	if (!desc)		return -EINVAL;	desc->irq_data.chip_data = data;	irq_put_desc_unlock(desc, flags);	return 0;}EXPORT_SYMBOL(irq_set_chip_data); struct irq_data *irq_get_irq_data(unsigned int irq){	struct irq_desc *desc = irq_to_desc(irq); 	return desc ? &desc->irq_data : NULL;}EXPORT_SYMBOL_GPL(irq_get_irq_data); static void irq_state_clr_disabled(struct irq_desc *desc){	irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED);} static void irq_state_set_disabled(struct irq_desc *desc){	irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);} static void irq_state_clr_masked(struct irq_desc *desc){	irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED);} static void irq_state_set_masked(struct irq_desc *desc){	irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);} int irq_startup(struct irq_desc *desc, bool resend){	int ret = 0; 	irq_state_clr_disabled(desc);	desc->depth = 0; 	if (desc->irq_data.chip->irq_startup) {		ret = desc->irq_data.chip->irq_startup(&desc->irq_data);		irq_state_clr_masked(desc);	} else {		irq_enable(desc);	}	if (resend)		check_irq_resend(desc, desc->irq_data.irq);	return ret;} void irq_shutdown(struct irq_desc *desc){	irq_state_set_disabled(desc);	desc->depth = 1;	if (desc->irq_data.chip->irq_shutdown)		desc->irq_data.chip->irq_shutdown(&desc->irq_data);	else if (desc->irq_data.chip->irq_disable)		desc->irq_data.chip->irq_disable(&desc->irq_data);	else		desc->irq_data.chip->irq_mask(&desc->irq_data);	irq_state_set_masked(desc);} void irq_enable(struct irq_desc *desc){	irq_state_clr_disabled(desc);	if (desc->irq_data.chip->irq_enable)		desc->irq_data.chip->irq_enable(&desc->irq_data);	else		desc->irq_data.chip->irq_unmask(&desc->irq_data);	irq_state_clr_masked(desc);} /** * irq_disable - Mark interrupt disabled * @desc:	irq descriptor which should be disabled * * If the chip does not implement the irq_disable callback, we * use a lazy disable approach. That means we mark the interrupt * disabled, but leave the hardware unmasked. That's an * optimization because we avoid the hardware access for the * common case where no interrupt happens after we marked it * disabled. If an interrupt happens, then the interrupt flow * handler masks the line at the hardware level and marks it * pending. */void irq_disable(struct irq_desc *desc){	irq_state_set_disabled(desc);	if (desc->irq_data.chip->irq_disable) {		desc->irq_data.chip->irq_disable(&desc->irq_data);		irq_state_set_masked(desc);	}} void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu){	if (desc->irq_data.chip->irq_enable)		desc->irq_data.chip->irq_enable(&desc->irq_data);	else		desc->irq_data.chip->irq_unmask(&desc->irq_data);	cpumask_set_cpu(cpu, desc->percpu_enabled);} void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu){	if (desc->irq_data.chip->irq_disable)		desc->irq_data.chip->irq_disable(&desc->irq_data);	else		desc->irq_data.chip->irq_mask(&desc->irq_data);	cpumask_clear_cpu(cpu, desc->percpu_enabled);} static inline void mask_ack_irq(struct irq_desc *desc){	if (desc->irq_data.chip->irq_mask_ack)		desc->irq_data.chip->irq_mask_ack(&desc->irq_data);	else {		desc->irq_data.chip->irq_mask(&desc->irq_data);		if (desc->irq_data.chip->irq_ack)			desc->irq_data.chip->irq_ack(&desc->irq_data);	}	irq_state_set_masked(desc);} void mask_irq(struct irq_desc *desc){	if (desc->irq_data.chip->irq_mask) {		desc->irq_data.chip->irq_mask(&desc->irq_data);		irq_state_set_masked(desc);	}} void unmask_irq(struct irq_desc *desc){	if (desc->irq_data.chip->irq_unmask) {		desc->irq_data.chip->irq_unmask(&desc->irq_data);		irq_state_clr_masked(desc);	}} /* *	handle_nested_irq - Handle a nested irq from a irq thread *	@irq:	the interrupt number * *	Handle interrupts which are nested into a threaded interrupt *	handler. The handler function is called inside the calling *	threads context. */void handle_nested_irq(unsigned int irq){	struct irq_desc *desc = irq_to_desc(irq);	struct irqaction *action;	irqreturn_t action_ret; 	might_sleep(); 	raw_spin_lock_irq(&desc->lock); 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);	kstat_incr_irqs_this_cpu(irq, desc); 	action = desc->action;	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {		desc->istate |= IRQS_PENDING;		goto out_unlock;	} 	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);	raw_spin_unlock_irq(&desc->lock); 	action_ret = action->thread_fn(action->irq, action->dev_id);	if (!noirqdebug)		note_interrupt(irq, desc, action_ret); 	raw_spin_lock_irq(&desc->lock);	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); out_unlock:	raw_spin_unlock_irq(&desc->lock);}EXPORT_SYMBOL_GPL(handle_nested_irq); static bool irq_check_poll(struct irq_desc *desc){	if (!(desc->istate & IRQS_POLL_INPROGRESS))		return false;	return irq_wait_for_poll(desc);} /** *	handle_simple_irq - Simple and software-decoded IRQs. *	@irq:	the interrupt number *	@desc:	the interrupt description structure for this irq * *	Simple interrupts are either sent from a demultiplexing interrupt *	handler or come from hardware, where no interrupt hardware control *	is necessary. * *	Note: The caller is expected to handle the ack, clear, mask and *	unmask issues if necessary. */voidhandle_simple_irq(unsigned int irq, struct irq_desc *desc){	raw_spin_lock(&desc->lock); 	if (unlikely(irqd_irq_inprogress(&desc->irq_data)))		if (!irq_check_poll(desc))			goto out_unlock; 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);	kstat_incr_irqs_this_cpu(irq, desc); 	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {		desc->istate |= IRQS_PENDING;		goto out_unlock;	} 	handle_irq_event(desc); out_unlock:	raw_spin_unlock(&desc->lock);}EXPORT_SYMBOL_GPL(handle_simple_irq); /* * Called unconditionally from handle_level_irq() and only for oneshot * interrupts from handle_fasteoi_irq() */static void cond_unmask_irq(struct irq_desc *desc){	/*	 * We need to unmask in the following cases:	 * - Standard level irq (IRQF_ONESHOT is not set)	 * - Oneshot irq which did not wake the thread (caused by a	 *   spurious interrupt or a primary handler handling it	 *   completely).	 */	if (!irqd_irq_disabled(&desc->irq_data) &&	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot)		unmask_irq(desc);} /** *	handle_level_irq - Level type irq handler *	@irq:	the interrupt number *	@desc:	the interrupt description structure for this irq * *	Level type interrupts are active as long as the hardware line has *	the active level. This may require to mask the interrupt and unmask *	it after the associated handler has acknowledged the device, so the *	interrupt line is back to inactive. */voidhandle_level_irq(unsigned int irq, struct irq_desc *desc){	raw_spin_lock(&desc->lock);	mask_ack_irq(desc); 	if (unlikely(irqd_irq_inprogress(&desc->irq_data)))		if (!irq_check_poll(desc))			goto out_unlock; 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);	kstat_incr_irqs_this_cpu(irq, desc); 	/*	 * If its disabled or no action available	 * keep it masked and get out of here	 */	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {		desc->istate |= IRQS_PENDING;		goto out_unlock;	} 	handle_irq_event(desc); 	cond_unmask_irq(desc); out_unlock:	raw_spin_unlock(&desc->lock);}EXPORT_SYMBOL_GPL(handle_level_irq); #ifdef CONFIG_IRQ_PREFLOW_FASTEOIstatic inline void preflow_handler(struct irq_desc *desc){	if (desc->preflow_handler)		desc->preflow_handler(&desc->irq_data);}#elsestatic inline void preflow_handler(struct irq_desc *desc) { }#endif /** *	handle_fasteoi_irq - irq handler for transparent controllers *	@irq:	the interrupt number *	@desc:	the interrupt description structure for this irq * *	Only a single callback will be issued to the chip: an ->eoi() *	call when the interrupt has been serviced. This enables support *	for modern forms of interrupt handlers, which handle the flow *	details in hardware, transparently. */voidhandle_fasteoi_irq(unsigned int irq, struct irq_desc *desc){	raw_spin_lock(&desc->lock); 	if (unlikely(irqd_irq_inprogress(&desc->irq_data)))		if (!irq_check_poll(desc))			goto out; 	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);	kstat_incr_irqs_this_cpu(irq, desc); 	/*	 * If its disabled or no action available	 * then mask it and get out of here:	 */	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {		desc->istate |= IRQS_PENDING;		mask_irq(desc);		goto out;	} 	if (desc->istate & IRQS_ONESHOT)		mask_irq(desc); 	preflow_handler(desc);	handle_irq_event(desc); 	if (desc->istate & IRQS_ONESHOT)		cond_unmask_irq(desc); out_eoi:	desc->irq_data.chip->irq_eoi(&desc->irq_data);out_unlock:	raw_spin_unlock(&desc->lock);	return;out:	if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))		goto out_eoi;	goto out_unlock;} /** *	handle_edge_irq - edge type IRQ handler *	@irq:	the interrupt number *	@desc:	the interrupt description structure for this irq * *	Interrupt occures on the falling and/or rising edge of a hardware *	signal. The occurrence is latched into the irq controller hardware *	and must be acked in order to be reenabled. After the ack another *	interrupt can happen on the same source even before the first one *	is handled by the associated event handler. If this happens it *	might be necessary to disable (mask) the interrupt depending on the

Lines 1–500 of 788.