xref: /freebsd/sys/dev/ipmi/ipmi_opal.c (revision b75e32a466dbab7a6729ff7a6472c6f9c9207491)
10bf0bb83SJustin Hibbits /*-
20bf0bb83SJustin Hibbits  * Copyright (C) 2018 Justin Hibbits
30bf0bb83SJustin Hibbits  *
40bf0bb83SJustin Hibbits  * Redistribution and use in source and binary forms, with or without
50bf0bb83SJustin Hibbits  * modification, are permitted provided that the following conditions
60bf0bb83SJustin Hibbits  * are met:
70bf0bb83SJustin Hibbits  * 1. Redistributions of source code must retain the above copyright
80bf0bb83SJustin Hibbits  *    notice, this list of conditions and the following disclaimer.
90bf0bb83SJustin Hibbits  * 2. Redistributions in binary form must reproduce the above copyright
100bf0bb83SJustin Hibbits  *    notice, this list of conditions and the following disclaimer in the
110bf0bb83SJustin Hibbits  *    documentation and/or other materials provided with the distribution.
120bf0bb83SJustin Hibbits  *
130bf0bb83SJustin Hibbits  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
140bf0bb83SJustin Hibbits  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
150bf0bb83SJustin Hibbits  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
160bf0bb83SJustin Hibbits  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
170bf0bb83SJustin Hibbits  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
180bf0bb83SJustin Hibbits  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
190bf0bb83SJustin Hibbits  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
200bf0bb83SJustin Hibbits  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
210bf0bb83SJustin Hibbits  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
220bf0bb83SJustin Hibbits  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230bf0bb83SJustin Hibbits  */
240bf0bb83SJustin Hibbits 
250bf0bb83SJustin Hibbits #include <sys/param.h>
260bf0bb83SJustin Hibbits #include <sys/kernel.h>
270bf0bb83SJustin Hibbits #include <sys/systm.h>
28e2e050c8SConrad Meyer #include <sys/lock.h>
290bf0bb83SJustin Hibbits #include <sys/module.h>
30e2e050c8SConrad Meyer #include <sys/mutex.h>
310bf0bb83SJustin Hibbits #include <sys/bus.h>
320bf0bb83SJustin Hibbits #include <sys/kthread.h>
330bf0bb83SJustin Hibbits #include <sys/proc.h>
340bf0bb83SJustin Hibbits #include <sys/selinfo.h>
350bf0bb83SJustin Hibbits #include <sys/sysctl.h>
360bf0bb83SJustin Hibbits 
370bf0bb83SJustin Hibbits #include <vm/vm.h>
380bf0bb83SJustin Hibbits #include <vm/pmap.h>
390bf0bb83SJustin Hibbits 
400bf0bb83SJustin Hibbits #include <machine/bus.h>
410bf0bb83SJustin Hibbits 
420bf0bb83SJustin Hibbits #include <dev/ofw/openfirm.h>
430bf0bb83SJustin Hibbits #include <dev/ofw/ofw_bus.h>
440bf0bb83SJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
450bf0bb83SJustin Hibbits 
460bf0bb83SJustin Hibbits #include <sys/ipmi.h>
470bf0bb83SJustin Hibbits #include <dev/ipmi/ipmivars.h>
480bf0bb83SJustin Hibbits 
490bf0bb83SJustin Hibbits #include <powerpc/powernv/opal.h>
500bf0bb83SJustin Hibbits 
51f6f325c8SLeandro Lupori /*
52f6f325c8SLeandro Lupori  * OPAL_IPMI_DEBUG
53f6f325c8SLeandro Lupori  *
54f6f325c8SLeandro Lupori  * 0 - disabled
55f6f325c8SLeandro Lupori  * 1 - enable error messages (EPRINTF)
56f6f325c8SLeandro Lupori  * 2 - enable error and debug messages (DPRINTF)
57f6f325c8SLeandro Lupori  */
58f6f325c8SLeandro Lupori #define	OPAL_IPMI_DEBUG		0
59f6f325c8SLeandro Lupori #if OPAL_IPMI_DEBUG >= 2
60f6f325c8SLeandro Lupori /* debug printf */
61f6f325c8SLeandro Lupori #define	DPRINTF(fmt, ...)	printf("ipmi: " fmt "\n", ## __VA_ARGS__)
62f6f325c8SLeandro Lupori #else
63f6f325c8SLeandro Lupori #define	DPRINTF(fmt, ...)	((void)0)
64f6f325c8SLeandro Lupori #endif
65f6f325c8SLeandro Lupori #if OPAL_IPMI_DEBUG >= 1
66f6f325c8SLeandro Lupori /* error printf: to print messages only when something fails */
67f6f325c8SLeandro Lupori #define	EPRINTF(fmt, ...)	printf("ipmi: " fmt "\n", ## __VA_ARGS__)
68f6f325c8SLeandro Lupori #else
69f6f325c8SLeandro Lupori #define	EPRINTF(fmt, ...)	((void)0)
70f6f325c8SLeandro Lupori #endif
71f6f325c8SLeandro Lupori 
720bf0bb83SJustin Hibbits struct opal_ipmi_softc {
730bf0bb83SJustin Hibbits 	struct ipmi_softc ipmi;
740bf0bb83SJustin Hibbits 	uint64_t sc_interface;
75f6f325c8SLeandro Lupori 	int sc_timedout;
760bf0bb83SJustin Hibbits 	struct opal_ipmi_msg *sc_msg; /* Protected by IPMI lock */
770bf0bb83SJustin Hibbits };
780bf0bb83SJustin Hibbits 
790bf0bb83SJustin Hibbits static MALLOC_DEFINE(M_IPMI, "ipmi", "OPAL IPMI");
800bf0bb83SJustin Hibbits 
810bf0bb83SJustin Hibbits static int
opal_ipmi_recv(struct opal_ipmi_softc * sc,uint64_t * msg_len,int timo)82f6f325c8SLeandro Lupori opal_ipmi_recv(struct opal_ipmi_softc *sc, uint64_t *msg_len, int timo)
83f6f325c8SLeandro Lupori {
84f6f325c8SLeandro Lupori 	int err;
85f6f325c8SLeandro Lupori 
86f6f325c8SLeandro Lupori 	if (timo == 0)
87f6f325c8SLeandro Lupori 		timo = MAX_TIMEOUT;
88f6f325c8SLeandro Lupori 	timo *= 10; /* Timeout is in milliseconds, we delay in 100us */
89f6f325c8SLeandro Lupori 
90f6f325c8SLeandro Lupori 	for (;;) {
91f6f325c8SLeandro Lupori 		*msg_len = sizeof(struct opal_ipmi_msg) + IPMI_MAX_RX;
92f6f325c8SLeandro Lupori 		/* Crank the OPAL state machine while we poll for a reply. */
93f6f325c8SLeandro Lupori 		opal_call(OPAL_POLL_EVENTS, NULL);
94f6f325c8SLeandro Lupori 		err = opal_call(OPAL_IPMI_RECV, sc->sc_interface,
95f6f325c8SLeandro Lupori 		    vtophys(sc->sc_msg), vtophys(msg_len));
96f6f325c8SLeandro Lupori 		if (err != OPAL_EMPTY)
97f6f325c8SLeandro Lupori 			break;
98f6f325c8SLeandro Lupori 
99f6f325c8SLeandro Lupori 		DELAY(100);
100f6f325c8SLeandro Lupori 		if (timo-- <= 0) {
101f6f325c8SLeandro Lupori 			sc->sc_timedout = 1;
102f6f325c8SLeandro Lupori 			break;
103f6f325c8SLeandro Lupori 		}
104f6f325c8SLeandro Lupori 	}
105f6f325c8SLeandro Lupori 
106f6f325c8SLeandro Lupori 	if (err != OPAL_SUCCESS)
107f6f325c8SLeandro Lupori 		EPRINTF("RECV: error: %d", err);
108f6f325c8SLeandro Lupori 
109f6f325c8SLeandro Lupori 	switch (err) {
110f6f325c8SLeandro Lupori 	case OPAL_SUCCESS:
111f6f325c8SLeandro Lupori 		DPRINTF("RECV: rv=%02x len=%ld",
112f6f325c8SLeandro Lupori 		    sc->sc_msg->data[0], *msg_len);
113f6f325c8SLeandro Lupori 		return (0);
114f6f325c8SLeandro Lupori 	case OPAL_RESOURCE:
115f6f325c8SLeandro Lupori 		return (ENOMEM);
116f6f325c8SLeandro Lupori 	case OPAL_EMPTY:
117f6f325c8SLeandro Lupori 		return (EAGAIN);
118f6f325c8SLeandro Lupori 	default:
119f6f325c8SLeandro Lupori 		return (EIO);
120f6f325c8SLeandro Lupori 	}
121f6f325c8SLeandro Lupori }
122f6f325c8SLeandro Lupori 
123f6f325c8SLeandro Lupori static void
opal_ipmi_discard_msgs(struct opal_ipmi_softc * sc)124f6f325c8SLeandro Lupori opal_ipmi_discard_msgs(struct opal_ipmi_softc *sc)
125f6f325c8SLeandro Lupori {
126f6f325c8SLeandro Lupori 	uint64_t msg_len;
127f6f325c8SLeandro Lupori 	int err, i = 0;
128f6f325c8SLeandro Lupori 
129f6f325c8SLeandro Lupori 	/* OPAL_IPMI_RECV fails when msg version is not set. */
130f6f325c8SLeandro Lupori 	sc->sc_msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
131f6f325c8SLeandro Lupori 
132f6f325c8SLeandro Lupori 	/* Wait up to 100ms for the 1st timedout message. */
133f6f325c8SLeandro Lupori 	err = opal_ipmi_recv(sc, &msg_len, 100);
134f6f325c8SLeandro Lupori 	while (err == 0) {
135f6f325c8SLeandro Lupori 		i++;
136f6f325c8SLeandro Lupori 		/* Wait only 10ms for the remaining messages. */
137f6f325c8SLeandro Lupori 		err = opal_ipmi_recv(sc, &msg_len, 10);
138f6f325c8SLeandro Lupori 	}
139f6f325c8SLeandro Lupori 	if (i > 0)
140f6f325c8SLeandro Lupori 		EPRINTF("Discarded %d message(s)", i);
141f6f325c8SLeandro Lupori 	sc->sc_timedout = 0;
142f6f325c8SLeandro Lupori }
143f6f325c8SLeandro Lupori 
144f6f325c8SLeandro Lupori static int
opal_ipmi_polled_request(struct opal_ipmi_softc * sc,struct ipmi_request * req,int timo)145*b75e32a4SGleb Smirnoff opal_ipmi_polled_request(struct opal_ipmi_softc *sc, struct ipmi_request *req,
146*b75e32a4SGleb Smirnoff     int timo)
1470bf0bb83SJustin Hibbits {
1480bf0bb83SJustin Hibbits 	uint64_t msg_len;
1490bf0bb83SJustin Hibbits 	int err;
1500bf0bb83SJustin Hibbits 
151f6f325c8SLeandro Lupori 	/*
152f6f325c8SLeandro Lupori 	 * Discard timed out messages before sending a new one, to avoid
153f6f325c8SLeandro Lupori 	 * them being confused with the reply of the new message.
154f6f325c8SLeandro Lupori 	 */
155f6f325c8SLeandro Lupori 	if (sc->sc_timedout)
156f6f325c8SLeandro Lupori 		opal_ipmi_discard_msgs(sc);
157f6f325c8SLeandro Lupori 
1580bf0bb83SJustin Hibbits 	/* Construct and send the message. */
1590bf0bb83SJustin Hibbits 	sc->sc_msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
1600bf0bb83SJustin Hibbits 	sc->sc_msg->netfn = req->ir_addr;
1610bf0bb83SJustin Hibbits 	sc->sc_msg->cmd = req->ir_command;
1620bf0bb83SJustin Hibbits 
1630bf0bb83SJustin Hibbits 	if (req->ir_requestlen > IPMI_MAX_RX) {
1640bf0bb83SJustin Hibbits 		err = ENOMEM;
1650bf0bb83SJustin Hibbits 		goto out;
1660bf0bb83SJustin Hibbits 	}
1670bf0bb83SJustin Hibbits 	memcpy(sc->sc_msg->data, req->ir_request, req->ir_requestlen);
1680bf0bb83SJustin Hibbits 
1690bf0bb83SJustin Hibbits 	msg_len = sizeof(*sc->sc_msg) + req->ir_requestlen;
1700bf0bb83SJustin Hibbits 	err = opal_call(OPAL_IPMI_SEND, sc->sc_interface, vtophys(sc->sc_msg),
1710bf0bb83SJustin Hibbits 	    msg_len);
172f6f325c8SLeandro Lupori 
173f6f325c8SLeandro Lupori 	DPRINTF("SEND: cmd=%02x netfn=%02x len=%ld -> %d",
174f6f325c8SLeandro Lupori 	    sc->sc_msg->cmd, sc->sc_msg->netfn, msg_len, err);
175f6f325c8SLeandro Lupori 
176f6f325c8SLeandro Lupori 	if (err != OPAL_SUCCESS)
177f6f325c8SLeandro Lupori 		EPRINTF("SEND: error: %d", err);
178f6f325c8SLeandro Lupori 
1790bf0bb83SJustin Hibbits 	switch (err) {
1800bf0bb83SJustin Hibbits 	case OPAL_SUCCESS:
1810bf0bb83SJustin Hibbits 		break;
1820bf0bb83SJustin Hibbits 	case OPAL_PARAMETER:
1830bf0bb83SJustin Hibbits 	case OPAL_UNSUPPORTED:
1840bf0bb83SJustin Hibbits 		err = EINVAL;
1850bf0bb83SJustin Hibbits 		goto out;
1860bf0bb83SJustin Hibbits 	case OPAL_RESOURCE:
1870bf0bb83SJustin Hibbits 		err = ENOMEM;
1880bf0bb83SJustin Hibbits 		goto out;
189f6f325c8SLeandro Lupori 	case OPAL_HARDWARE:
190f6f325c8SLeandro Lupori 	default:
191f6f325c8SLeandro Lupori 		err = EIO;
192f6f325c8SLeandro Lupori 		goto out;
1930bf0bb83SJustin Hibbits 	}
1940bf0bb83SJustin Hibbits 
195*b75e32a4SGleb Smirnoff 	if ((err = opal_ipmi_recv(sc, &msg_len, timo)) == 0) {
1960bf0bb83SJustin Hibbits 		/* Subtract one extra for the completion code. */
1970bf0bb83SJustin Hibbits 		req->ir_replylen = msg_len - sizeof(struct opal_ipmi_msg) - 1;
1980bf0bb83SJustin Hibbits 		req->ir_replylen = min(req->ir_replylen, req->ir_replybuflen);
1990bf0bb83SJustin Hibbits 		memcpy(req->ir_reply, &sc->sc_msg->data[1], req->ir_replylen);
2000bf0bb83SJustin Hibbits 		req->ir_compcode = sc->sc_msg->data[0];
2010bf0bb83SJustin Hibbits 	}
2020bf0bb83SJustin Hibbits 
2030bf0bb83SJustin Hibbits out:
2040bf0bb83SJustin Hibbits 	return (err);
2050bf0bb83SJustin Hibbits }
2060bf0bb83SJustin Hibbits 
2070bf0bb83SJustin Hibbits static int
opal_ipmi_probe(device_t dev)2080bf0bb83SJustin Hibbits opal_ipmi_probe(device_t dev)
2090bf0bb83SJustin Hibbits {
2100bf0bb83SJustin Hibbits 	if (!ofw_bus_is_compatible(dev, "ibm,opal-ipmi"))
2110bf0bb83SJustin Hibbits 		return (ENXIO);
2120bf0bb83SJustin Hibbits 
2130bf0bb83SJustin Hibbits 	device_set_desc(dev, "OPAL IPMI System Interface");
2140bf0bb83SJustin Hibbits 
2150bf0bb83SJustin Hibbits 	return (BUS_PROBE_DEFAULT);
2160bf0bb83SJustin Hibbits }
2170bf0bb83SJustin Hibbits 
2180bf0bb83SJustin Hibbits static void
opal_ipmi_loop(void * arg)2190bf0bb83SJustin Hibbits opal_ipmi_loop(void *arg)
2200bf0bb83SJustin Hibbits {
2210bf0bb83SJustin Hibbits 	struct opal_ipmi_softc *sc = arg;
2220bf0bb83SJustin Hibbits 	struct ipmi_request *req;
223f6f325c8SLeandro Lupori 	int i, err;
2240bf0bb83SJustin Hibbits 
2250bf0bb83SJustin Hibbits 	IPMI_LOCK(&sc->ipmi);
2260bf0bb83SJustin Hibbits 	while ((req = ipmi_dequeue_request(&sc->ipmi)) != NULL) {
2270bf0bb83SJustin Hibbits 		IPMI_UNLOCK(&sc->ipmi);
228f6f325c8SLeandro Lupori 		err = EIO;
229f6f325c8SLeandro Lupori 		for (i = 0; i < 3 && err != 0; i++) {
2300bf0bb83SJustin Hibbits 			IPMI_IO_LOCK(&sc->ipmi);
231f6f325c8SLeandro Lupori 			err = opal_ipmi_polled_request(sc, req, MAX_TIMEOUT);
2320bf0bb83SJustin Hibbits 			IPMI_IO_UNLOCK(&sc->ipmi);
2330bf0bb83SJustin Hibbits 		}
234f6f325c8SLeandro Lupori 		req->ir_error = err == 0 ? 0 : EIO;
2350bf0bb83SJustin Hibbits 		IPMI_LOCK(&sc->ipmi);
2360bf0bb83SJustin Hibbits 		ipmi_complete_request(&sc->ipmi, req);
2370bf0bb83SJustin Hibbits 	}
2380bf0bb83SJustin Hibbits 	IPMI_UNLOCK(&sc->ipmi);
2390bf0bb83SJustin Hibbits 	kproc_exit(0);
2400bf0bb83SJustin Hibbits }
2410bf0bb83SJustin Hibbits 
2420bf0bb83SJustin Hibbits static int
opal_ipmi_startup(struct ipmi_softc * sc)2430bf0bb83SJustin Hibbits opal_ipmi_startup(struct ipmi_softc *sc)
2440bf0bb83SJustin Hibbits {
2450bf0bb83SJustin Hibbits 
2460bf0bb83SJustin Hibbits 	return (kproc_create(opal_ipmi_loop, sc, &sc->ipmi_kthread, 0, 0,
2470bf0bb83SJustin Hibbits 	    "%s: opal", device_get_nameunit(sc->ipmi_dev)));
2480bf0bb83SJustin Hibbits }
2490bf0bb83SJustin Hibbits 
2500bf0bb83SJustin Hibbits static int
opal_ipmi_driver_request(struct ipmi_softc * isc,struct ipmi_request * req)251366d6a42SGleb Smirnoff opal_ipmi_driver_request(struct ipmi_softc *isc, struct ipmi_request *req)
2520bf0bb83SJustin Hibbits {
2530bf0bb83SJustin Hibbits 	struct opal_ipmi_softc *sc = (struct opal_ipmi_softc *)isc;
2540bf0bb83SJustin Hibbits 	int i, err;
2550bf0bb83SJustin Hibbits 
2560bf0bb83SJustin Hibbits 	for (i = 0; i < 3; i++) {
2570bf0bb83SJustin Hibbits 		IPMI_LOCK(&sc->ipmi);
258*b75e32a4SGleb Smirnoff 		err = opal_ipmi_polled_request(sc, req, 0);
2590bf0bb83SJustin Hibbits 		IPMI_UNLOCK(&sc->ipmi);
2600bf0bb83SJustin Hibbits 		if (err == 0)
2610bf0bb83SJustin Hibbits 			break;
2620bf0bb83SJustin Hibbits 	}
2630bf0bb83SJustin Hibbits 
2640bf0bb83SJustin Hibbits 	req->ir_error = err;
2650bf0bb83SJustin Hibbits 
2660bf0bb83SJustin Hibbits 	return (err);
2670bf0bb83SJustin Hibbits }
2680bf0bb83SJustin Hibbits 
2690bf0bb83SJustin Hibbits static int
opal_ipmi_attach(device_t dev)2700bf0bb83SJustin Hibbits opal_ipmi_attach(device_t dev)
2710bf0bb83SJustin Hibbits {
2720bf0bb83SJustin Hibbits 	struct opal_ipmi_softc *sc;
273f6f325c8SLeandro Lupori 	pcell_t ifid;
2740bf0bb83SJustin Hibbits 
2750bf0bb83SJustin Hibbits 	sc = device_get_softc(dev);
2760bf0bb83SJustin Hibbits 
2770bf0bb83SJustin Hibbits 	if (OF_getencprop(ofw_bus_get_node(dev), "ibm,ipmi-interface-id",
278f6f325c8SLeandro Lupori 	    &ifid, sizeof(ifid)) < 0) {
2790bf0bb83SJustin Hibbits 		device_printf(dev, "Missing interface id\n");
2800bf0bb83SJustin Hibbits 		return (ENXIO);
2810bf0bb83SJustin Hibbits 	}
282f6f325c8SLeandro Lupori 	sc->sc_interface = ifid;
2830bf0bb83SJustin Hibbits 	sc->ipmi.ipmi_startup = opal_ipmi_startup;
2840bf0bb83SJustin Hibbits 	sc->ipmi.ipmi_driver_request = opal_ipmi_driver_request;
28554318d2aSJustin Hibbits 	sc->ipmi.ipmi_enqueue_request = ipmi_polled_enqueue_request;
28654318d2aSJustin Hibbits 	sc->ipmi.ipmi_driver_requests_polled = 1;
2870bf0bb83SJustin Hibbits 	sc->ipmi.ipmi_dev = dev;
2880bf0bb83SJustin Hibbits 
2890bf0bb83SJustin Hibbits 	sc->sc_msg = malloc(sizeof(struct opal_ipmi_msg) + IPMI_MAX_RX, M_IPMI,
2900bf0bb83SJustin Hibbits 	    M_WAITOK | M_ZERO);
2910bf0bb83SJustin Hibbits 
292f6f325c8SLeandro Lupori 	/* Discard old messages that may have remained in receive queue. */
293f6f325c8SLeandro Lupori 	opal_ipmi_discard_msgs(sc);
294f6f325c8SLeandro Lupori 
2950bf0bb83SJustin Hibbits 	return (ipmi_attach(dev));
2960bf0bb83SJustin Hibbits }
2970bf0bb83SJustin Hibbits 
2980bf0bb83SJustin Hibbits static int
opal_ipmi_detach(device_t dev)2990bf0bb83SJustin Hibbits opal_ipmi_detach(device_t dev)
3000bf0bb83SJustin Hibbits {
30195a1f0e8SJustin Hibbits 	struct opal_ipmi_softc *sc;
30295a1f0e8SJustin Hibbits 	int err;
30395a1f0e8SJustin Hibbits 
30495a1f0e8SJustin Hibbits 	sc = device_get_softc(dev);
30595a1f0e8SJustin Hibbits 	err = ipmi_detach(dev);
30695a1f0e8SJustin Hibbits 	if (err == 0)
30795a1f0e8SJustin Hibbits 		free(sc->sc_msg, M_IPMI);
30895a1f0e8SJustin Hibbits 
30995a1f0e8SJustin Hibbits 	return (err);
3100bf0bb83SJustin Hibbits }
3110bf0bb83SJustin Hibbits 
3120bf0bb83SJustin Hibbits static device_method_t	opal_ipmi_methods[] = {
3130bf0bb83SJustin Hibbits 	/* Device interface */
3140bf0bb83SJustin Hibbits 	DEVMETHOD(device_probe,		opal_ipmi_probe),
3150bf0bb83SJustin Hibbits 	DEVMETHOD(device_attach,	opal_ipmi_attach),
3160bf0bb83SJustin Hibbits 	DEVMETHOD(device_detach,	opal_ipmi_detach),
3170bf0bb83SJustin Hibbits 	DEVMETHOD_END
3180bf0bb83SJustin Hibbits };
3190bf0bb83SJustin Hibbits 
3200bf0bb83SJustin Hibbits static driver_t opal_ipmi_driver = {
3210bf0bb83SJustin Hibbits 	"ipmi",
3220bf0bb83SJustin Hibbits 	opal_ipmi_methods,
3230bf0bb83SJustin Hibbits 	sizeof(struct opal_ipmi_softc)
3240bf0bb83SJustin Hibbits };
3250bf0bb83SJustin Hibbits 
326fd773e2bSJohn Baldwin DRIVER_MODULE(opal_ipmi, opal, opal_ipmi_driver, NULL, NULL);
327