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