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