1162562Sjhb/*-
2162562Sjhb * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3162562Sjhb * All rights reserved.
4162562Sjhb *
5162562Sjhb * Redistribution and use in source and binary forms, with or without
6162562Sjhb * modification, are permitted provided that the following conditions
7162562Sjhb * are met:
8162562Sjhb * 1. Redistributions of source code must retain the above copyright
9162562Sjhb *    notice, this list of conditions and the following disclaimer.
10162562Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11162562Sjhb *    notice, this list of conditions and the following disclaimer in the
12162562Sjhb *    documentation and/or other materials provided with the distribution.
13162562Sjhb *
14162562Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15162562Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16162562Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17162562Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18162562Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19162562Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20162562Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21162562Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22162562Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23162562Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24162562Sjhb * SUCH DAMAGE.
25162562Sjhb */
26162562Sjhb
27162562Sjhb#include <sys/cdefs.h>
28162562Sjhb__FBSDID("$FreeBSD$");
29162562Sjhb
30162562Sjhb#include <sys/param.h>
31162562Sjhb#include <sys/systm.h>
32162562Sjhb#include <sys/bus.h>
33162562Sjhb#include <sys/condvar.h>
34162562Sjhb#include <sys/eventhandler.h>
35162562Sjhb#include <sys/kernel.h>
36162562Sjhb#include <sys/module.h>
37162562Sjhb#include <sys/rman.h>
38162562Sjhb#include <sys/selinfo.h>
39162562Sjhb
40162562Sjhb#include <dev/smbus/smbconf.h>
41162562Sjhb#include <dev/smbus/smbus.h>
42162562Sjhb#include <dev/smbus/smb.h>
43162562Sjhb
44162562Sjhb#include "smbus_if.h"
45162562Sjhb
46162562Sjhb#ifdef LOCAL_MODULE
47162562Sjhb#include <ipmivars.h>
48162562Sjhb#else
49162562Sjhb#include <dev/ipmi/ipmivars.h>
50162562Sjhb#endif
51162562Sjhb
52162562Sjhbstatic void ipmi_smbus_identify(driver_t *driver, device_t parent);
53162562Sjhbstatic int ipmi_smbus_probe(device_t dev);
54162562Sjhbstatic int ipmi_smbus_attach(device_t dev);
55162562Sjhb
56162562Sjhbstatic void
57162562Sjhbipmi_smbus_identify(driver_t *driver, device_t parent)
58162562Sjhb{
59162562Sjhb	struct ipmi_get_info info;
60162562Sjhb
61162562Sjhb	if (ipmi_smbios_identify(&info) && info.iface_type == SSIF_MODE &&
62162562Sjhb	    device_find_child(parent, "ipmi", -1) == NULL)
63162562Sjhb		BUS_ADD_CHILD(parent, 0, "ipmi", -1);
64162562Sjhb}
65162562Sjhb
66162562Sjhbstatic int
67162562Sjhbipmi_smbus_probe(device_t dev)
68162562Sjhb{
69162562Sjhb
70162562Sjhb	device_set_desc(dev, "IPMI System Interface");
71162562Sjhb	return (BUS_PROBE_DEFAULT);
72162562Sjhb}
73162562Sjhb
74162562Sjhbstatic int
75162562Sjhbipmi_smbus_attach(device_t dev)
76162562Sjhb{
77162562Sjhb	struct ipmi_softc *sc = device_get_softc(dev);
78162562Sjhb	struct ipmi_get_info info;
79162562Sjhb	int error;
80162562Sjhb
81162562Sjhb	/* This should never fail. */
82162562Sjhb	if (!ipmi_smbios_identify(&info))
83162562Sjhb		return (ENXIO);
84162562Sjhb
85162562Sjhb	if (info.iface_type != SSIF_MODE) {
86162562Sjhb		device_printf(dev, "No SSIF IPMI interface found\n");
87162562Sjhb		return (ENXIO);
88162562Sjhb	}
89162562Sjhb
90162562Sjhb	sc->ipmi_dev = dev;
91162562Sjhb
92162562Sjhb	if (info.irq != 0) {
93162562Sjhb		sc->ipmi_irq_rid = 0;
94162562Sjhb		sc->ipmi_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ,
95162562Sjhb		    &sc->ipmi_irq_rid, info.irq, info.irq, 1,
96162562Sjhb		    RF_SHAREABLE | RF_ACTIVE);
97162562Sjhb	}
98162562Sjhb
99162562Sjhb	device_printf(dev, "SSIF mode found at address 0x%llx on %s\n",
100162562Sjhb	    (long long)info.address, device_get_name(device_get_parent(dev)));
101162562Sjhb	error = ipmi_ssif_attach(sc, device_get_parent(dev), info.address);
102162562Sjhb	if (error)
103162562Sjhb		goto bad;
104162562Sjhb
105162562Sjhb	error = ipmi_attach(dev);
106162562Sjhb	if (error)
107162562Sjhb		goto bad;
108162562Sjhb
109162562Sjhb	return (0);
110162562Sjhbbad:
111162562Sjhb	ipmi_release_resources(dev);
112162562Sjhb	return (error);
113162562Sjhb}
114162562Sjhb
115162562Sjhbstatic device_method_t ipmi_methods[] = {
116162562Sjhb	/* Device interface */
117162562Sjhb	DEVMETHOD(device_identify,	ipmi_smbus_identify),
118162562Sjhb	DEVMETHOD(device_probe,		ipmi_smbus_probe),
119162562Sjhb	DEVMETHOD(device_attach,	ipmi_smbus_attach),
120162562Sjhb	DEVMETHOD(device_detach,	ipmi_detach),
121162562Sjhb	{ 0, 0 }
122162562Sjhb};
123162562Sjhb
124162562Sjhbstatic driver_t ipmi_smbus_driver = {
125162562Sjhb	"ipmi",
126162562Sjhb	ipmi_methods,
127162562Sjhb	sizeof(struct ipmi_softc)
128162562Sjhb};
129162562Sjhb
130162562SjhbDRIVER_MODULE(ipmi_smbus, smbus, ipmi_smbus_driver, ipmi_devclass, 0, 0);
131162562SjhbMODULE_DEPEND(ipmi_smbus, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
132