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