ipmi_acpi.c revision 193530
1133808Spjd/*- 2133808Spjd * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 3133808Spjd * All rights reserved. 4133808Spjd * 5133808Spjd * Redistribution and use in source and binary forms, with or without 6133808Spjd * modification, are permitted provided that the following conditions 7133808Spjd * are met: 8133808Spjd * 1. Redistributions of source code must retain the above copyright 9133808Spjd * notice, this list of conditions and the following disclaimer. 10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright 11133808Spjd * notice, this list of conditions and the following disclaimer in the 12133808Spjd * documentation and/or other materials provided with the distribution. 13133808Spjd * 14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133808Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133808Spjd * SUCH DAMAGE. 25133808Spjd */ 26133808Spjd 27133808Spjd#include <sys/cdefs.h> 28133808Spjd__FBSDID("$FreeBSD: head/sys/dev/ipmi/ipmi_acpi.c 193530 2009-06-05 18:44:36Z jkim $"); 29133808Spjd 30133808Spjd#include <sys/param.h> 31133808Spjd#include <sys/systm.h> 32133808Spjd#include <sys/bus.h> 33133808Spjd#include <sys/condvar.h> 34133808Spjd#include <sys/kernel.h> 35133808Spjd#include <sys/module.h> 36133808Spjd#include <sys/rman.h> 37133808Spjd#include <sys/selinfo.h> 38133808Spjd 39133808Spjd#include <contrib/dev/acpica/include/acpi.h> 40133808Spjd 41133808Spjd#include <dev/acpica/acpivar.h> 42133808Spjd 43133808Spjd/* Hooks for the ACPI CA debugging infrastructure */ 44133808Spjd#define _COMPONENT ACPI_BUTTON 45133808SpjdACPI_MODULE_NAME("IPMI") 46133808Spjd 47133808Spjd#ifdef LOCAL_MODULE 48133808Spjd#include <ipmi.h> 49133808Spjd#include <ipmivars.h> 50133808Spjd#else 51133808Spjd#include <sys/ipmi.h> 52133808Spjd#include <dev/ipmi/ipmivars.h> 53133808Spjd#endif 54133808Spjd 55133808Spjdstatic int ipmi_acpi_probe(device_t); 56133808Spjdstatic int ipmi_acpi_attach(device_t); 57133808Spjd 58133808Spjdint 59133808Spjdipmi_acpi_probe(device_t dev) 60133808Spjd{ 61134124Spjd static char *ipmi_ids[] = {"IPI0001", NULL}; 62134124Spjd 63134168Spjd if (ipmi_attached) 64134168Spjd return (EBUSY); 65133808Spjd 66133808Spjd if (acpi_disabled("ipmi") || 67133808Spjd ACPI_ID_PROBE(device_get_parent(dev), dev, ipmi_ids) == NULL) 68133808Spjd return (ENXIO); 69133808Spjd 70133808Spjd device_set_desc(dev, "IPMI System Interface"); 71133808Spjd 72133808Spjd return (0); 73133808Spjd} 74133808Spjd 75133808Spjdstatic int 76133808Spjdipmi_acpi_attach(device_t dev) 77133808Spjd{ 78133808Spjd ACPI_HANDLE devh; 79133808Spjd const char *mode; 80134124Spjd struct ipmi_get_info info; 81134168Spjd struct ipmi_softc *sc = device_get_softc(dev); 82133808Spjd int count, error, flags, i, type; 83133808Spjd int interface_type = 0, interface_version = 0; 84133808Spjd 85133808Spjd error = 0; 86133808Spjd devh = acpi_get_handle(dev); 87133808Spjd if (ACPI_FAILURE(acpi_GetInteger(devh, "_IFT", &interface_type))) 88133808Spjd return (ENXIO); 89133808Spjd 90133808Spjd if (ACPI_FAILURE(acpi_GetInteger(devh, "_SRV", &interface_version))) 91133808Spjd return (ENXIO); 92133808Spjd 93133808Spjd switch (interface_type) { 94133808Spjd case KCS_MODE: 95133808Spjd count = 2; 96133808Spjd mode = "KCS"; 97133808Spjd break; 98133808Spjd case SMIC_MODE: 99133808Spjd count = 3; 100133808Spjd mode = "SMIC"; 101133808Spjd break; 102133808Spjd case BT_MODE: 103133808Spjd device_printf(dev, "BT interface not supported\n"); 104133808Spjd return (ENXIO); 105133808Spjd case SSIF_MODE: 106133808Spjd if (ACPI_FAILURE(acpi_GetInteger(devh, "_ADR", &flags))) 107133808Spjd return (ENXIO); 108134168Spjd info.address = flags; 109133808Spjd device_printf(dev, "SSIF interface not supported on ACPI\n"); 110133808Spjd return (0); 111134168Spjd default: 112133808Spjd return (ENXIO); 113133808Spjd } 114133808Spjd 115133960Spjd if (bus_get_resource(dev, SYS_RES_IOPORT, 0, NULL, NULL) == 0) 116133808Spjd type = SYS_RES_IOPORT; 117133808Spjd else if (bus_get_resource(dev, SYS_RES_MEMORY, 0, NULL, NULL) == 0) 118133808Spjd type = SYS_RES_MEMORY; 119133808Spjd else { 120133808Spjd device_printf(dev, "unknown resource type\n"); 121133808Spjd return (ENXIO); 122133808Spjd } 123133808Spjd 124133808Spjd sc->ipmi_io_rid = 0; 125133808Spjd sc->ipmi_io_res[0] = bus_alloc_resource_any(dev, type, 126133808Spjd &sc->ipmi_io_rid, RF_ACTIVE); 127133808Spjd sc->ipmi_io_type = type; 128133808Spjd sc->ipmi_io_spacing = 1; 129133808Spjd if (sc->ipmi_io_res[0] == NULL) { 130133808Spjd device_printf(dev, "couldn't configure I/O resource\n"); 131133808Spjd return (ENXIO); 132133808Spjd } 133133808Spjd 134133808Spjd /* If we have multiple resources, allocate up to MAX_RES. */ 135133808Spjd for (i = 1; i < MAX_RES; i++) { 136133808Spjd sc->ipmi_io_rid = i; 137133808Spjd sc->ipmi_io_res[i] = bus_alloc_resource_any(dev, type, 138133808Spjd &sc->ipmi_io_rid, RF_ACTIVE); 139133808Spjd if (sc->ipmi_io_res[i] == NULL) 140133808Spjd break; 141133808Spjd } 142133808Spjd sc->ipmi_io_rid = 0; 143133808Spjd 144133808Spjd /* If we have multiple resources, make sure we have enough of them. */ 145133808Spjd if (sc->ipmi_io_res[1] != NULL && sc->ipmi_io_res[count - 1] == NULL) { 146133808Spjd device_printf(dev, "too few I/O resources\n"); 147133808Spjd error = ENXIO; 148133808Spjd goto bad; 149133808Spjd } 150134168Spjd 151134124Spjd device_printf(dev, "%s mode found at %s 0x%jx on %s\n", 152134420Spjd mode, type == SYS_RES_IOPORT ? "io" : "mem", 153134420Spjd (uintmax_t)rman_get_start(sc->ipmi_io_res[0]), 154133808Spjd device_get_name(device_get_parent(dev))); 155133808Spjd 156133808Spjd sc->ipmi_dev = dev; 157133808Spjd 158133808Spjd /* 159133808Spjd * Setup an interrupt if we have an interrupt resource. We 160133808Spjd * don't support GPE interrupts via _GPE yet. 161133808Spjd */ 162133808Spjd sc->ipmi_irq_rid = 0; 163133808Spjd sc->ipmi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 164133808Spjd &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE); 165133808Spjd 166133808Spjd /* Warn if _GPE exists. */ 167133808Spjd if (ACPI_SUCCESS(AcpiEvaluateObject(devh, "_GPE", NULL, NULL))) 168133808Spjd device_printf(dev, "_GPE support not implemented\n"); 169133808Spjd 170133808Spjd /* 171133808Spjd * We assume an alignment of 1 byte as currently the IPMI spec 172133808Spjd * doesn't provide any way to determine the alignment via ACPI. 173133808Spjd */ 174133808Spjd switch (interface_type) { 175133808Spjd case KCS_MODE: 176133808Spjd error = ipmi_kcs_attach(sc); 177133808Spjd if (error) 178133808Spjd goto bad; 179133808Spjd break; 180133808Spjd case SMIC_MODE: 181133808Spjd error = ipmi_smic_attach(sc); 182133808Spjd if (error) 183133808Spjd goto bad; 184133808Spjd break; 185133808Spjd } 186133808Spjd error = ipmi_attach(dev); 187133808Spjd if (error) 188133808Spjd goto bad; 189133808Spjd 190133808Spjd return (0); 191133808Spjdbad: 192133808Spjd ipmi_release_resources(dev); 193133808Spjd return (error); 194134124Spjd} 195134124Spjd 196134124Spjdstatic device_method_t ipmi_methods[] = { 197134124Spjd /* Device interface */ 198134124Spjd DEVMETHOD(device_probe, ipmi_acpi_probe), 199134124Spjd DEVMETHOD(device_attach, ipmi_acpi_attach), 200134124Spjd DEVMETHOD(device_detach, ipmi_detach), 201134168Spjd { 0, 0 } 202134168Spjd}; 203134168Spjd 204134168Spjdstatic driver_t ipmi_acpi_driver = { 205134168Spjd "ipmi", 206134168Spjd ipmi_methods, 207134168Spjd sizeof(struct ipmi_softc), 208134168Spjd}; 209134168Spjd 210134168SpjdDRIVER_MODULE(ipmi_acpi, acpi, ipmi_acpi_driver, ipmi_devclass, 0, 0); 211134168SpjdMODULE_DEPEND(ipmi_acpi, acpi, 1, 1, 1); 212133808Spjd