1d72a0786SJohn Baldwin /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4d72a0786SJohn Baldwin * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
5d72a0786SJohn Baldwin * All rights reserved.
6d72a0786SJohn Baldwin *
7d72a0786SJohn Baldwin * Redistribution and use in source and binary forms, with or without
8d72a0786SJohn Baldwin * modification, are permitted provided that the following conditions
9d72a0786SJohn Baldwin * are met:
10d72a0786SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
11d72a0786SJohn Baldwin * notice, this list of conditions and the following disclaimer.
12d72a0786SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
13d72a0786SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
14d72a0786SJohn Baldwin * documentation and/or other materials provided with the distribution.
15d72a0786SJohn Baldwin *
16d72a0786SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d72a0786SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d72a0786SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d72a0786SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d72a0786SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d72a0786SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d72a0786SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d72a0786SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d72a0786SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d72a0786SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d72a0786SJohn Baldwin * SUCH DAMAGE.
27d72a0786SJohn Baldwin */
28d72a0786SJohn Baldwin
29d72a0786SJohn Baldwin #include <sys/param.h>
30d72a0786SJohn Baldwin #include <sys/systm.h>
31d72a0786SJohn Baldwin #include <sys/bus.h>
32d72a0786SJohn Baldwin #include <sys/condvar.h>
33d72a0786SJohn Baldwin #include <sys/kernel.h>
34d72a0786SJohn Baldwin #include <sys/module.h>
35d72a0786SJohn Baldwin #include <sys/rman.h>
36d72a0786SJohn Baldwin #include <sys/selinfo.h>
37d72a0786SJohn Baldwin
38129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
39129d3046SJung-uk Kim
40d72a0786SJohn Baldwin #include <dev/acpica/acpivar.h>
41d72a0786SJohn Baldwin
42d72a0786SJohn Baldwin /* Hooks for the ACPI CA debugging infrastructure */
43d72a0786SJohn Baldwin #define _COMPONENT ACPI_BUTTON
44d72a0786SJohn Baldwin ACPI_MODULE_NAME("IPMI")
45d72a0786SJohn Baldwin
46d72a0786SJohn Baldwin #ifdef LOCAL_MODULE
47d72a0786SJohn Baldwin #include <ipmi.h>
48d72a0786SJohn Baldwin #include <ipmivars.h>
49d72a0786SJohn Baldwin #else
50d72a0786SJohn Baldwin #include <sys/ipmi.h>
51d72a0786SJohn Baldwin #include <dev/ipmi/ipmivars.h>
52d72a0786SJohn Baldwin #endif
53d72a0786SJohn Baldwin
54d72a0786SJohn Baldwin static int ipmi_acpi_probe(device_t);
55d72a0786SJohn Baldwin static int ipmi_acpi_attach(device_t);
56d72a0786SJohn Baldwin
57d72a0786SJohn Baldwin int
ipmi_acpi_probe(device_t dev)58d72a0786SJohn Baldwin ipmi_acpi_probe(device_t dev)
59d72a0786SJohn Baldwin {
60d72a0786SJohn Baldwin static char *ipmi_ids[] = {"IPI0001", NULL};
615efca36fSTakanori Watanabe int rv;
62d72a0786SJohn Baldwin
63d72a0786SJohn Baldwin if (ipmi_attached)
64d72a0786SJohn Baldwin return (EBUSY);
65d72a0786SJohn Baldwin
665efca36fSTakanori Watanabe if (acpi_disabled("ipmi"))
67d72a0786SJohn Baldwin return (ENXIO);
685efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ipmi_ids, NULL);
695efca36fSTakanori Watanabe if (rv <= 0)
70d72a0786SJohn Baldwin device_set_desc(dev, "IPMI System Interface");
71d72a0786SJohn Baldwin
725efca36fSTakanori Watanabe return (rv);
73d72a0786SJohn Baldwin }
74d72a0786SJohn Baldwin
75d72a0786SJohn Baldwin static int
ipmi_acpi_attach(device_t dev)76d72a0786SJohn Baldwin ipmi_acpi_attach(device_t dev)
77d72a0786SJohn Baldwin {
78d72a0786SJohn Baldwin ACPI_HANDLE devh;
79d72a0786SJohn Baldwin const char *mode;
80d72a0786SJohn Baldwin struct ipmi_softc *sc = device_get_softc(dev);
81677e70e0SJohn Baldwin int count, error, i, type;
82d72a0786SJohn Baldwin int interface_type = 0, interface_version = 0;
83d72a0786SJohn Baldwin
84d72a0786SJohn Baldwin error = 0;
85d72a0786SJohn Baldwin devh = acpi_get_handle(dev);
86d72a0786SJohn Baldwin if (ACPI_FAILURE(acpi_GetInteger(devh, "_IFT", &interface_type)))
87d72a0786SJohn Baldwin return (ENXIO);
88d72a0786SJohn Baldwin
89d72a0786SJohn Baldwin if (ACPI_FAILURE(acpi_GetInteger(devh, "_SRV", &interface_version)))
90d72a0786SJohn Baldwin return (ENXIO);
91d72a0786SJohn Baldwin
92d72a0786SJohn Baldwin switch (interface_type) {
93d72a0786SJohn Baldwin case KCS_MODE:
94*1f166509SAndrey V. Elsukov count = IPMI_IF_KCS_NRES;
95d72a0786SJohn Baldwin mode = "KCS";
96d72a0786SJohn Baldwin break;
97d72a0786SJohn Baldwin case SMIC_MODE:
98*1f166509SAndrey V. Elsukov count = IPMI_IF_SMIC_NRES;
99d72a0786SJohn Baldwin mode = "SMIC";
100d72a0786SJohn Baldwin break;
101d72a0786SJohn Baldwin case BT_MODE:
102*1f166509SAndrey V. Elsukov count = IPMI_IF_BT_NRES;
103*1f166509SAndrey V. Elsukov mode = "BT";
104*1f166509SAndrey V. Elsukov break;
105d72a0786SJohn Baldwin case SSIF_MODE:
106d72a0786SJohn Baldwin device_printf(dev, "SSIF interface not supported on ACPI\n");
107d72a0786SJohn Baldwin return (0);
108d72a0786SJohn Baldwin default:
109d72a0786SJohn Baldwin return (ENXIO);
110d72a0786SJohn Baldwin }
111d72a0786SJohn Baldwin
112d72a0786SJohn Baldwin if (bus_get_resource(dev, SYS_RES_IOPORT, 0, NULL, NULL) == 0)
113d72a0786SJohn Baldwin type = SYS_RES_IOPORT;
114d72a0786SJohn Baldwin else if (bus_get_resource(dev, SYS_RES_MEMORY, 0, NULL, NULL) == 0)
115d72a0786SJohn Baldwin type = SYS_RES_MEMORY;
116d72a0786SJohn Baldwin else {
117d72a0786SJohn Baldwin device_printf(dev, "unknown resource type\n");
118d72a0786SJohn Baldwin return (ENXIO);
119d72a0786SJohn Baldwin }
120d72a0786SJohn Baldwin
121d72a0786SJohn Baldwin sc->ipmi_io_rid = 0;
122d72a0786SJohn Baldwin sc->ipmi_io_res[0] = bus_alloc_resource_any(dev, type,
123d72a0786SJohn Baldwin &sc->ipmi_io_rid, RF_ACTIVE);
124d72a0786SJohn Baldwin sc->ipmi_io_type = type;
125d72a0786SJohn Baldwin sc->ipmi_io_spacing = 1;
126d72a0786SJohn Baldwin if (sc->ipmi_io_res[0] == NULL) {
127d72a0786SJohn Baldwin device_printf(dev, "couldn't configure I/O resource\n");
128d72a0786SJohn Baldwin return (ENXIO);
129d72a0786SJohn Baldwin }
130d72a0786SJohn Baldwin
131d72a0786SJohn Baldwin /* If we have multiple resources, allocate up to MAX_RES. */
132d72a0786SJohn Baldwin for (i = 1; i < MAX_RES; i++) {
133d72a0786SJohn Baldwin sc->ipmi_io_rid = i;
134d72a0786SJohn Baldwin sc->ipmi_io_res[i] = bus_alloc_resource_any(dev, type,
135d72a0786SJohn Baldwin &sc->ipmi_io_rid, RF_ACTIVE);
136d72a0786SJohn Baldwin if (sc->ipmi_io_res[i] == NULL)
137d72a0786SJohn Baldwin break;
138d72a0786SJohn Baldwin }
139d72a0786SJohn Baldwin sc->ipmi_io_rid = 0;
140d72a0786SJohn Baldwin
141d72a0786SJohn Baldwin /* If we have multiple resources, make sure we have enough of them. */
142d72a0786SJohn Baldwin if (sc->ipmi_io_res[1] != NULL && sc->ipmi_io_res[count - 1] == NULL) {
143d72a0786SJohn Baldwin device_printf(dev, "too few I/O resources\n");
144d72a0786SJohn Baldwin error = ENXIO;
145d72a0786SJohn Baldwin goto bad;
146d72a0786SJohn Baldwin }
147d72a0786SJohn Baldwin
148d72a0786SJohn Baldwin device_printf(dev, "%s mode found at %s 0x%jx on %s\n",
149d72a0786SJohn Baldwin mode, type == SYS_RES_IOPORT ? "io" : "mem",
150d72a0786SJohn Baldwin (uintmax_t)rman_get_start(sc->ipmi_io_res[0]),
151d72a0786SJohn Baldwin device_get_name(device_get_parent(dev)));
152d72a0786SJohn Baldwin
153d72a0786SJohn Baldwin sc->ipmi_dev = dev;
154d72a0786SJohn Baldwin
155d72a0786SJohn Baldwin /*
156d72a0786SJohn Baldwin * Setup an interrupt if we have an interrupt resource. We
157d72a0786SJohn Baldwin * don't support GPE interrupts via _GPE yet.
158d72a0786SJohn Baldwin */
159d72a0786SJohn Baldwin sc->ipmi_irq_rid = 0;
160d72a0786SJohn Baldwin sc->ipmi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
161d72a0786SJohn Baldwin &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE);
162d72a0786SJohn Baldwin
163d72a0786SJohn Baldwin /* Warn if _GPE exists. */
164d72a0786SJohn Baldwin if (ACPI_SUCCESS(AcpiEvaluateObject(devh, "_GPE", NULL, NULL)))
165d72a0786SJohn Baldwin device_printf(dev, "_GPE support not implemented\n");
166d72a0786SJohn Baldwin
167d72a0786SJohn Baldwin /*
168d72a0786SJohn Baldwin * We assume an alignment of 1 byte as currently the IPMI spec
169d72a0786SJohn Baldwin * doesn't provide any way to determine the alignment via ACPI.
170d72a0786SJohn Baldwin */
171*1f166509SAndrey V. Elsukov error = ENXIO;
172d72a0786SJohn Baldwin switch (interface_type) {
173d72a0786SJohn Baldwin case KCS_MODE:
174d72a0786SJohn Baldwin error = ipmi_kcs_attach(sc);
175d72a0786SJohn Baldwin break;
176d72a0786SJohn Baldwin case SMIC_MODE:
177d72a0786SJohn Baldwin error = ipmi_smic_attach(sc);
178*1f166509SAndrey V. Elsukov break;
179*1f166509SAndrey V. Elsukov case BT_MODE:
180*1f166509SAndrey V. Elsukov error = ipmi_bt_attach(sc);
181d72a0786SJohn Baldwin break;
182d72a0786SJohn Baldwin }
183*1f166509SAndrey V. Elsukov if (error)
184*1f166509SAndrey V. Elsukov goto bad;
185d72a0786SJohn Baldwin error = ipmi_attach(dev);
186d72a0786SJohn Baldwin if (error)
187d72a0786SJohn Baldwin goto bad;
188d72a0786SJohn Baldwin
189d72a0786SJohn Baldwin return (0);
190d72a0786SJohn Baldwin bad:
191d72a0786SJohn Baldwin ipmi_release_resources(dev);
192d72a0786SJohn Baldwin return (error);
193d72a0786SJohn Baldwin }
194d72a0786SJohn Baldwin
195d72a0786SJohn Baldwin static device_method_t ipmi_methods[] = {
196d72a0786SJohn Baldwin /* Device interface */
197d72a0786SJohn Baldwin DEVMETHOD(device_probe, ipmi_acpi_probe),
198d72a0786SJohn Baldwin DEVMETHOD(device_attach, ipmi_acpi_attach),
199d72a0786SJohn Baldwin DEVMETHOD(device_detach, ipmi_detach),
200d72a0786SJohn Baldwin { 0, 0 }
201d72a0786SJohn Baldwin };
202d72a0786SJohn Baldwin
203d72a0786SJohn Baldwin static driver_t ipmi_acpi_driver = {
204d72a0786SJohn Baldwin "ipmi",
205d72a0786SJohn Baldwin ipmi_methods,
206d72a0786SJohn Baldwin sizeof(struct ipmi_softc),
207d72a0786SJohn Baldwin };
208d72a0786SJohn Baldwin
209fd773e2bSJohn Baldwin DRIVER_MODULE(ipmi_acpi, acpi, ipmi_acpi_driver, 0, 0);
210d72a0786SJohn Baldwin MODULE_DEPEND(ipmi_acpi, acpi, 1, 1, 1);
211