1*e012216eSyasuoka /* $OpenBSD: ipmi_acpi.c,v 1.7 2025/01/28 02:20:49 yasuoka Exp $ */ 2a74532a1Spatrick /* 3a74532a1Spatrick * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 4a74532a1Spatrick * 5a74532a1Spatrick * Permission to use, copy, modify, and distribute this software for any 6a74532a1Spatrick * purpose with or without fee is hereby granted, provided that the above 7a74532a1Spatrick * copyright notice and this permission notice appear in all copies. 8a74532a1Spatrick * 9a74532a1Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10a74532a1Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11a74532a1Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12a74532a1Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13a74532a1Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14a74532a1Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15a74532a1Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16a74532a1Spatrick */ 17a74532a1Spatrick 18a74532a1Spatrick #include <sys/param.h> 19a74532a1Spatrick #include <sys/signalvar.h> 20a74532a1Spatrick #include <sys/systm.h> 21a74532a1Spatrick #include <sys/device.h> 22a74532a1Spatrick #include <sys/malloc.h> 23a74532a1Spatrick 24a74532a1Spatrick #include <machine/bus.h> 25a74532a1Spatrick #include <machine/apmvar.h> 26a74532a1Spatrick 27a74532a1Spatrick #include <dev/acpi/acpireg.h> 28a74532a1Spatrick #include <dev/acpi/acpivar.h> 29a74532a1Spatrick #include <dev/acpi/acpidev.h> 30a74532a1Spatrick #include <dev/acpi/amltypes.h> 31a74532a1Spatrick #include <dev/acpi/dsdt.h> 32a74532a1Spatrick #undef DEVNAME 33a74532a1Spatrick 34a74532a1Spatrick #include <dev/ipmivar.h> 35a74532a1Spatrick 36a74532a1Spatrick #define DEVNAME(s) ((s)->sc.sc_dev.dv_xname) 37a74532a1Spatrick 38a74532a1Spatrick int ipmi_acpi_match(struct device *, void *, void *); 39a74532a1Spatrick void ipmi_acpi_attach(struct device *, struct device *, void *); 40a74532a1Spatrick int ipmi_acpi_parse_crs(int, union acpi_resource *, void *); 41a74532a1Spatrick 42a74532a1Spatrick struct ipmi_acpi_softc { 43a74532a1Spatrick struct ipmi_softc sc; 44a74532a1Spatrick 45a74532a1Spatrick struct acpi_softc *sc_acpi; 46a74532a1Spatrick struct aml_node *sc_devnode; 47a74532a1Spatrick 48a74532a1Spatrick int sc_ift; 4902af067eSkettenis int sc_srv; 50a74532a1Spatrick 51a74532a1Spatrick bus_size_t sc_iobase; 52a74532a1Spatrick int sc_iospacing; 53a74532a1Spatrick char sc_iotype; 54a74532a1Spatrick }; 55a74532a1Spatrick 56471aeecfSnaddy const struct cfattach ipmi_acpi_ca = { 57a74532a1Spatrick sizeof(struct ipmi_acpi_softc), ipmi_acpi_match, ipmi_acpi_attach, 583a3d566bSjsg NULL, ipmi_activate 59a74532a1Spatrick }; 60a74532a1Spatrick 61a74532a1Spatrick const char *ipmi_acpi_hids[] = { ACPI_DEV_IPMI, NULL }; 62a74532a1Spatrick 63a74532a1Spatrick int 64a74532a1Spatrick ipmi_acpi_match(struct device *parent, void *match, void *aux) 65a74532a1Spatrick { 66a74532a1Spatrick struct acpi_attach_args *aa = aux; 67a74532a1Spatrick struct cfdata *cf = match; 68a74532a1Spatrick 69a74532a1Spatrick /* sanity */ 70a74532a1Spatrick return (acpi_matchhids(aa, ipmi_acpi_hids, cf->cf_driver->cd_name)); 71a74532a1Spatrick } 72a74532a1Spatrick 73a74532a1Spatrick void 74a74532a1Spatrick ipmi_acpi_attach(struct device *parent, struct device *self, void *aux) 75a74532a1Spatrick { 76a74532a1Spatrick struct ipmi_acpi_softc *sc = (struct ipmi_acpi_softc *)self; 77a74532a1Spatrick struct acpi_attach_args *aa = aux; 78a74532a1Spatrick struct ipmi_attach_args ia; 79a74532a1Spatrick struct aml_value res; 8002af067eSkettenis int64_t ift, srv = 0; 81a74532a1Spatrick int rc; 82a74532a1Spatrick 83a74532a1Spatrick sc->sc_acpi = (struct acpi_softc *)parent; 84a74532a1Spatrick sc->sc_devnode = aa->aaa_node; 85a74532a1Spatrick 86a74532a1Spatrick rc = aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_IFT", 0, NULL, &ift); 87a74532a1Spatrick if (rc) { 88a74532a1Spatrick printf(": no _IFT\n"); 89a74532a1Spatrick return; 90a74532a1Spatrick } 91a74532a1Spatrick sc->sc_ift = ift; 92a74532a1Spatrick 9302af067eSkettenis aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_SRV", 0, NULL, &srv); 9402af067eSkettenis sc->sc_srv = srv; 9502af067eSkettenis 96a74532a1Spatrick if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) { 97a74532a1Spatrick printf(": no _CRS method\n"); 98a74532a1Spatrick return; 99a74532a1Spatrick } 100a74532a1Spatrick if (res.type != AML_OBJTYPE_BUFFER) { 101a74532a1Spatrick printf(": invalid _CRS object (type %d len %d)\n", 102a74532a1Spatrick res.type, res.length); 103a74532a1Spatrick aml_freevalue(&res); 104a74532a1Spatrick return; 105a74532a1Spatrick } 106a74532a1Spatrick 107a74532a1Spatrick aml_parse_resource(&res, ipmi_acpi_parse_crs, sc); 108a74532a1Spatrick aml_freevalue(&res); 109a74532a1Spatrick 11002af067eSkettenis if (sc->sc_iotype == 0) { 111a74532a1Spatrick printf("%s: incomplete resources (ift %d)\n", 112a74532a1Spatrick DEVNAME(sc), sc->sc_ift); 113a74532a1Spatrick return; 114a74532a1Spatrick } 115a74532a1Spatrick 116c08dc278Skettenis memset(&ia, 0, sizeof(ia)); 11702af067eSkettenis ia.iaa_iot = sc->sc_acpi->sc_iot; 11802af067eSkettenis ia.iaa_memt = sc->sc_acpi->sc_memt; 119a74532a1Spatrick ia.iaa_if_type = sc->sc_ift; 12002af067eSkettenis ia.iaa_if_rev = (sc->sc_srv >> 4); 121a74532a1Spatrick ia.iaa_if_irq = -1; 122a74532a1Spatrick ia.iaa_if_irqlvl = 0; 123cda7789cSkettenis ia.iaa_if_iosize = 1; 124a74532a1Spatrick ia.iaa_if_iospacing = sc->sc_iospacing; 125a74532a1Spatrick ia.iaa_if_iobase = sc->sc_iobase; 126a74532a1Spatrick ia.iaa_if_iotype = sc->sc_iotype; 127a74532a1Spatrick 128c08dc278Skettenis ipmi_attach_common(&sc->sc, &ia); 129a74532a1Spatrick } 130a74532a1Spatrick 131a74532a1Spatrick int 132a74532a1Spatrick ipmi_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg) 133a74532a1Spatrick { 134a74532a1Spatrick struct ipmi_acpi_softc *sc = arg; 135a74532a1Spatrick int type = AML_CRSTYPE(crs); 13602af067eSkettenis bus_size_t addr; 13702af067eSkettenis char iotype; 13802af067eSkettenis 13902af067eSkettenis switch (type) { 140*e012216eSyasuoka case SR_IRQ: 141*e012216eSyasuoka /* Ignore for now. */ 142*e012216eSyasuoka return 0; 14302af067eSkettenis case SR_IOPORT: 14402af067eSkettenis addr = crs->sr_ioport._max; 14502af067eSkettenis iotype = 'i'; 14602af067eSkettenis break; 14702af067eSkettenis case LR_MEM32FIXED: 14802af067eSkettenis addr = crs->lr_m32fixed._bas; 14902af067eSkettenis iotype = 'm'; 15002af067eSkettenis break; 15102af067eSkettenis case LR_EXTIRQ: 15202af067eSkettenis /* Ignore for now. */ 15302af067eSkettenis return 0; 15402af067eSkettenis default: 15502af067eSkettenis printf("\n%s: unexpected resource #%d type %d", 15602af067eSkettenis DEVNAME(sc), crsidx, type); 15702af067eSkettenis sc->sc_iotype = 0; 15802af067eSkettenis return -1; 15902af067eSkettenis } 160a74532a1Spatrick 161a74532a1Spatrick switch (crsidx) { 162a74532a1Spatrick case 0: 16302af067eSkettenis sc->sc_iobase = addr; 164a74532a1Spatrick sc->sc_iospacing = 1; 16502af067eSkettenis sc->sc_iotype = iotype; 166a74532a1Spatrick break; 167a74532a1Spatrick case 1: 16802af067eSkettenis if (sc->sc_iotype != iotype) { 16902af067eSkettenis printf("\n%s: unexpected resource #%d type %d\n", 170a74532a1Spatrick DEVNAME(sc), crsidx, type); 17102af067eSkettenis sc->sc_iotype = 0; 17202af067eSkettenis return -1; 173a74532a1Spatrick } 17402af067eSkettenis if (addr <= sc->sc_iobase) { 17502af067eSkettenis sc->sc_iotype = 0; 17602af067eSkettenis return -1; 17702af067eSkettenis } 17802af067eSkettenis sc->sc_iospacing = addr - sc->sc_iobase; 179a74532a1Spatrick break; 180a74532a1Spatrick default: 18102af067eSkettenis printf("\n%s: invalid resource #%d type %d (ift %d)", 182a74532a1Spatrick DEVNAME(sc), crsidx, type, sc->sc_ift); 18302af067eSkettenis sc->sc_iotype = 0; 18402af067eSkettenis return -1; 185a74532a1Spatrick } 186a74532a1Spatrick 187a74532a1Spatrick return 0; 188a74532a1Spatrick } 189