xref: /freebsd/sys/dev/acpica/acpi_ged.c (revision dbedcc169f70c924a680e02bc86d7419682a70ac)
1a9880bfeSTakanori Watanabe /*-
2a9880bfeSTakanori Watanabe  * Copyright (c) 2022 Takanori Watanabe
3a9880bfeSTakanori Watanabe  *
4a9880bfeSTakanori Watanabe  * Redistribution and use in source and binary forms, with or without
5a9880bfeSTakanori Watanabe  * modification, are permitted provided that the following conditions
6a9880bfeSTakanori Watanabe  * are met:
7a9880bfeSTakanori Watanabe  * 1. Redistributions of source code must retain the above copyright
8a9880bfeSTakanori Watanabe  *    notice, this list of conditions and the following disclaimer.
9a9880bfeSTakanori Watanabe  * 2. Redistributions in binary form must reproduce the above copyright
10a9880bfeSTakanori Watanabe  *    notice, this list of conditions and the following disclaimer in the
11a9880bfeSTakanori Watanabe  *    documentation and/or other materials provided with the distribution.
12a9880bfeSTakanori Watanabe  *
13a9880bfeSTakanori Watanabe  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14a9880bfeSTakanori Watanabe  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15a9880bfeSTakanori Watanabe  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16a9880bfeSTakanori Watanabe  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17a9880bfeSTakanori Watanabe  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18a9880bfeSTakanori Watanabe  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19a9880bfeSTakanori Watanabe  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20a9880bfeSTakanori Watanabe  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21a9880bfeSTakanori Watanabe  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22a9880bfeSTakanori Watanabe  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23a9880bfeSTakanori Watanabe  * SUCH DAMAGE.
24a9880bfeSTakanori Watanabe  */
25a9880bfeSTakanori Watanabe 
26a9880bfeSTakanori Watanabe #include <sys/cdefs.h>
27a9880bfeSTakanori Watanabe #include "opt_acpi.h"
28a9880bfeSTakanori Watanabe 
29a9880bfeSTakanori Watanabe #include <sys/param.h>
30a9880bfeSTakanori Watanabe #include <sys/bus.h>
31a9880bfeSTakanori Watanabe #include <sys/kernel.h>
32a9880bfeSTakanori Watanabe #include <sys/malloc.h>
33a9880bfeSTakanori Watanabe #include <sys/module.h>
34a9880bfeSTakanori Watanabe #include <sys/rman.h>
35a9880bfeSTakanori Watanabe 
36a9880bfeSTakanori Watanabe #include <contrib/dev/acpica/include/acpi.h>
37a9880bfeSTakanori Watanabe #include <contrib/dev/acpica/include/accommon.h>
38a9880bfeSTakanori Watanabe #include <dev/acpica/acpivar.h>
39a9880bfeSTakanori Watanabe 
40a9880bfeSTakanori Watanabe /* Hooks for the ACPI CA debugging infrastructure */
41ba23f762SGleb Smirnoff #define _COMPONENT ACPI_BUS
42a9880bfeSTakanori Watanabe ACPI_MODULE_NAME("GED")
43a9880bfeSTakanori Watanabe 
44a9880bfeSTakanori Watanabe static MALLOC_DEFINE(M_ACPIGED, "acpiged", "ACPI Generic event data");
45a9880bfeSTakanori Watanabe 
46a9880bfeSTakanori Watanabe struct acpi_ged_event {
47a9880bfeSTakanori Watanabe 	device_t dev;
48a9880bfeSTakanori Watanabe 	struct resource *r;
49a9880bfeSTakanori Watanabe 	int rid;
50a9880bfeSTakanori Watanabe 	void *cookie;
51a9880bfeSTakanori Watanabe 	ACPI_HANDLE ah;
52a9880bfeSTakanori Watanabe 	ACPI_OBJECT_LIST args;
53a9880bfeSTakanori Watanabe 	ACPI_OBJECT arg1;
54a9880bfeSTakanori Watanabe };
55a9880bfeSTakanori Watanabe 
56a9880bfeSTakanori Watanabe struct acpi_ged_softc {
57a9880bfeSTakanori Watanabe 	int numevts;
58a9880bfeSTakanori Watanabe 	struct acpi_ged_event *evts;
59a9880bfeSTakanori Watanabe };
60a9880bfeSTakanori Watanabe 
61a9880bfeSTakanori Watanabe static int acpi_ged_probe(device_t dev);
62a9880bfeSTakanori Watanabe static int acpi_ged_attach(device_t dev);
63a9880bfeSTakanori Watanabe static int acpi_ged_detach(device_t dev);
64a9880bfeSTakanori Watanabe 
65a9880bfeSTakanori Watanabe static char *ged_ids[] = { "ACPI0013", NULL };
66a9880bfeSTakanori Watanabe 
67a9880bfeSTakanori Watanabe static device_method_t acpi_ged_methods[] = {
68a9880bfeSTakanori Watanabe 	/* Device interface */
69a9880bfeSTakanori Watanabe 	DEVMETHOD(device_probe, acpi_ged_probe),
70a9880bfeSTakanori Watanabe 	DEVMETHOD(device_attach, acpi_ged_attach),
71a9880bfeSTakanori Watanabe 	DEVMETHOD(device_detach, acpi_ged_detach),
72a9880bfeSTakanori Watanabe 	DEVMETHOD_END
73a9880bfeSTakanori Watanabe };
74a9880bfeSTakanori Watanabe 
75a9880bfeSTakanori Watanabe static driver_t acpi_ged_driver = {
76a9880bfeSTakanori Watanabe 	"acpi_ged",
77a9880bfeSTakanori Watanabe 	acpi_ged_methods,
78a9880bfeSTakanori Watanabe 	sizeof(struct acpi_ged_softc),
79a9880bfeSTakanori Watanabe };
80a9880bfeSTakanori Watanabe 
81a9880bfeSTakanori Watanabe DRIVER_MODULE(acpi_ged, acpi, acpi_ged_driver, 0, 0);
82a9880bfeSTakanori Watanabe MODULE_DEPEND(acpi_ged, acpi, 1, 1, 1);
83a9880bfeSTakanori Watanabe 
84be91b479SAndrew Gallatin static int acpi_ged_defer;
85be91b479SAndrew Gallatin SYSCTL_INT(_debug_acpi, OID_AUTO, ged_defer, CTLFLAG_RWTUN,
86be91b479SAndrew Gallatin     &acpi_ged_defer, 0,
87be91b479SAndrew Gallatin     "Handle ACPI GED via a task, rather than in the ISR");
88be91b479SAndrew Gallatin 
89a9880bfeSTakanori Watanabe static void
acpi_ged_evt(void * arg)90a9880bfeSTakanori Watanabe acpi_ged_evt(void *arg)
91a9880bfeSTakanori Watanabe {
92a9880bfeSTakanori Watanabe 	struct acpi_ged_event *evt = arg;
93a9880bfeSTakanori Watanabe 
94a9880bfeSTakanori Watanabe 	AcpiEvaluateObject(evt->ah, NULL, &evt->args, NULL);
95a9880bfeSTakanori Watanabe }
96a9880bfeSTakanori Watanabe 
97a9880bfeSTakanori Watanabe static void
acpi_ged_intr(void * arg)98a9880bfeSTakanori Watanabe acpi_ged_intr(void *arg)
99a9880bfeSTakanori Watanabe {
100be91b479SAndrew Gallatin 	struct acpi_ged_event *evt = arg;
101be91b479SAndrew Gallatin 
102be91b479SAndrew Gallatin 	if (acpi_ged_defer)
103a9880bfeSTakanori Watanabe 		AcpiOsExecute(OSL_GPE_HANDLER, acpi_ged_evt, arg);
104be91b479SAndrew Gallatin 	else
105be91b479SAndrew Gallatin 		AcpiEvaluateObject(evt->ah, NULL, &evt->args, NULL);
106a9880bfeSTakanori Watanabe }
107a9880bfeSTakanori Watanabe static int
acpi_ged_probe(device_t dev)108a9880bfeSTakanori Watanabe acpi_ged_probe(device_t dev)
109a9880bfeSTakanori Watanabe {
110a9880bfeSTakanori Watanabe 	int rv;
111a9880bfeSTakanori Watanabe 
112a9880bfeSTakanori Watanabe 	if (acpi_disabled("ged"))
113a9880bfeSTakanori Watanabe 		return (ENXIO);
114a9880bfeSTakanori Watanabe 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ged_ids, NULL);
115a9880bfeSTakanori Watanabe 	if (rv > 0)
116a9880bfeSTakanori Watanabe 		return (ENXIO);
117a9880bfeSTakanori Watanabe 
118a9880bfeSTakanori Watanabe 	device_set_desc(dev, "Generic Event Device");
119a9880bfeSTakanori Watanabe 	return (rv);
120a9880bfeSTakanori Watanabe }
121a9880bfeSTakanori Watanabe 
122a9880bfeSTakanori Watanabe /*this should be in acpi_resource.*/
123a9880bfeSTakanori Watanabe static int
acpi_get_trigger(ACPI_RESOURCE * res)124a9880bfeSTakanori Watanabe acpi_get_trigger(ACPI_RESOURCE *res)
125a9880bfeSTakanori Watanabe {
126a9880bfeSTakanori Watanabe 	int trig;
127a9880bfeSTakanori Watanabe 
128a9880bfeSTakanori Watanabe 	switch (res->Type) {
129a9880bfeSTakanori Watanabe 	case ACPI_RESOURCE_TYPE_IRQ:
130a9880bfeSTakanori Watanabe 		KASSERT(res->Data.Irq.InterruptCount == 1,
131a9880bfeSTakanori Watanabe 			("%s: multiple interrupts", __func__));
132a9880bfeSTakanori Watanabe 		trig = res->Data.Irq.Triggering;
133a9880bfeSTakanori Watanabe 		break;
134a9880bfeSTakanori Watanabe 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
135a9880bfeSTakanori Watanabe 		KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
136a9880bfeSTakanori Watanabe 			("%s: multiple interrupts", __func__));
137a9880bfeSTakanori Watanabe 		trig = res->Data.ExtendedIrq.Triggering;
138a9880bfeSTakanori Watanabe 		break;
139a9880bfeSTakanori Watanabe 	default:
140a9880bfeSTakanori Watanabe 		panic("%s: bad resource type %u", __func__, res->Type);
141a9880bfeSTakanori Watanabe 	}
142a9880bfeSTakanori Watanabe 
143a9880bfeSTakanori Watanabe 	return (trig == ACPI_EDGE_SENSITIVE)
144a9880bfeSTakanori Watanabe 		? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL;
145a9880bfeSTakanori Watanabe }
146a9880bfeSTakanori Watanabe 
147a9880bfeSTakanori Watanabe static int
acpi_ged_attach(device_t dev)148a9880bfeSTakanori Watanabe acpi_ged_attach(device_t dev)
149a9880bfeSTakanori Watanabe {
150a9880bfeSTakanori Watanabe 	struct acpi_ged_softc *sc = device_get_softc(dev);
151a9880bfeSTakanori Watanabe 	struct resource_list *rl;
152a9880bfeSTakanori Watanabe 	struct resource_list_entry *rle;
153a9880bfeSTakanori Watanabe 	ACPI_RESOURCE ares;
154a9880bfeSTakanori Watanabe 	ACPI_HANDLE evt_method;
155a9880bfeSTakanori Watanabe 	int i;
156a9880bfeSTakanori Watanabe 	int rawirq, trig;
157a9880bfeSTakanori Watanabe 	char name[] = "_Xnn";
158a9880bfeSTakanori Watanabe 
159a9880bfeSTakanori Watanabe 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
160a9880bfeSTakanori Watanabe 
161a9880bfeSTakanori Watanabe 	if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(dev), "_EVT",
162a9880bfeSTakanori Watanabe 				       &evt_method))) {
163a9880bfeSTakanori Watanabe 		device_printf(dev, "_EVT not found\n");
164a9880bfeSTakanori Watanabe 		evt_method = NULL;
165a9880bfeSTakanori Watanabe 	}
166a9880bfeSTakanori Watanabe 
167a9880bfeSTakanori Watanabe 	rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
168a9880bfeSTakanori Watanabe 	STAILQ_FOREACH(rle, rl, link) {
169a9880bfeSTakanori Watanabe 		if (rle->type == SYS_RES_IRQ) {
170a9880bfeSTakanori Watanabe 			sc->numevts++;
171a9880bfeSTakanori Watanabe 		}
172a9880bfeSTakanori Watanabe 	}
173a9880bfeSTakanori Watanabe 	sc->evts = mallocarray(sc->numevts, sizeof(*sc->evts), M_ACPIGED,
174a9880bfeSTakanori Watanabe 	    M_WAITOK | M_ZERO);
175a9880bfeSTakanori Watanabe 	for (i = 0; i < sc->numevts; i++) {
176a9880bfeSTakanori Watanabe 		sc->evts[i].dev = dev;
177a9880bfeSTakanori Watanabe 		sc->evts[i].rid = i;
178a9880bfeSTakanori Watanabe 		sc->evts[i].r = bus_alloc_resource_any(dev, SYS_RES_IRQ,
179a9880bfeSTakanori Watanabe 		    &sc->evts[i].rid,  RF_ACTIVE | RF_SHAREABLE);
180a9880bfeSTakanori Watanabe 		if (sc->evts[i].r == NULL) {
181a9880bfeSTakanori Watanabe 			device_printf(dev, "Cannot alloc %dth irq\n", i);
182a9880bfeSTakanori Watanabe 			continue;
183a9880bfeSTakanori Watanabe 		}
184a9880bfeSTakanori Watanabe #ifdef INTRNG
185a9880bfeSTakanori Watanabe 		{
186a9880bfeSTakanori Watanabe 			struct intr_map_data_acpi *ima;
187a9880bfeSTakanori Watanabe 			ima = rman_get_virtual(sc->evts[i].r);
188a9880bfeSTakanori Watanabe 			if (ima == NULL) {
189a9880bfeSTakanori Watanabe 				device_printf(dev, "map not found"
190a9880bfeSTakanori Watanabe 					      " non-intrng?\n");
191a9880bfeSTakanori Watanabe 				rawirq = rman_get_start(sc->evts[i].r);
192a9880bfeSTakanori Watanabe 				trig = INTR_TRIGGER_LEVEL;
193a9880bfeSTakanori Watanabe 				if (ACPI_SUCCESS(acpi_lookup_irq_resource
194a9880bfeSTakanori Watanabe 					(dev, sc->evts[i].rid,
195a9880bfeSTakanori Watanabe 					 sc->evts[i].r, &ares))) {
196a9880bfeSTakanori Watanabe 					trig = acpi_get_trigger(&ares);
197a9880bfeSTakanori Watanabe 				}
198a9880bfeSTakanori Watanabe 			} else if (ima->hdr.type == INTR_MAP_DATA_ACPI) {
199a9880bfeSTakanori Watanabe 				device_printf(dev, "Raw IRQ %d\n", ima->irq);
200a9880bfeSTakanori Watanabe 				rawirq = ima->irq;
201a9880bfeSTakanori Watanabe 				trig = ima->trig;
202a9880bfeSTakanori Watanabe 			} else {
203a9880bfeSTakanori Watanabe 				device_printf(dev, "Not supported intr"
204a9880bfeSTakanori Watanabe 					      " type%d\n", ima->hdr.type);
205a9880bfeSTakanori Watanabe 				continue;
206a9880bfeSTakanori Watanabe 			}
207a9880bfeSTakanori Watanabe 		}
208a9880bfeSTakanori Watanabe #else
2099cf5db63STakanori Watanabe 		rawirq = rman_get_start(sc->evts[i].r);
210a9880bfeSTakanori Watanabe 		trig = INTR_TRIGGER_LEVEL;
211a9880bfeSTakanori Watanabe 		if (ACPI_SUCCESS(acpi_lookup_irq_resource
212a9880bfeSTakanori Watanabe 				(dev, sc->evts[i].rid,
213a9880bfeSTakanori Watanabe 				 sc->evts[i].r, &ares))) {
214a9880bfeSTakanori Watanabe 			trig = acpi_get_trigger(&ares);
215a9880bfeSTakanori Watanabe 		}
216a9880bfeSTakanori Watanabe #endif
217a9880bfeSTakanori Watanabe 		if (rawirq < 0x100) {
218a9880bfeSTakanori Watanabe 			sprintf(name, "_%c%02X",
219a9880bfeSTakanori Watanabe 				((trig == INTR_TRIGGER_EDGE) ? 'E' : 'L'),
220a9880bfeSTakanori Watanabe 				rawirq);
221a9880bfeSTakanori Watanabe 			if (ACPI_SUCCESS(AcpiGetHandle
222a9880bfeSTakanori Watanabe 					(acpi_get_handle(dev),
223a9880bfeSTakanori Watanabe 					 name, &sc->evts[i].ah))) {
224a9880bfeSTakanori Watanabe 				sc->evts[i].args.Count = 0; /* ensure */
225a9880bfeSTakanori Watanabe 			} else {
226a9880bfeSTakanori Watanabe 				sc->evts[i].ah = NULL; /* ensure */
227a9880bfeSTakanori Watanabe 			}
228a9880bfeSTakanori Watanabe 		}
229a9880bfeSTakanori Watanabe 
230a9880bfeSTakanori Watanabe 		if (sc->evts[i].ah == NULL) {
231a9880bfeSTakanori Watanabe 			if (evt_method != NULL) {
232a9880bfeSTakanori Watanabe 				sc->evts[i].ah = evt_method;
233a9880bfeSTakanori Watanabe 				sc->evts[i].arg1.Type = ACPI_TYPE_INTEGER;
234a9880bfeSTakanori Watanabe 				sc->evts[i].arg1.Integer.Value = rawirq;
235a9880bfeSTakanori Watanabe 				sc->evts[i].args.Count = 1;
236a9880bfeSTakanori Watanabe 				sc->evts[i].args.Pointer = &sc->evts[i].arg1;
237a9880bfeSTakanori Watanabe 			} else{
238a9880bfeSTakanori Watanabe 				device_printf
239a9880bfeSTakanori Watanabe 					(dev,
240a9880bfeSTakanori Watanabe 					 "Cannot find handler method %d\n",
241a9880bfeSTakanori Watanabe 					 i);
242a9880bfeSTakanori Watanabe 				continue;
243a9880bfeSTakanori Watanabe 			}
244a9880bfeSTakanori Watanabe 		}
245a9880bfeSTakanori Watanabe 
246a9880bfeSTakanori Watanabe 		if (bus_setup_intr(dev, sc->evts[i].r,
247*dbedcc16SAndrew Turner 			INTR_TYPE_MISC | INTR_MPSAFE | INTR_SLEEPABLE |
248*dbedcc16SAndrew Turner 			INTR_EXCL, NULL,  acpi_ged_intr, &sc->evts[i],
249*dbedcc16SAndrew Turner 			&sc->evts[i].cookie) != 0) {
250a9880bfeSTakanori Watanabe 			device_printf(dev, "Failed to setup intr %d\n", i);
251a9880bfeSTakanori Watanabe 		}
252a9880bfeSTakanori Watanabe 	}
253a9880bfeSTakanori Watanabe 
254a9880bfeSTakanori Watanabe 	return_VALUE(0);
255a9880bfeSTakanori Watanabe }
256a9880bfeSTakanori Watanabe 
257a9880bfeSTakanori Watanabe static int
acpi_ged_detach(device_t dev)258a9880bfeSTakanori Watanabe acpi_ged_detach(device_t dev)
259a9880bfeSTakanori Watanabe {
260a9880bfeSTakanori Watanabe 	struct acpi_ged_softc *sc = device_get_softc(dev);
261a9880bfeSTakanori Watanabe 	int i;
262a9880bfeSTakanori Watanabe 
263a9880bfeSTakanori Watanabe 	for (i = 0; i < sc->numevts; i++) {
264a9880bfeSTakanori Watanabe 		if (sc->evts[i].cookie) {
265a9880bfeSTakanori Watanabe 			bus_teardown_intr(dev, sc->evts[i].r,
266a9880bfeSTakanori Watanabe 			    sc->evts[i].cookie);
267a9880bfeSTakanori Watanabe 		}
268a9880bfeSTakanori Watanabe 		if (sc->evts[i].r) {
269a9880bfeSTakanori Watanabe 			bus_release_resource(dev, SYS_RES_IRQ, sc->evts[i].rid,
270a9880bfeSTakanori Watanabe 			    sc->evts[i].r);
271a9880bfeSTakanori Watanabe 		}
272a9880bfeSTakanori Watanabe 	}
273a9880bfeSTakanori Watanabe 	free(sc->evts, M_ACPIGED);
274a9880bfeSTakanori Watanabe 
275a9880bfeSTakanori Watanabe 	return (0);
276a9880bfeSTakanori Watanabe }
277