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