hc
2023-11-07 f45e756958099c35d6afb746df1d40a1c6302cfc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
 * Copyright (C) 2005-2006, Thomas Gleixner
 *
 * This file contains the IRQ-resend code
 *
 * If the interrupt is waiting to be processed, we try to re-run it.
 * We can't directly run it from here since the caller might be in an
 * interrupt-protected region. Not all irq controller chips can
 * retrigger interrupts at the hardware level, so in those cases
 * we allow the resending of IRQs via a tasklet.
 */
 
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/interrupt.h>
 
#include "internals.h"
 
#ifdef CONFIG_HARDIRQS_SW_RESEND
 
/* Bitmap to handle software resend of interrupts: */
static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
 
/*
 * Run software resends of IRQ's
 */
static void resend_irqs(unsigned long arg)
{
   struct irq_desc *desc;
   int irq;
 
   while (!bitmap_empty(irqs_resend, nr_irqs)) {
       irq = find_first_bit(irqs_resend, nr_irqs);
       clear_bit(irq, irqs_resend);
       desc = irq_to_desc(irq);
       if (!desc)
           continue;
       local_irq_disable();
       desc->handle_irq(desc);
       local_irq_enable();
   }
}
 
/* Tasklet to handle resend: */
static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
 
#endif
 
/*
 * IRQ resend
 *
 * Is called with interrupts disabled and desc->lock held.
 */
void check_irq_resend(struct irq_desc *desc)
{
   /*
    * We do not resend level type interrupts. Level type
    * interrupts are resent by hardware when they are still
    * active. Clear the pending bit so suspend/resume does not
    * get confused.
    */
   if (irq_settings_is_level(desc)) {
       desc->istate &= ~IRQS_PENDING;
       return;
   }
   if (desc->istate & IRQS_REPLAY)
       return;
   if (desc->istate & IRQS_PENDING) {
       desc->istate &= ~IRQS_PENDING;
       desc->istate |= IRQS_REPLAY;
 
       if (!desc->irq_data.chip->irq_retrigger ||
           !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
#ifdef CONFIG_HARDIRQS_SW_RESEND
           unsigned int irq = irq_desc_get_irq(desc);
 
           /*
            * If the interrupt is running in the thread
            * context of the parent irq we need to be
            * careful, because we cannot trigger it
            * directly.
            */
           if (irq_settings_is_nested_thread(desc)) {
               /*
                * If the parent_irq is valid, we
                * retrigger the parent, otherwise we
                * do nothing.
                */
               if (!desc->parent_irq)
                   return;
               irq = desc->parent_irq;
           }
           /* Set it pending and activate the softirq: */
           set_bit(irq, irqs_resend);
           tasklet_schedule(&resend_tasklet);
#endif
       }
   }
}