xref: /openbsd-src/sys/dev/acpi/ipmi_acpi.c (revision e012216e8ad275af806b64ba937f97650f03c8a5)
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