Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpica/Osd/OsdInterrupt.c
39537 views
1
/*-
2
* Copyright (c) 2000 Michael Smith
3
* Copyright (c) 2000 BSDi
4
* Copyright (c) 2011 Jung-uk Kim <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
/*
30
* 6.5 : Interrupt handling
31
*/
32
33
#include <sys/param.h>
34
#include <sys/kernel.h>
35
#include <sys/bus.h>
36
#include <sys/lock.h>
37
#include <sys/malloc.h>
38
#include <sys/mutex.h>
39
#include <machine/bus.h>
40
#include <machine/resource.h>
41
#include <sys/rman.h>
42
43
#include <contrib/dev/acpica/include/acpi.h>
44
#include <contrib/dev/acpica/include/accommon.h>
45
46
#include <dev/acpica/acpivar.h>
47
48
#define _COMPONENT ACPI_OS_SERVICES
49
ACPI_MODULE_NAME("INTERRUPT")
50
51
static MALLOC_DEFINE(M_ACPIINTR, "acpiintr", "ACPI interrupt");
52
53
struct acpi_intr {
54
SLIST_ENTRY(acpi_intr) ai_link;
55
struct resource *ai_irq;
56
int ai_rid;
57
void *ai_handle;
58
int ai_number;
59
ACPI_OSD_HANDLER ai_handler;
60
void *ai_context;
61
};
62
static SLIST_HEAD(, acpi_intr) acpi_intr_list =
63
SLIST_HEAD_INITIALIZER(acpi_intr_list);
64
static struct mtx acpi_intr_lock;
65
66
static UINT32 InterruptOverride;
67
68
static void
69
acpi_intr_init(struct mtx *lock)
70
{
71
72
mtx_init(lock, "ACPI interrupt lock", NULL, MTX_DEF);
73
}
74
75
SYSINIT(acpi_intr, SI_SUB_DRIVERS, SI_ORDER_FIRST, acpi_intr_init,
76
&acpi_intr_lock);
77
78
static int
79
acpi_intr_handler(void *arg)
80
{
81
struct acpi_intr *ai;
82
83
ai = arg;
84
KASSERT(ai != NULL && ai->ai_handler != NULL,
85
("invalid ACPI interrupt handler"));
86
if (ai->ai_handler(ai->ai_context) == ACPI_INTERRUPT_HANDLED)
87
return (FILTER_HANDLED);
88
return (FILTER_STRAY);
89
}
90
91
static void
92
acpi_intr_destroy(device_t dev, struct acpi_intr *ai)
93
{
94
95
if (ai->ai_handle != NULL)
96
bus_teardown_intr(dev, ai->ai_irq, ai->ai_handle);
97
if (ai->ai_irq != NULL)
98
bus_release_resource(dev, SYS_RES_IRQ, ai->ai_rid, ai->ai_irq);
99
bus_delete_resource(dev, SYS_RES_IRQ, ai->ai_rid);
100
free(ai, M_ACPIINTR);
101
}
102
103
ACPI_STATUS
104
AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
105
ACPI_OSD_HANDLER ServiceRoutine, void *Context)
106
{
107
struct acpi_softc *sc;
108
struct acpi_intr *ai, *ap;
109
110
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
111
112
sc = devclass_get_softc(devclass_find("acpi"), 0);
113
KASSERT(sc != NULL && sc->acpi_dev != NULL,
114
("can't find ACPI device to register interrupt"));
115
116
if (InterruptNumber > 255 || ServiceRoutine == NULL)
117
return_ACPI_STATUS (AE_BAD_PARAMETER);
118
119
ai = malloc(sizeof(*ai), M_ACPIINTR, M_WAITOK | M_ZERO);
120
mtx_lock(&acpi_intr_lock);
121
SLIST_FOREACH(ap, &acpi_intr_list, ai_link) {
122
if (InterruptNumber == ap->ai_number ||
123
(InterruptNumber == InterruptOverride &&
124
InterruptNumber != AcpiGbl_FADT.SciInterrupt)) {
125
mtx_unlock(&acpi_intr_lock);
126
free(ai, M_ACPIINTR);
127
return_ACPI_STATUS (AE_ALREADY_EXISTS);
128
}
129
if (ai->ai_rid <= ap->ai_rid)
130
ai->ai_rid = ap->ai_rid + 1;
131
}
132
ai->ai_number = InterruptNumber;
133
ai->ai_handler = ServiceRoutine;
134
ai->ai_context = Context;
135
SLIST_INSERT_HEAD(&acpi_intr_list, ai, ai_link);
136
mtx_unlock(&acpi_intr_lock);
137
138
/*
139
* If the MADT contained an interrupt override directive for the SCI,
140
* we use that value instead of the one from the FADT.
141
*/
142
if (InterruptOverride != 0 &&
143
InterruptNumber == AcpiGbl_FADT.SciInterrupt) {
144
device_printf(sc->acpi_dev,
145
"Overriding SCI from IRQ %u to IRQ %u\n",
146
InterruptNumber, InterruptOverride);
147
InterruptNumber = InterruptOverride;
148
}
149
150
/* Set up the interrupt resource. */
151
bus_set_resource(sc->acpi_dev, SYS_RES_IRQ, ai->ai_rid,
152
InterruptNumber, 1);
153
ai->ai_irq = bus_alloc_resource_any(sc->acpi_dev, SYS_RES_IRQ,
154
&ai->ai_rid, RF_SHAREABLE | RF_ACTIVE);
155
if (ai->ai_irq == NULL) {
156
device_printf(sc->acpi_dev, "could not allocate interrupt\n");
157
goto error;
158
}
159
if (bus_setup_intr(sc->acpi_dev, ai->ai_irq,
160
INTR_TYPE_MISC | INTR_MPSAFE, acpi_intr_handler, NULL, ai,
161
&ai->ai_handle) != 0) {
162
device_printf(sc->acpi_dev, "could not set up interrupt\n");
163
goto error;
164
}
165
return_ACPI_STATUS (AE_OK);
166
167
error:
168
mtx_lock(&acpi_intr_lock);
169
SLIST_REMOVE(&acpi_intr_list, ai, acpi_intr, ai_link);
170
mtx_unlock(&acpi_intr_lock);
171
acpi_intr_destroy(sc->acpi_dev, ai);
172
return_ACPI_STATUS (AE_ALREADY_EXISTS);
173
}
174
175
ACPI_STATUS
176
AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber,
177
ACPI_OSD_HANDLER ServiceRoutine)
178
{
179
struct acpi_softc *sc;
180
struct acpi_intr *ai;
181
182
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
183
184
sc = devclass_get_softc(devclass_find("acpi"), 0);
185
KASSERT(sc != NULL && sc->acpi_dev != NULL,
186
("can't find ACPI device to deregister interrupt"));
187
188
if (InterruptNumber > 255 || ServiceRoutine == NULL)
189
return_ACPI_STATUS (AE_BAD_PARAMETER);
190
mtx_lock(&acpi_intr_lock);
191
SLIST_FOREACH(ai, &acpi_intr_list, ai_link)
192
if (InterruptNumber == ai->ai_number) {
193
if (ServiceRoutine != ai->ai_handler) {
194
mtx_unlock(&acpi_intr_lock);
195
return_ACPI_STATUS (AE_BAD_PARAMETER);
196
}
197
SLIST_REMOVE(&acpi_intr_list, ai, acpi_intr, ai_link);
198
break;
199
}
200
mtx_unlock(&acpi_intr_lock);
201
if (ai == NULL)
202
return_ACPI_STATUS (AE_NOT_EXIST);
203
acpi_intr_destroy(sc->acpi_dev, ai);
204
return_ACPI_STATUS (AE_OK);
205
}
206
207
ACPI_STATUS
208
acpi_OverrideInterruptLevel(UINT32 InterruptNumber)
209
{
210
211
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
212
213
if (InterruptOverride != 0)
214
return_ACPI_STATUS (AE_ALREADY_EXISTS);
215
InterruptOverride = InterruptNumber;
216
return_ACPI_STATUS (AE_OK);
217
}
218
219