hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
 * SPDX-License-Identifier: GPL-2.0
 */
 
#include <linux/interrupt.h>
#include <linux/irq_pipeline.h>
#include <linux/tick.h>
#include <cobalt/kernel/sched.h>
#include <cobalt/kernel/lock.h>
#include <cobalt/kernel/intr.h>
 
void xnintr_host_tick(struct xnsched *sched) /* hard irqs off */
{
   sched->lflags &= ~XNHTICK;
   tick_notify_proxy();
}
 
/*
 * Low-level core clock irq handler. This one forwards ticks from the
 * Xenomai platform timer to nkclock exclusively.
 */
void xnintr_core_clock_handler(void)
{
   struct xnsched *sched;
 
   xnlock_get(&nklock);
   xnclock_tick(&nkclock);
   xnlock_put(&nklock);
 
   /*
    * If the core clock interrupt preempted a real-time thread,
    * any transition to the root thread has already triggered a
    * host tick propagation from xnsched_run(), so at this point,
    * we only need to propagate the host tick in case the
    * interrupt preempted the root thread.
    */
   sched = xnsched_current();
   if ((sched->lflags & XNHTICK) &&
       xnthread_test_state(sched->curr, XNROOT))
       xnintr_host_tick(sched);
}
 
static irqreturn_t xnintr_irq_handler(int irq, void *dev_id)
{
   struct xnintr *intr = dev_id;
   int ret;
 
   ret = intr->isr(intr);
   XENO_WARN_ON_ONCE(USER, (ret & XN_IRQ_STATMASK) == 0);
 
   if (ret & XN_IRQ_DISABLE)
       disable_irq(irq);
   else if (ret & XN_IRQ_PROPAGATE)
       irq_post_inband(irq);
 
   return ret & XN_IRQ_NONE ? IRQ_NONE : IRQ_HANDLED;
}
 
int xnintr_init(struct xnintr *intr, const char *name,
       unsigned int irq, xnisr_t isr, xniack_t iack,
       int flags)
{
   secondary_mode_only();
 
   intr->irq = irq;
   intr->isr = isr;
   intr->iack = NULL;    /* unused */
   intr->cookie = NULL;
   intr->name = name ? : "<unknown>";
   intr->flags = flags;
   intr->status = 0;
   intr->unhandled = 0;    /* unused */
   raw_spin_lock_init(&intr->lock); /* unused */
 
   return 0;
}
EXPORT_SYMBOL_GPL(xnintr_init);
 
void xnintr_destroy(struct xnintr *intr)
{
   secondary_mode_only();
   xnintr_detach(intr);
}
EXPORT_SYMBOL_GPL(xnintr_destroy);
 
int xnintr_attach(struct xnintr *intr, void *cookie, const cpumask_t *cpumask)
{
   cpumask_t tmp_mask, *effective_mask;
   int ret;
 
   secondary_mode_only();
 
   intr->cookie = cookie;
 
   if (!cpumask) {
       effective_mask = &xnsched_realtime_cpus;
   } else {
       effective_mask = &tmp_mask;
       cpumask_and(effective_mask, &xnsched_realtime_cpus, cpumask);
       if (cpumask_empty(effective_mask))
           return -EINVAL;
   }
#ifdef CONFIG_SMP
   ret = irq_set_affinity_hint(intr->irq, effective_mask);
   if (ret)
       return ret;
#endif
 
   return request_irq(intr->irq, xnintr_irq_handler, IRQF_OOB,
           intr->name, intr);
}
EXPORT_SYMBOL_GPL(xnintr_attach);
 
void xnintr_detach(struct xnintr *intr)
{
   secondary_mode_only();
#ifdef CONFIG_SMP
   irq_set_affinity_hint(intr->irq, NULL);
#endif
   free_irq(intr->irq, intr);
}
EXPORT_SYMBOL_GPL(xnintr_detach);
 
void xnintr_enable(struct xnintr *intr)
{
}
EXPORT_SYMBOL_GPL(xnintr_enable);
 
void xnintr_disable(struct xnintr *intr)
{
}
EXPORT_SYMBOL_GPL(xnintr_disable);
 
int xnintr_affinity(struct xnintr *intr, const cpumask_t *cpumask)
{
   cpumask_t effective_mask;
 
   secondary_mode_only();
 
   cpumask_and(&effective_mask, &xnsched_realtime_cpus, cpumask);
   if (cpumask_empty(&effective_mask))
       return -EINVAL;
 
   return irq_set_affinity_hint(intr->irq, &effective_mask);
}
EXPORT_SYMBOL_GPL(xnintr_affinity);