1/* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2012. */ 2/* 3 * linux/kernel/irq/resend.c 4 * 5 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar 6 * Copyright (C) 2005-2006, Thomas Gleixner 7 * 8 * This file contains the IRQ-resend code 9 * 10 * If the interrupt is waiting to be processed, we try to re-run it. 11 * We can't directly run it from here since the caller might be in an 12 * interrupt-protected region. Not all irq controller chips can 13 * retrigger interrupts at the hardware level, so in those cases 14 * we allow the resending of IRQs via a tasklet. 15 */ 16 17#include <linux/irq.h> 18#include <linux/module.h> 19#include <linux/random.h> 20#include <linux/interrupt.h> 21 22#if defined(CONFIG_BUZZZ) 23#include <asm/buzzz.h> 24#endif /* CONFIG_BUZZZ */ 25 26#include "internals.h" 27 28#ifdef CONFIG_HARDIRQS_SW_RESEND 29 30/* Bitmap to handle software resend of interrupts: */ 31static DECLARE_BITMAP(irqs_resend, NR_IRQS); 32 33/* 34 * Run software resends of IRQ's 35 */ 36static void resend_irqs(unsigned long arg) 37{ 38 struct irq_desc *desc; 39 int irq; 40 41 while (!bitmap_empty(irqs_resend, nr_irqs)) { 42 irq = find_first_bit(irqs_resend, nr_irqs); 43 44#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 1) 45 buzzz_kevt_log1(BUZZZ_KEVT_ID_IRQ_RESEND, irq); 46#endif /* BUZZZ_KEVT_LVL */ 47 48 clear_bit(irq, irqs_resend); 49 desc = irq_to_desc(irq); 50 local_irq_disable(); 51 desc->handle_irq(irq, desc); 52 local_irq_enable(); 53 } 54} 55 56/* Tasklet to handle resend: */ 57static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); 58 59#endif 60 61/* 62 * IRQ resend 63 * 64 * Is called with interrupts disabled and desc->lock held. 65 */ 66void check_irq_resend(struct irq_desc *desc, unsigned int irq) 67{ 68 unsigned int status = desc->status; 69 70#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 1) 71 buzzz_kevt_log1(BUZZZ_KEVT_ID_IRQ_CHECK, irq); 72#endif /* BUZZZ_KEVT_LVL */ 73 74 /* 75 * Make sure the interrupt is enabled, before resending it: 76 */ 77 desc->chip->enable(irq); 78 79 /* 80 * We do not resend level type interrupts. Level type 81 * interrupts are resent by hardware when they are still 82 * active. 83 */ 84 if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { 85 desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY; 86 87 if (!desc->chip->retrigger || !desc->chip->retrigger(irq)) { 88#ifdef CONFIG_HARDIRQS_SW_RESEND 89 /* Set it pending and activate the softirq: */ 90 set_bit(irq, irqs_resend); 91 tasklet_schedule(&resend_tasklet); 92#endif 93 } 94 } 95} 96