📄 manage.c
字号:
/* * linux/kernel/irq/manage.c * * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar * Copyright (C) 2005-2006 Thomas Gleixner * * This file contains driver APIs to the irq subsystem. */#include <linux/irq.h>#include <linux/module.h>#include <linux/random.h>#include <linux/interrupt.h>#include <linux/slab.h>#include "internals.h"#ifdef CONFIG_SMPcpumask_t irq_default_affinity = CPU_MASK_ALL;/** * synchronize_irq - wait for pending IRQ handlers (on other CPUs) * @irq: interrupt number to wait for * * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while * holding a resource the IRQ handler may need you will deadlock. * * This function may be called - with care - from IRQ context. */void synchronize_irq(unsigned int irq){ struct irq_desc *desc = irq_desc + irq; unsigned int status; if (irq >= NR_IRQS) return; do { unsigned long flags; /* * Wait until we're out of the critical section. This might * give the wrong answer due to the lack of memory barriers. */ while (desc->status & IRQ_INPROGRESS) cpu_relax(); /* Ok, that indicated we're done: double-check carefully. */ spin_lock_irqsave(&desc->lock, flags); status = desc->status; spin_unlock_irqrestore(&desc->lock, flags); /* Oops, that failed? */ } while (status & IRQ_INPROGRESS);}EXPORT_SYMBOL(synchronize_irq);/** * irq_can_set_affinity - Check if the affinity of a given irq can be set * @irq: Interrupt to check * */int irq_can_set_affinity(unsigned int irq){ struct irq_desc *desc = irq_desc + irq; if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip || !desc->chip->set_affinity) return 0; return 1;}/** * irq_set_affinity - Set the irq affinity of a given irq * @irq: Interrupt to set affinity * @cpumask: cpumask * */int irq_set_affinity(unsigned int irq, cpumask_t cpumask){ struct irq_desc *desc = irq_desc + irq; if (!desc->chip->set_affinity) return -EINVAL; set_balance_irq_affinity(irq, cpumask);#ifdef CONFIG_GENERIC_PENDING_IRQ set_pending_irq(irq, cpumask);#else desc->affinity = cpumask; desc->chip->set_affinity(irq, cpumask);#endif return 0;}#ifndef CONFIG_AUTO_IRQ_AFFINITY/* * Generic version of the affinity autoselector. */int irq_select_affinity(unsigned int irq){ cpumask_t mask; if (!irq_can_set_affinity(irq)) return 0; cpus_and(mask, cpu_online_map, irq_default_affinity); irq_desc[irq].affinity = mask; irq_desc[irq].chip->set_affinity(irq, mask); set_balance_irq_affinity(irq, mask); return 0;}#endif#endif/** * disable_irq_nosync - disable an irq without waiting * @irq: Interrupt to disable * * Disable the selected interrupt line. Disables and Enables are * nested. * Unlike disable_irq(), this function does not ensure existing * instances of the IRQ handler have completed before returning. * * This function may be called from IRQ context. */void disable_irq_nosync(unsigned int irq){ struct irq_desc *desc = irq_desc + irq; unsigned long flags; if (irq >= NR_IRQS) return; spin_lock_irqsave(&desc->lock, flags); if (!desc->depth++) { desc->status |= IRQ_DISABLED; desc->chip->disable(irq); } spin_unlock_irqrestore(&desc->lock, flags);}EXPORT_SYMBOL(disable_irq_nosync);/** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * * Disable the selected interrupt line. Enables and Disables are * nested. * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while * holding a resource the IRQ handler may need you will deadlock. * * This function may be called - with care - from IRQ context. */void disable_irq(unsigned int irq){ struct irq_desc *desc = irq_desc + irq; if (irq >= NR_IRQS) return; disable_irq_nosync(irq); if (desc->action) synchronize_irq(irq);}EXPORT_SYMBOL(disable_irq);static void __enable_irq(struct irq_desc *desc, unsigned int irq){ switch (desc->depth) { case 0: WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); break; case 1: { unsigned int status = desc->status & ~IRQ_DISABLED; /* Prevent probing on this irq: */ desc->status = status | IRQ_NOPROBE; check_irq_resend(desc, irq); /* fall-through */ } default: desc->depth--; }}/** * enable_irq - enable handling of an irq * @irq: Interrupt to enable * * Undoes the effect of one call to disable_irq(). If this * matches the last disable, processing of interrupts on this * IRQ line is re-enabled. * * This function may be called from IRQ context. */void enable_irq(unsigned int irq){ struct irq_desc *desc = irq_desc + irq; unsigned long flags; if (irq >= NR_IRQS) return; spin_lock_irqsave(&desc->lock, flags); __enable_irq(desc, irq); spin_unlock_irqrestore(&desc->lock, flags);}EXPORT_SYMBOL(enable_irq);int set_irq_wake_real(unsigned int irq, unsigned int on){ struct irq_desc *desc = irq_desc + irq; int ret = -ENXIO; if (desc->chip->set_wake) ret = desc->chip->set_wake(irq, on); return ret;}/** * set_irq_wake - control irq power management wakeup * @irq: interrupt to control * @on: enable/disable power management wakeup * * Enable/disable power management wakeup mode, which is * disabled by default. Enables and disables must match, * just as they match for non-wakeup mode support. * * Wakeup mode lets this IRQ wake the system from sleep * states like "suspend to RAM". */int set_irq_wake(unsigned int irq, unsigned int on){ struct irq_desc *desc = irq_desc + irq; unsigned long flags; int ret = 0; /* wakeup-capable irqs can be shared between drivers that * don't need to have the same sleep mode behaviors. */ spin_lock_irqsave(&desc->lock, flags); if (on) { if (desc->wake_depth++ == 0) { ret = set_irq_wake_real(irq, on); if (ret) desc->wake_depth = 0; else desc->status |= IRQ_WAKEUP; } } else { if (desc->wake_depth == 0) { WARN(1, "Unbalanced IRQ %d wake disable\n", irq); } else if (--desc->wake_depth == 0) { ret = set_irq_wake_real(irq, on); if (ret) desc->wake_depth = 1; else desc->status &= ~IRQ_WAKEUP; } } spin_unlock_irqrestore(&desc->lock, flags); return ret;}EXPORT_SYMBOL(set_irq_wake);/* * Internal function that tells the architecture code whether a * particular irq has been exclusively allocated or is available * for driver use. */int can_request_irq(unsigned int irq, unsigned long irqflags){ struct irqaction *action; if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST) return 0; action = irq_desc[irq].action; if (action) if (irqflags & action->flags & IRQF_SHARED) action = NULL; return !action;}void compat_irq_chip_set_default_handler(struct irq_desc *desc){ /* * If the architecture still has not overriden * the flow handler then zap the default. This * should catch incorrect flow-type setting. */ if (desc->handle_irq == &handle_bad_irq) desc->handle_irq = NULL;}static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, unsigned long flags){ int ret; if (!chip || !chip->set_type) { /* * IRQF_TRIGGER_* but the PIC does not support multiple * flow-types? */ pr_warning("No set_type function for IRQ %d (%s)\n", irq, chip ? (chip->name ? : "unknown") : "unknown"); return 0; } ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK); if (ret) pr_err("setting trigger mode %d for irq %u failed (%pF)\n", (int)(flags & IRQF_TRIGGER_MASK), irq, chip->set_type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -