ipmi_pci.c revision 155517
115177Snate/*- 215284Snate * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 315284Snate * All rights reserved. 415284Snate * 515284Snate * Redistribution and use in source and binary forms, with or without 615284Snate * modification, are permitted provided that the following conditions 715284Snate * are met: 815284Snate * 1. Redistributions of source code must retain the above copyright 915284Snate * notice, this list of conditions and the following disclaimer. 1015284Snate * 2. Redistributions in binary form must reproduce the above copyright 1115284Snate * notice, this list of conditions and the following disclaimer in the 1215284Snate * documentation and/or other materials provided with the distribution. 1315284Snate * 1415284Snate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1515284Snate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1615284Snate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1715284Snate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1815284Snate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1915284Snate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2015284Snate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2115284Snate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2215284Snate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2315284Snate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2415284Snate * SUCH DAMAGE. 2510217Sphk */ 2630171Scharnier 2730171Scharnier#include <sys/cdefs.h> 2830171Scharnier__FBSDID("$FreeBSD: head/sys/dev/ipmi/ipmi_pci.c 155517 2006-02-10 20:51:35Z ambrisko $"); 2935310Snate 3030171Scharnier#include <sys/param.h> 3130171Scharnier#include <sys/malloc.h> 3230171Scharnier#include <sys/systm.h> 3310217Sphk#include <sys/kernel.h> 3410217Sphk#include <sys/module.h> 3510217Sphk#include <sys/selinfo.h> 3630171Scharnier 3710217Sphk#include <sys/bus.h> 3810217Sphk#include <sys/conf.h> 3931290Snate 4010217Sphk#include <machine/bus.h> 4110217Sphk#include <machine/resource.h> 4210217Sphk#include <sys/rman.h> 4310217Sphk 4416487Snate#include <dev/pci/pcireg.h> 4516487Snate#include <dev/pci/pcivar.h> 4616487Snate 4716487Snate#ifdef LOCAL_MODULE 4816487Snate#include <ipmivars.h> 4916487Snate#else 5016487Snate#include <dev/ipmi/ipmivars.h> 5116487Snate#endif 5216487Snate 5316487Snatestatic int ipmi_pci_probe(device_t dev); 5410217Sphkstatic int ipmi_pci_attach(device_t dev); 5516487Snatestatic int ipmi_pci_detach(device_t dev); 5615177Snate 5715177Snatestatic device_method_t ipmi_methods[] = { 5815177Snate /* Device interface */ 5915177Snate DEVMETHOD(device_probe, ipmi_pci_probe), 6015177Snate DEVMETHOD(device_attach, ipmi_pci_attach), 6115177Snate DEVMETHOD(device_detach, ipmi_pci_detach), 6215177Snate { 0, 0 } 6315177Snate}; 6415177Snate 6515177Snatestruct ipmi_ident 6615177Snate{ 6715177Snate u_int16_t vendor; 6815177Snate u_int16_t device; 6915177Snate char *desc; 7015177Snate} ipmi_identifiers[] = { 7115177Snate {0x1028, 0x000d, "Dell PE2650 SMIC interface"}, 7215177Snate {0, 0, 0} 7315177Snate}; 7415177Snate 7515177Snatestatic int 7615177Snateipmi_pci_probe(device_t dev) { 7715177Snate struct ipmi_ident *m; 7815177Snate 7915177Snate if (ipmi_attached) 8015177Snate return ENXIO; 8115177Snate 8215177Snate for (m = ipmi_identifiers; m->vendor != 0; m++) { 8315177Snate if ((m->vendor == pci_get_vendor(dev)) && 8415177Snate (m->device == pci_get_device(dev))) { 8515177Snate device_set_desc(dev, m->desc); 8615177Snate return (BUS_PROBE_DEFAULT); 8715177Snate } 8810217Sphk } 8910217Sphk 9010217Sphk return ENXIO; 9110217Sphk} 9210217Sphk 9310217Sphkstatic int 9410217Sphkipmi_pci_attach(device_t dev) { 9515177Snate struct ipmi_softc *sc = device_get_softc(dev); 9615177Snate device_t parent, smbios_attach_dev = NULL; 9715177Snate devclass_t dc; 9810217Sphk int status, flags; 9910217Sphk int error; 10010217Sphk 10110217Sphk 10215177Snate /* 10310217Sphk * We need to attach to something that can address the BIOS/ 10410217Sphk * SMBIOS memory range. This is usually the isa bus however 10515177Snate * during a static kernel boot the isa bus is not available 10610217Sphk * so we run up the tree to the nexus bus. A module load 10715177Snate * will use the isa bus attachment. If neither work bail 10815177Snate * since the SMBIOS defines stuff we need to know to attach to 10910217Sphk * this device. 11015177Snate */ 11115177Snate dc = devclass_find("isa"); 11215177Snate if (dc != NULL) { 11315177Snate smbios_attach_dev = devclass_get_device(dc, 0); 11415177Snate } 11515177Snate 11615177Snate if (smbios_attach_dev == NULL) { 11715177Snate smbios_attach_dev = dev; 11815177Snate for (;;) { 11915177Snate parent = device_get_parent(smbios_attach_dev); 12015177Snate if (parent == NULL) 12115177Snate break; 12215177Snate if (strcmp(device_get_name(smbios_attach_dev), 12315177Snate "nexus") == 0) 12415177Snate break; 12515177Snate smbios_attach_dev = parent; 12610217Sphk } 12710217Sphk } 12815177Snate 12910217Sphk if (smbios_attach_dev == NULL) { 13015177Snate device_printf(dev, "Couldn't find isa/nexus device\n"); 13110217Sphk goto bad; 13210217Sphk } 13310217Sphk sc->ipmi_smbios_dev = ipmi_smbios_identify(NULL, smbios_attach_dev); 13410217Sphk if (sc->ipmi_smbios_dev == NULL) { 13510217Sphk device_printf(dev, "Couldn't find isa device\n"); 13610217Sphk goto bad; 13715177Snate } 13815177Snate error = ipmi_smbios_probe(sc->ipmi_smbios_dev); 13915177Snate if (error != 0) { 14015177Snate goto bad; 14115177Snate } 14210217Sphk sc->ipmi_dev = dev; 14315177Snate error = ipmi_smbios_query(dev); 14410217Sphk device_delete_child(dev, sc->ipmi_smbios_dev); 14515177Snate if (error != 0) 14610217Sphk goto bad; 14710217Sphk 14810217Sphk /* Now we know about the IPMI attachment info. */ 14910217Sphk if (sc->ipmi_bios_info.kcs_mode) { 15015177Snate if (sc->ipmi_bios_info.io_mode) 15110217Sphk device_printf(dev, "KCS mode found at io 0x%llx " 15215177Snate "alignment 0x%x on %s\n", 15310217Sphk (long long)sc->ipmi_bios_info.address, 15415177Snate sc->ipmi_bios_info.offset, 15510217Sphk device_get_name(device_get_parent(sc->ipmi_dev))); 15610217Sphk else 15715177Snate device_printf(dev, "KCS mode found at mem 0x%llx " 15815177Snate "alignment 0x%x on %s\n", 15910217Sphk (long long)sc->ipmi_bios_info.address, 16010217Sphk sc->ipmi_bios_info.offset, 16115177Snate device_get_name(device_get_parent(sc->ipmi_dev))); 16210217Sphk 16315177Snate sc->ipmi_kcs_status_reg = sc->ipmi_bios_info.offset; 16410217Sphk sc->ipmi_kcs_command_reg = sc->ipmi_bios_info.offset; 16510217Sphk sc->ipmi_kcs_data_out_reg = 0; 16615177Snate sc->ipmi_kcs_data_in_reg = 0; 16710217Sphk 16810217Sphk if (sc->ipmi_bios_info.io_mode) { 16910217Sphk sc->ipmi_io_rid = PCIR_BAR(0); 17016487Snate sc->ipmi_io_res = bus_alloc_resource(dev, 17110217Sphk SYS_RES_IOPORT, &sc->ipmi_io_rid, 17210217Sphk sc->ipmi_bios_info.address, 17334699Shosokawa sc->ipmi_bios_info.address + 17410217Sphk (sc->ipmi_bios_info.offset * 2), 17510217Sphk sc->ipmi_bios_info.offset * 2, 17634699Shosokawa RF_ACTIVE); 17716466Snate } else { 17815177Snate sc->ipmi_mem_rid = PCIR_BAR(0); 17934699Shosokawa sc->ipmi_mem_res = bus_alloc_resource(dev, 18016466Snate SYS_RES_MEMORY, &sc->ipmi_mem_rid, 18115177Snate sc->ipmi_bios_info.address, 18234699Shosokawa sc->ipmi_bios_info.address + 18316466Snate (sc->ipmi_bios_info.offset * 2), 18415177Snate sc->ipmi_bios_info.offset * 2, 18534699Shosokawa RF_ACTIVE); 18616466Snate } 18710217Sphk 18815177Snate if (!sc->ipmi_io_res){ 18910217Sphk device_printf(dev, "couldn't configure pci io res\n"); 19010217Sphk goto bad; 19110217Sphk } 19216487Snate 19310255Sphk status = INB(sc, sc->ipmi_kcs_status_reg); 19410217Sphk if (status == 0xff) { 19515177Snate device_printf(dev, "couldn't find it\n"); 19610217Sphk goto bad; 19710217Sphk } 19810217Sphk if(status & KCS_STATUS_OBF){ 19910217Sphk ipmi_read(dev, NULL, 0); 20010217Sphk } 20115177Snate } else if (sc->ipmi_bios_info.smic_mode) { 20210217Sphk if (sc->ipmi_bios_info.io_mode) 20310217Sphk device_printf(dev, "SMIC mode found at io 0x%llx " 20415177Snate "alignment 0x%x on %s\n", 20510217Sphk (long long)sc->ipmi_bios_info.address, 20610217Sphk sc->ipmi_bios_info.offset, 20715177Snate device_get_name(device_get_parent(sc->ipmi_dev))); 20810217Sphk else 20915177Snate device_printf(dev, "SMIC mode found at mem 0x%llx " 21010217Sphk "alignment 0x%x on %s\n", 21110217Sphk (long long)sc->ipmi_bios_info.address, 21210217Sphk sc->ipmi_bios_info.offset, 21316487Snate device_get_name(device_get_parent(sc->ipmi_dev))); 21410255Sphk 21510217Sphk sc->ipmi_smic_data = 0; 21615177Snate sc->ipmi_smic_ctl_sts = sc->ipmi_bios_info.offset; 21715177Snate sc->ipmi_smic_flags = sc->ipmi_bios_info.offset * 2; 21815177Snate 21915177Snate if (sc->ipmi_bios_info.io_mode) { 22015177Snate sc->ipmi_io_rid = PCIR_BAR(0); 22115177Snate sc->ipmi_io_res = bus_alloc_resource(dev, 22210217Sphk SYS_RES_IOPORT, &sc->ipmi_io_rid, 22310217Sphk sc->ipmi_bios_info.address, 22410217Sphk sc->ipmi_bios_info.address + 22510217Sphk (sc->ipmi_bios_info.offset * 3), 22615177Snate sc->ipmi_bios_info.offset * 3, 22710217Sphk RF_ACTIVE); 22810217Sphk } else { 22910217Sphk sc->ipmi_mem_rid = PCIR_BAR(0); 23010217Sphk sc->ipmi_mem_res = bus_alloc_resource(dev, 23115177Snate SYS_RES_MEMORY, &sc->ipmi_mem_rid, 23210217Sphk sc->ipmi_bios_info.address, 23310217Sphk sc->ipmi_bios_info.address + 23410217Sphk (sc->ipmi_bios_info.offset * 2), 23516487Snate sc->ipmi_bios_info.offset * 2, 23610255Sphk RF_ACTIVE); 23710217Sphk } 23815177Snate 23915177Snate if (!sc->ipmi_io_res && !sc->ipmi_mem_res){ 24015177Snate device_printf(dev, "couldn't configure pci res\n"); 24115177Snate goto bad; 24215177Snate } 24315177Snate 24415177Snate flags = INB(sc, sc->ipmi_smic_flags); 24515177Snate if (flags == 0xff) { 24615177Snate device_printf(dev, "couldn't find it\n"); 24715177Snate goto bad; 24810217Sphk } 24910217Sphk if ((flags & SMIC_STATUS_SMS_ATN) 25015177Snate && (flags & SMIC_STATUS_RX_RDY)){ 25110217Sphk ipmi_read(dev, NULL, 0); 25210217Sphk } 25310217Sphk } else { 25415177Snate device_printf(dev, "No IPMI interface found\n"); 25510217Sphk goto bad; 25610217Sphk } 25710217Sphk ipmi_attach(dev); 25810217Sphk 25910217Sphk sc->ipmi_irq_rid = 0; 26010217Sphk sc->ipmi_irq_res = bus_alloc_resource_any(sc->ipmi_dev, SYS_RES_IRQ, 26110217Sphk &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE); 26215177Snate if (sc->ipmi_irq_res == NULL) { 26310217Sphk device_printf(sc->ipmi_dev, "can't allocate interrupt\n"); 26410217Sphk } else { 26510217Sphk if (bus_setup_intr(sc->ipmi_dev, sc->ipmi_irq_res, 26610217Sphk INTR_TYPE_MISC, ipmi_intr, 26710217Sphk sc->ipmi_dev, &sc->ipmi_irq)) { 26815177Snate device_printf(sc->ipmi_dev, 26915177Snate "can't set up interrupt\n"); 27015177Snate return (EINVAL); 27110217Sphk } 27210217Sphk } 27310217Sphk 27410217Sphk return 0; 27510217Sphkbad: 27610217Sphk return ENXIO; 27710217Sphk} 27810217Sphk 27915177Snatestatic int ipmi_pci_detach(device_t dev) { 28015177Snate struct ipmi_softc *sc; 28110217Sphk 28210217Sphk sc = device_get_softc(dev); 28315177Snate ipmi_detach(dev); 28410217Sphk if (sc->ipmi_ev_tag) 28510217Sphk EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_ev_tag); 28615177Snate 28710217Sphk if (sc->ipmi_mem_res) 28810217Sphk bus_release_resource(dev, SYS_RES_MEMORY, sc->ipmi_mem_rid, 28910217Sphk sc->ipmi_mem_res); 29015177Snate if (sc->ipmi_io_res) 29110217Sphk bus_release_resource(dev, SYS_RES_IOPORT, sc->ipmi_io_rid, 29210217Sphk sc->ipmi_io_res); 29310217Sphk if (sc->ipmi_irq) 29410217Sphk bus_teardown_intr(sc->ipmi_dev, sc->ipmi_irq_res, 29510217Sphk sc->ipmi_irq); 29610217Sphk if (sc->ipmi_irq_res) 29710217Sphk bus_release_resource(sc->ipmi_dev, SYS_RES_IRQ, 29815177Snate sc->ipmi_irq_rid, sc->ipmi_irq_res); 29910217Sphk 30010217Sphk return 0; 30110217Sphk} 30210217Sphk 30310217Sphkstatic driver_t ipmi_pci_driver = { 30410217Sphk "ipmi", 30510217Sphk ipmi_methods, 30610217Sphk sizeof(struct ipmi_softc) 30710217Sphk}; 30810217Sphk 30910217SphkDRIVER_MODULE(ipmi_foo, pci, ipmi_pci_driver, ipmi_devclass, 0, 0); 31010217Sphk