1 /* $OpenBSD: ipmi_acpi.c,v 1.3 2020/01/06 12:35:57 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_iospacing = sc->sc_iospacing; 123 ia.iaa_if_iobase = sc->sc_iobase; 124 ia.iaa_if_iotype = sc->sc_iotype; 125 126 ipmi_attach_common(&sc->sc, &ia); 127 } 128 129 int 130 ipmi_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg) 131 { 132 struct ipmi_acpi_softc *sc = arg; 133 int type = AML_CRSTYPE(crs); 134 bus_size_t addr; 135 char iotype; 136 137 switch (type) { 138 case SR_IOPORT: 139 addr = crs->sr_ioport._max; 140 iotype = 'i'; 141 break; 142 case LR_MEM32FIXED: 143 addr = crs->lr_m32fixed._bas; 144 iotype = 'm'; 145 break; 146 case LR_EXTIRQ: 147 /* Ignore for now. */ 148 return 0; 149 default: 150 printf("\n%s: unexpected resource #%d type %d", 151 DEVNAME(sc), crsidx, type); 152 sc->sc_iotype = 0; 153 return -1; 154 } 155 156 switch (crsidx) { 157 case 0: 158 sc->sc_iobase = addr; 159 sc->sc_iospacing = 1; 160 sc->sc_iotype = iotype; 161 break; 162 case 1: 163 if (sc->sc_iotype != iotype) { 164 printf("\n%s: unexpected resource #%d type %d\n", 165 DEVNAME(sc), crsidx, type); 166 sc->sc_iotype = 0; 167 return -1; 168 } 169 if (addr <= sc->sc_iobase) { 170 sc->sc_iotype = 0; 171 return -1; 172 } 173 sc->sc_iospacing = addr - sc->sc_iobase; 174 break; 175 default: 176 printf("\n%s: invalid resource #%d type %d (ift %d)", 177 DEVNAME(sc), crsidx, type, sc->sc_ift); 178 sc->sc_iotype = 0; 179 return -1; 180 } 181 182 return 0; 183 } 184