1 /*- 2 * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/malloc.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/selinfo.h> 36 37 #include <sys/bus.h> 38 #include <sys/conf.h> 39 40 #include <machine/bus.h> 41 #include <machine/resource.h> 42 #include <sys/rman.h> 43 44 #include <dev/pci/pcireg.h> 45 #include <dev/pci/pcivar.h> 46 47 #ifdef LOCAL_MODULE 48 #include <ipmivars.h> 49 #else 50 #include <dev/ipmi/ipmivars.h> 51 #endif 52 53 static int ipmi_pci_probe(device_t dev); 54 static int ipmi_pci_attach(device_t dev); 55 static int ipmi_pci_detach(device_t dev); 56 57 static device_method_t ipmi_methods[] = { 58 /* Device interface */ 59 DEVMETHOD(device_probe, ipmi_pci_probe), 60 DEVMETHOD(device_attach, ipmi_pci_attach), 61 DEVMETHOD(device_detach, ipmi_pci_detach), 62 { 0, 0 } 63 }; 64 65 struct ipmi_ident 66 { 67 u_int16_t vendor; 68 u_int16_t device; 69 char *desc; 70 } ipmi_identifiers[] = { 71 {0x1028, 0x000d, "Dell PE2650 SMIC interface"}, 72 {0, 0, 0} 73 }; 74 75 static int 76 ipmi_pci_probe(device_t dev) { 77 struct ipmi_ident *m; 78 79 if (ipmi_attached) 80 return ENXIO; 81 82 for (m = ipmi_identifiers; m->vendor != 0; m++) { 83 if ((m->vendor == pci_get_vendor(dev)) && 84 (m->device == pci_get_device(dev))) { 85 device_set_desc(dev, m->desc); 86 return (BUS_PROBE_DEFAULT); 87 } 88 } 89 90 return ENXIO; 91 } 92 93 static int 94 ipmi_pci_attach(device_t dev) { 95 struct ipmi_softc *sc = device_get_softc(dev); 96 device_t parent, smbios_attach_dev = NULL; 97 devclass_t dc; 98 int status, flags; 99 int error; 100 101 102 /* 103 * We need to attach to something that can address the BIOS/ 104 * SMBIOS memory range. This is usually the isa bus however 105 * during a static kernel boot the isa bus is not available 106 * so we run up the tree to the nexus bus. A module load 107 * will use the isa bus attachment. If neither work bail 108 * since the SMBIOS defines stuff we need to know to attach to 109 * this device. 110 */ 111 dc = devclass_find("isa"); 112 if (dc != NULL) { 113 smbios_attach_dev = devclass_get_device(dc, 0); 114 } 115 116 if (smbios_attach_dev == NULL) { 117 smbios_attach_dev = dev; 118 for (;;) { 119 parent = device_get_parent(smbios_attach_dev); 120 if (parent == NULL) 121 break; 122 if (strcmp(device_get_name(smbios_attach_dev), 123 "nexus") == 0) 124 break; 125 smbios_attach_dev = parent; 126 } 127 } 128 129 if (smbios_attach_dev == NULL) { 130 device_printf(dev, "Couldn't find isa/nexus device\n"); 131 goto bad; 132 } 133 sc->ipmi_smbios_dev = ipmi_smbios_identify(NULL, smbios_attach_dev); 134 if (sc->ipmi_smbios_dev == NULL) { 135 device_printf(dev, "Couldn't find isa device\n"); 136 goto bad; 137 } 138 error = ipmi_smbios_probe(sc->ipmi_smbios_dev); 139 if (error != 0) { 140 goto bad; 141 } 142 sc->ipmi_dev = dev; 143 error = ipmi_smbios_query(dev); 144 device_delete_child(dev, sc->ipmi_smbios_dev); 145 if (error != 0) 146 goto bad; 147 148 /* Now we know about the IPMI attachment info. */ 149 if (sc->ipmi_bios_info.kcs_mode) { 150 if (sc->ipmi_bios_info.io_mode) 151 device_printf(dev, "KCS mode found at io 0x%llx " 152 "alignment 0x%x on %s\n", 153 (long long)sc->ipmi_bios_info.address, 154 sc->ipmi_bios_info.offset, 155 device_get_name(device_get_parent(sc->ipmi_dev))); 156 else 157 device_printf(dev, "KCS mode found at mem 0x%llx " 158 "alignment 0x%x on %s\n", 159 (long long)sc->ipmi_bios_info.address, 160 sc->ipmi_bios_info.offset, 161 device_get_name(device_get_parent(sc->ipmi_dev))); 162 163 sc->ipmi_kcs_status_reg = sc->ipmi_bios_info.offset; 164 sc->ipmi_kcs_command_reg = sc->ipmi_bios_info.offset; 165 sc->ipmi_kcs_data_out_reg = 0; 166 sc->ipmi_kcs_data_in_reg = 0; 167 168 if (sc->ipmi_bios_info.io_mode) { 169 sc->ipmi_io_rid = PCIR_BAR(0); 170 sc->ipmi_io_res = bus_alloc_resource(dev, 171 SYS_RES_IOPORT, &sc->ipmi_io_rid, 172 sc->ipmi_bios_info.address, 173 sc->ipmi_bios_info.address + 174 (sc->ipmi_bios_info.offset * 2), 175 sc->ipmi_bios_info.offset * 2, 176 RF_ACTIVE); 177 } else { 178 sc->ipmi_mem_rid = PCIR_BAR(0); 179 sc->ipmi_mem_res = bus_alloc_resource(dev, 180 SYS_RES_MEMORY, &sc->ipmi_mem_rid, 181 sc->ipmi_bios_info.address, 182 sc->ipmi_bios_info.address + 183 (sc->ipmi_bios_info.offset * 2), 184 sc->ipmi_bios_info.offset * 2, 185 RF_ACTIVE); 186 } 187 188 if (!sc->ipmi_io_res){ 189 device_printf(dev, "couldn't configure pci io res\n"); 190 goto bad; 191 } 192 193 status = INB(sc, sc->ipmi_kcs_status_reg); 194 if (status == 0xff) { 195 device_printf(dev, "couldn't find it\n"); 196 goto bad; 197 } 198 if(status & KCS_STATUS_OBF){ 199 ipmi_read(dev, NULL, 0); 200 } 201 } else if (sc->ipmi_bios_info.smic_mode) { 202 if (sc->ipmi_bios_info.io_mode) 203 device_printf(dev, "SMIC mode found at io 0x%llx " 204 "alignment 0x%x on %s\n", 205 (long long)sc->ipmi_bios_info.address, 206 sc->ipmi_bios_info.offset, 207 device_get_name(device_get_parent(sc->ipmi_dev))); 208 else 209 device_printf(dev, "SMIC mode found at mem 0x%llx " 210 "alignment 0x%x on %s\n", 211 (long long)sc->ipmi_bios_info.address, 212 sc->ipmi_bios_info.offset, 213 device_get_name(device_get_parent(sc->ipmi_dev))); 214 215 sc->ipmi_smic_data = 0; 216 sc->ipmi_smic_ctl_sts = sc->ipmi_bios_info.offset; 217 sc->ipmi_smic_flags = sc->ipmi_bios_info.offset * 2; 218 219 if (sc->ipmi_bios_info.io_mode) { 220 sc->ipmi_io_rid = PCIR_BAR(0); 221 sc->ipmi_io_res = bus_alloc_resource(dev, 222 SYS_RES_IOPORT, &sc->ipmi_io_rid, 223 sc->ipmi_bios_info.address, 224 sc->ipmi_bios_info.address + 225 (sc->ipmi_bios_info.offset * 3), 226 sc->ipmi_bios_info.offset * 3, 227 RF_ACTIVE); 228 } else { 229 sc->ipmi_mem_rid = PCIR_BAR(0); 230 sc->ipmi_mem_res = bus_alloc_resource(dev, 231 SYS_RES_MEMORY, &sc->ipmi_mem_rid, 232 sc->ipmi_bios_info.address, 233 sc->ipmi_bios_info.address + 234 (sc->ipmi_bios_info.offset * 2), 235 sc->ipmi_bios_info.offset * 2, 236 RF_ACTIVE); 237 } 238 239 if (!sc->ipmi_io_res && !sc->ipmi_mem_res){ 240 device_printf(dev, "couldn't configure pci res\n"); 241 goto bad; 242 } 243 244 flags = INB(sc, sc->ipmi_smic_flags); 245 if (flags == 0xff) { 246 device_printf(dev, "couldn't find it\n"); 247 goto bad; 248 } 249 if ((flags & SMIC_STATUS_SMS_ATN) 250 && (flags & SMIC_STATUS_RX_RDY)){ 251 ipmi_read(dev, NULL, 0); 252 } 253 } else { 254 device_printf(dev, "No IPMI interface found\n"); 255 goto bad; 256 } 257 ipmi_attach(dev); 258 259 sc->ipmi_irq_rid = 0; 260 sc->ipmi_irq_res = bus_alloc_resource_any(sc->ipmi_dev, SYS_RES_IRQ, 261 &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE); 262 if (sc->ipmi_irq_res == NULL) { 263 device_printf(sc->ipmi_dev, "can't allocate interrupt\n"); 264 } else { 265 if (bus_setup_intr(sc->ipmi_dev, sc->ipmi_irq_res, 266 INTR_TYPE_MISC, ipmi_intr, 267 sc->ipmi_dev, &sc->ipmi_irq)) { 268 device_printf(sc->ipmi_dev, 269 "can't set up interrupt\n"); 270 return (EINVAL); 271 } 272 } 273 274 return 0; 275 bad: 276 return ENXIO; 277 } 278 279 static int ipmi_pci_detach(device_t dev) { 280 struct ipmi_softc *sc; 281 282 sc = device_get_softc(dev); 283 ipmi_detach(dev); 284 if (sc->ipmi_ev_tag) 285 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_ev_tag); 286 287 if (sc->ipmi_mem_res) 288 bus_release_resource(dev, SYS_RES_MEMORY, sc->ipmi_mem_rid, 289 sc->ipmi_mem_res); 290 if (sc->ipmi_io_res) 291 bus_release_resource(dev, SYS_RES_IOPORT, sc->ipmi_io_rid, 292 sc->ipmi_io_res); 293 if (sc->ipmi_irq) 294 bus_teardown_intr(sc->ipmi_dev, sc->ipmi_irq_res, 295 sc->ipmi_irq); 296 if (sc->ipmi_irq_res) 297 bus_release_resource(sc->ipmi_dev, SYS_RES_IRQ, 298 sc->ipmi_irq_rid, sc->ipmi_irq_res); 299 300 return 0; 301 } 302 303 static driver_t ipmi_pci_driver = { 304 "ipmi", 305 ipmi_methods, 306 sizeof(struct ipmi_softc) 307 }; 308 309 DRIVER_MODULE(ipmi_foo, pci, ipmi_pci_driver, ipmi_devclass, 0, 0); 310