1 /* $OpenBSD: ipmi_acpi.c,v 1.4 2020/03/29 09:31:10 kettenis 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 struct cfattach ipmi_acpi_ca = { 57 sizeof(struct ipmi_acpi_softc), ipmi_acpi_match, ipmi_acpi_attach, 58 }; 59 60 const char *ipmi_acpi_hids[] = { ACPI_DEV_IPMI, NULL }; 61 62 int 63 ipmi_acpi_match(struct device *parent, void *match, void *aux) 64 { 65 struct acpi_attach_args *aa = aux; 66 struct cfdata *cf = match; 67 68 /* sanity */ 69 return (acpi_matchhids(aa, ipmi_acpi_hids, cf->cf_driver->cd_name)); 70 } 71 72 void 73 ipmi_acpi_attach(struct device *parent, struct device *self, void *aux) 74 { 75 struct ipmi_acpi_softc *sc = (struct ipmi_acpi_softc *)self; 76 struct acpi_attach_args *aa = aux; 77 struct ipmi_attach_args ia; 78 struct aml_value res; 79 int64_t ift, srv = 0; 80 int rc; 81 82 sc->sc_acpi = (struct acpi_softc *)parent; 83 sc->sc_devnode = aa->aaa_node; 84 85 rc = aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_IFT", 0, NULL, &ift); 86 if (rc) { 87 printf(": no _IFT\n"); 88 return; 89 } 90 sc->sc_ift = ift; 91 92 aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_SRV", 0, NULL, &srv); 93 sc->sc_srv = srv; 94 95 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) { 96 printf(": no _CRS method\n"); 97 return; 98 } 99 if (res.type != AML_OBJTYPE_BUFFER) { 100 printf(": invalid _CRS object (type %d len %d)\n", 101 res.type, res.length); 102 aml_freevalue(&res); 103 return; 104 } 105 106 aml_parse_resource(&res, ipmi_acpi_parse_crs, sc); 107 aml_freevalue(&res); 108 109 if (sc->sc_iotype == 0) { 110 printf("%s: incomplete resources (ift %d)\n", 111 DEVNAME(sc), sc->sc_ift); 112 return; 113 } 114 115 memset(&ia, 0, sizeof(ia)); 116 ia.iaa_iot = sc->sc_acpi->sc_iot; 117 ia.iaa_memt = sc->sc_acpi->sc_memt; 118 ia.iaa_if_type = sc->sc_ift; 119 ia.iaa_if_rev = (sc->sc_srv >> 4); 120 ia.iaa_if_irq = -1; 121 ia.iaa_if_irqlvl = 0; 122 ia.iaa_if_iosize = 1; 123 ia.iaa_if_iospacing = sc->sc_iospacing; 124 ia.iaa_if_iobase = sc->sc_iobase; 125 ia.iaa_if_iotype = sc->sc_iotype; 126 127 ipmi_attach_common(&sc->sc, &ia); 128 } 129 130 int 131 ipmi_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg) 132 { 133 struct ipmi_acpi_softc *sc = arg; 134 int type = AML_CRSTYPE(crs); 135 bus_size_t addr; 136 char iotype; 137 138 switch (type) { 139 case SR_IOPORT: 140 addr = crs->sr_ioport._max; 141 iotype = 'i'; 142 break; 143 case LR_MEM32FIXED: 144 addr = crs->lr_m32fixed._bas; 145 iotype = 'm'; 146 break; 147 case LR_EXTIRQ: 148 /* Ignore for now. */ 149 return 0; 150 default: 151 printf("\n%s: unexpected resource #%d type %d", 152 DEVNAME(sc), crsidx, type); 153 sc->sc_iotype = 0; 154 return -1; 155 } 156 157 switch (crsidx) { 158 case 0: 159 sc->sc_iobase = addr; 160 sc->sc_iospacing = 1; 161 sc->sc_iotype = iotype; 162 break; 163 case 1: 164 if (sc->sc_iotype != iotype) { 165 printf("\n%s: unexpected resource #%d type %d\n", 166 DEVNAME(sc), crsidx, type); 167 sc->sc_iotype = 0; 168 return -1; 169 } 170 if (addr <= sc->sc_iobase) { 171 sc->sc_iotype = 0; 172 return -1; 173 } 174 sc->sc_iospacing = addr - sc->sc_iobase; 175 break; 176 default: 177 printf("\n%s: invalid resource #%d type %d (ift %d)", 178 DEVNAME(sc), crsidx, type, sc->sc_ift); 179 sc->sc_iotype = 0; 180 return -1; 181 } 182 183 return 0; 184 } 185