xref: /freebsd/sys/dev/acpica/acpi_ged.c (revision ba23f762ece54a86f64b8ef62bbfc9c73c98762c)
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 __FBSDID("$FreeBSD$");
28a9880bfeSTakanori Watanabe 
29a9880bfeSTakanori Watanabe #include "opt_acpi.h"
30a9880bfeSTakanori Watanabe 
31a9880bfeSTakanori Watanabe #include <sys/param.h>
32a9880bfeSTakanori Watanabe #include <sys/bus.h>
33a9880bfeSTakanori Watanabe #include <sys/kernel.h>
34a9880bfeSTakanori Watanabe #include <sys/malloc.h>
35a9880bfeSTakanori Watanabe #include <sys/module.h>
36a9880bfeSTakanori Watanabe #include <sys/rman.h>
37a9880bfeSTakanori Watanabe 
38a9880bfeSTakanori Watanabe #include <contrib/dev/acpica/include/acpi.h>
39a9880bfeSTakanori Watanabe #include <contrib/dev/acpica/include/accommon.h>
40a9880bfeSTakanori Watanabe #include <dev/acpica/acpivar.h>
41a9880bfeSTakanori Watanabe 
42a9880bfeSTakanori Watanabe /* Hooks for the ACPI CA debugging infrastructure */
43*ba23f762SGleb Smirnoff #define _COMPONENT ACPI_BUS
44a9880bfeSTakanori Watanabe ACPI_MODULE_NAME("GED")
45a9880bfeSTakanori Watanabe 
46a9880bfeSTakanori Watanabe static MALLOC_DEFINE(M_ACPIGED, "acpiged", "ACPI Generic event data");
47a9880bfeSTakanori Watanabe 
48a9880bfeSTakanori Watanabe struct acpi_ged_event {
49a9880bfeSTakanori Watanabe 	device_t dev;
50a9880bfeSTakanori Watanabe 	struct resource *r;
51a9880bfeSTakanori Watanabe 	int rid;
52a9880bfeSTakanori Watanabe 	void *cookie;
53a9880bfeSTakanori Watanabe 	ACPI_HANDLE ah;
54a9880bfeSTakanori Watanabe 	ACPI_OBJECT_LIST args;
55a9880bfeSTakanori Watanabe 	ACPI_OBJECT arg1;
56a9880bfeSTakanori Watanabe };
57a9880bfeSTakanori Watanabe 
58a9880bfeSTakanori Watanabe struct acpi_ged_softc {
59a9880bfeSTakanori Watanabe 	int numevts;
60a9880bfeSTakanori Watanabe 	struct acpi_ged_event *evts;
61a9880bfeSTakanori Watanabe };
62a9880bfeSTakanori Watanabe 
63a9880bfeSTakanori Watanabe static int acpi_ged_probe(device_t dev);
64a9880bfeSTakanori Watanabe static int acpi_ged_attach(device_t dev);
65a9880bfeSTakanori Watanabe static int acpi_ged_detach(device_t dev);
66a9880bfeSTakanori Watanabe 
67a9880bfeSTakanori Watanabe static char *ged_ids[] = { "ACPI0013", NULL };
68a9880bfeSTakanori Watanabe 
69a9880bfeSTakanori Watanabe static device_method_t acpi_ged_methods[] = {
70a9880bfeSTakanori Watanabe 	/* Device interface */
71a9880bfeSTakanori Watanabe 	DEVMETHOD(device_probe, acpi_ged_probe),
72a9880bfeSTakanori Watanabe 	DEVMETHOD(device_attach, acpi_ged_attach),
73a9880bfeSTakanori Watanabe 	DEVMETHOD(device_detach, acpi_ged_detach),
74a9880bfeSTakanori Watanabe 	DEVMETHOD_END
75a9880bfeSTakanori Watanabe };
76a9880bfeSTakanori Watanabe 
77a9880bfeSTakanori Watanabe static driver_t acpi_ged_driver = {
78a9880bfeSTakanori Watanabe 	"acpi_ged",
79a9880bfeSTakanori Watanabe 	acpi_ged_methods,
80a9880bfeSTakanori Watanabe 	sizeof(struct acpi_ged_softc),
81a9880bfeSTakanori Watanabe };
82a9880bfeSTakanori Watanabe 
83a9880bfeSTakanori Watanabe DRIVER_MODULE(acpi_ged, acpi, acpi_ged_driver, 0, 0);
84a9880bfeSTakanori Watanabe MODULE_DEPEND(acpi_ged, acpi, 1, 1, 1);
85a9880bfeSTakanori Watanabe 
86a9880bfeSTakanori Watanabe static void
87a9880bfeSTakanori Watanabe acpi_ged_evt(void *arg)
88a9880bfeSTakanori Watanabe {
89a9880bfeSTakanori Watanabe 	struct acpi_ged_event *evt = arg;
90a9880bfeSTakanori Watanabe 
91a9880bfeSTakanori Watanabe 	AcpiEvaluateObject(evt->ah, NULL, &evt->args, NULL);
92a9880bfeSTakanori Watanabe }
93a9880bfeSTakanori Watanabe 
94a9880bfeSTakanori Watanabe static void
95a9880bfeSTakanori Watanabe acpi_ged_intr(void *arg)
96a9880bfeSTakanori Watanabe {
97a9880bfeSTakanori Watanabe 	AcpiOsExecute(OSL_GPE_HANDLER, acpi_ged_evt, arg);
98a9880bfeSTakanori Watanabe }
99a9880bfeSTakanori Watanabe static int
100a9880bfeSTakanori Watanabe acpi_ged_probe(device_t dev)
101a9880bfeSTakanori Watanabe {
102a9880bfeSTakanori Watanabe 	int rv;
103a9880bfeSTakanori Watanabe 
104a9880bfeSTakanori Watanabe 	if (acpi_disabled("ged"))
105a9880bfeSTakanori Watanabe 		return (ENXIO);
106a9880bfeSTakanori Watanabe 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ged_ids, NULL);
107a9880bfeSTakanori Watanabe 	if (rv > 0)
108a9880bfeSTakanori Watanabe 		return (ENXIO);
109a9880bfeSTakanori Watanabe 
110a9880bfeSTakanori Watanabe 	device_set_desc(dev, "Generic Event Device");
111a9880bfeSTakanori Watanabe 	return (rv);
112a9880bfeSTakanori Watanabe }
113a9880bfeSTakanori Watanabe 
114a9880bfeSTakanori Watanabe /*this should be in acpi_resource.*/
115a9880bfeSTakanori Watanabe static int
116a9880bfeSTakanori Watanabe acpi_get_trigger(ACPI_RESOURCE *res)
117a9880bfeSTakanori Watanabe {
118a9880bfeSTakanori Watanabe 	int trig;
119a9880bfeSTakanori Watanabe 
120a9880bfeSTakanori Watanabe 	switch (res->Type) {
121a9880bfeSTakanori Watanabe 	case ACPI_RESOURCE_TYPE_IRQ:
122a9880bfeSTakanori Watanabe 		KASSERT(res->Data.Irq.InterruptCount == 1,
123a9880bfeSTakanori Watanabe 			("%s: multiple interrupts", __func__));
124a9880bfeSTakanori Watanabe 		trig = res->Data.Irq.Triggering;
125a9880bfeSTakanori Watanabe 		break;
126a9880bfeSTakanori Watanabe 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
127a9880bfeSTakanori Watanabe 		KASSERT(res->Data.ExtendedIrq.InterruptCount == 1,
128a9880bfeSTakanori Watanabe 			("%s: multiple interrupts", __func__));
129a9880bfeSTakanori Watanabe 		trig = res->Data.ExtendedIrq.Triggering;
130a9880bfeSTakanori Watanabe 		break;
131a9880bfeSTakanori Watanabe 	default:
132a9880bfeSTakanori Watanabe 		panic("%s: bad resource type %u", __func__, res->Type);
133a9880bfeSTakanori Watanabe 	}
134a9880bfeSTakanori Watanabe 
135a9880bfeSTakanori Watanabe 	return (trig == ACPI_EDGE_SENSITIVE)
136a9880bfeSTakanori Watanabe 		? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL;
137a9880bfeSTakanori Watanabe }
138a9880bfeSTakanori Watanabe 
139a9880bfeSTakanori Watanabe static int
140a9880bfeSTakanori Watanabe acpi_ged_attach(device_t dev)
141a9880bfeSTakanori Watanabe {
142a9880bfeSTakanori Watanabe 	struct acpi_ged_softc *sc = device_get_softc(dev);
143a9880bfeSTakanori Watanabe 	struct resource_list *rl;
144a9880bfeSTakanori Watanabe 	struct resource_list_entry *rle;
145a9880bfeSTakanori Watanabe 	ACPI_RESOURCE ares;
146a9880bfeSTakanori Watanabe 	ACPI_HANDLE evt_method;
147a9880bfeSTakanori Watanabe 	int i;
148a9880bfeSTakanori Watanabe 	int rawirq, trig;
149a9880bfeSTakanori Watanabe 	char name[] = "_Xnn";
150a9880bfeSTakanori Watanabe 
151a9880bfeSTakanori Watanabe 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
152a9880bfeSTakanori Watanabe 
153a9880bfeSTakanori Watanabe 	if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(dev), "_EVT",
154a9880bfeSTakanori Watanabe 				       &evt_method))) {
155a9880bfeSTakanori Watanabe 		device_printf(dev, "_EVT not found\n");
156a9880bfeSTakanori Watanabe 		evt_method = NULL;
157a9880bfeSTakanori Watanabe 	}
158a9880bfeSTakanori Watanabe 
159a9880bfeSTakanori Watanabe 	rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
160a9880bfeSTakanori Watanabe 	STAILQ_FOREACH(rle, rl, link) {
161a9880bfeSTakanori Watanabe 		if (rle->type == SYS_RES_IRQ) {
162a9880bfeSTakanori Watanabe 			sc->numevts++;
163a9880bfeSTakanori Watanabe 		}
164a9880bfeSTakanori Watanabe 	}
165a9880bfeSTakanori Watanabe 	sc->evts = mallocarray(sc->numevts, sizeof(*sc->evts), M_ACPIGED,
166a9880bfeSTakanori Watanabe 	    M_WAITOK | M_ZERO);
167a9880bfeSTakanori Watanabe 	for (i = 0; i < sc->numevts; i++) {
168a9880bfeSTakanori Watanabe 		sc->evts[i].dev = dev;
169a9880bfeSTakanori Watanabe 		sc->evts[i].rid = i;
170a9880bfeSTakanori Watanabe 		sc->evts[i].r = bus_alloc_resource_any(dev, SYS_RES_IRQ,
171a9880bfeSTakanori Watanabe 		    &sc->evts[i].rid,  RF_ACTIVE | RF_SHAREABLE);
172a9880bfeSTakanori Watanabe 		if (sc->evts[i].r == NULL) {
173a9880bfeSTakanori Watanabe 			device_printf(dev, "Cannot alloc %dth irq\n", i);
174a9880bfeSTakanori Watanabe 			continue;
175a9880bfeSTakanori Watanabe 		}
176a9880bfeSTakanori Watanabe #ifdef INTRNG
177a9880bfeSTakanori Watanabe 		{
178a9880bfeSTakanori Watanabe 			struct intr_map_data_acpi *ima;
179a9880bfeSTakanori Watanabe 			ima = rman_get_virtual(sc->evts[i].r);
180a9880bfeSTakanori Watanabe 			if (ima == NULL) {
181a9880bfeSTakanori Watanabe 				device_printf(dev, "map not found"
182a9880bfeSTakanori Watanabe 					      " non-intrng?\n");
183a9880bfeSTakanori Watanabe 				rawirq = rman_get_start(sc->evts[i].r);
184a9880bfeSTakanori Watanabe 				trig = INTR_TRIGGER_LEVEL;
185a9880bfeSTakanori Watanabe 				if (ACPI_SUCCESS(acpi_lookup_irq_resource
186a9880bfeSTakanori Watanabe 					(dev, sc->evts[i].rid,
187a9880bfeSTakanori Watanabe 					 sc->evts[i].r, &ares))) {
188a9880bfeSTakanori Watanabe 					trig = acpi_get_trigger(&ares);
189a9880bfeSTakanori Watanabe 				}
190a9880bfeSTakanori Watanabe 			} else if (ima->hdr.type == INTR_MAP_DATA_ACPI) {
191a9880bfeSTakanori Watanabe 				device_printf(dev, "Raw IRQ %d\n", ima->irq);
192a9880bfeSTakanori Watanabe 				rawirq = ima->irq;
193a9880bfeSTakanori Watanabe 				trig = ima->trig;
194a9880bfeSTakanori Watanabe 			} else {
195a9880bfeSTakanori Watanabe 				device_printf(dev, "Not supported intr"
196a9880bfeSTakanori Watanabe 					      " type%d\n", ima->hdr.type);
197a9880bfeSTakanori Watanabe 				continue;
198a9880bfeSTakanori Watanabe 			}
199a9880bfeSTakanori Watanabe 		}
200a9880bfeSTakanori Watanabe #else
2019cf5db63STakanori Watanabe 		rawirq = rman_get_start(sc->evts[i].r);
202a9880bfeSTakanori Watanabe 		trig = INTR_TRIGGER_LEVEL;
203a9880bfeSTakanori Watanabe 		if (ACPI_SUCCESS(acpi_lookup_irq_resource
204a9880bfeSTakanori Watanabe 				(dev, sc->evts[i].rid,
205a9880bfeSTakanori Watanabe 				 sc->evts[i].r, &ares))) {
206a9880bfeSTakanori Watanabe 			trig = acpi_get_trigger(&ares);
207a9880bfeSTakanori Watanabe 		}
208a9880bfeSTakanori Watanabe #endif
209a9880bfeSTakanori Watanabe 		if (rawirq < 0x100) {
210a9880bfeSTakanori Watanabe 			sprintf(name, "_%c%02X",
211a9880bfeSTakanori Watanabe 				((trig == INTR_TRIGGER_EDGE) ? 'E' : 'L'),
212a9880bfeSTakanori Watanabe 				rawirq);
213a9880bfeSTakanori Watanabe 			if (ACPI_SUCCESS(AcpiGetHandle
214a9880bfeSTakanori Watanabe 					(acpi_get_handle(dev),
215a9880bfeSTakanori Watanabe 					 name, &sc->evts[i].ah))) {
216a9880bfeSTakanori Watanabe 				sc->evts[i].args.Count = 0; /* ensure */
217a9880bfeSTakanori Watanabe 			} else {
218a9880bfeSTakanori Watanabe 				sc->evts[i].ah = NULL; /* ensure */
219a9880bfeSTakanori Watanabe 			}
220a9880bfeSTakanori Watanabe 		}
221a9880bfeSTakanori Watanabe 
222a9880bfeSTakanori Watanabe 		if (sc->evts[i].ah == NULL) {
223a9880bfeSTakanori Watanabe 			if (evt_method != NULL) {
224a9880bfeSTakanori Watanabe 				sc->evts[i].ah = evt_method;
225a9880bfeSTakanori Watanabe 				sc->evts[i].arg1.Type = ACPI_TYPE_INTEGER;
226a9880bfeSTakanori Watanabe 				sc->evts[i].arg1.Integer.Value = rawirq;
227a9880bfeSTakanori Watanabe 				sc->evts[i].args.Count = 1;
228a9880bfeSTakanori Watanabe 				sc->evts[i].args.Pointer = &sc->evts[i].arg1;
229a9880bfeSTakanori Watanabe 			} else{
230a9880bfeSTakanori Watanabe 				device_printf
231a9880bfeSTakanori Watanabe 					(dev,
232a9880bfeSTakanori Watanabe 					 "Cannot find handler method %d\n",
233a9880bfeSTakanori Watanabe 					 i);
234a9880bfeSTakanori Watanabe 				continue;
235a9880bfeSTakanori Watanabe 			}
236a9880bfeSTakanori Watanabe 		}
237a9880bfeSTakanori Watanabe 
238a9880bfeSTakanori Watanabe 		if (bus_setup_intr(dev, sc->evts[i].r,
239a9880bfeSTakanori Watanabe 			INTR_TYPE_MISC | INTR_MPSAFE, NULL, acpi_ged_intr,
240a9880bfeSTakanori Watanabe 			&sc->evts[i], &sc->evts[i].cookie) != 0) {
241a9880bfeSTakanori Watanabe 			device_printf(dev, "Failed to setup intr %d\n", i);
242a9880bfeSTakanori Watanabe 		}
243a9880bfeSTakanori Watanabe 	}
244a9880bfeSTakanori Watanabe 
245a9880bfeSTakanori Watanabe 	return_VALUE(0);
246a9880bfeSTakanori Watanabe }
247a9880bfeSTakanori Watanabe 
248a9880bfeSTakanori Watanabe static int
249a9880bfeSTakanori Watanabe acpi_ged_detach(device_t dev)
250a9880bfeSTakanori Watanabe {
251a9880bfeSTakanori Watanabe 	struct acpi_ged_softc *sc = device_get_softc(dev);
252a9880bfeSTakanori Watanabe 	int i;
253a9880bfeSTakanori Watanabe 
254a9880bfeSTakanori Watanabe 	for (i = 0; i < sc->numevts; i++) {
255a9880bfeSTakanori Watanabe 		if (sc->evts[i].cookie) {
256a9880bfeSTakanori Watanabe 			bus_teardown_intr(dev, sc->evts[i].r,
257a9880bfeSTakanori Watanabe 			    sc->evts[i].cookie);
258a9880bfeSTakanori Watanabe 		}
259a9880bfeSTakanori Watanabe 		if (sc->evts[i].r) {
260a9880bfeSTakanori Watanabe 			bus_release_resource(dev, SYS_RES_IRQ, sc->evts[i].rid,
261a9880bfeSTakanori Watanabe 			    sc->evts[i].r);
262a9880bfeSTakanori Watanabe 		}
263a9880bfeSTakanori Watanabe 	}
264a9880bfeSTakanori Watanabe 	free(sc->evts, M_ACPIGED);
265a9880bfeSTakanori Watanabe 
266a9880bfeSTakanori Watanabe 	return (0);
267a9880bfeSTakanori Watanabe }
268