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 * $FreeBSD: head/sys/dev/ipmi/ipmi_pci.c 168162 2007-03-31 21:39:02Z jhb $ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/condvar.h> 33 #include <sys/eventhandler.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/rman.h> 37 #include <sys/conf.h> 38 39 #include <bus/pci/pcireg.h> 40 #include <bus/pci/pcivar.h> 41 42 #ifdef LOCAL_MODULE 43 #include <ipmivars.h> 44 #else 45 #include <dev/misc/ipmi/ipmivars.h> 46 #endif 47 48 static int ipmi_pci_probe(device_t dev); 49 static int ipmi_pci_attach(device_t dev); 50 51 static struct ipmi_ident 52 { 53 u_int16_t vendor; 54 u_int16_t device; 55 char *desc; 56 } ipmi_identifiers[] = { 57 {0x1028, 0x000d, "Dell PE2650 SMIC interface"}, 58 {0, 0, 0} 59 }; 60 61 const char * 62 ipmi_pci_match(uint16_t vendor, uint16_t device) 63 { 64 struct ipmi_ident *m; 65 66 for (m = ipmi_identifiers; m->vendor != 0; m++) 67 if (m->vendor == vendor && m->device == device) 68 return (m->desc); 69 return (NULL); 70 } 71 72 static int 73 ipmi_pci_probe(device_t dev) 74 { 75 const char *desc; 76 77 if (ipmi_attached) 78 return (ENXIO); 79 80 desc = ipmi_pci_match(pci_get_vendor(dev), pci_get_device(dev)); 81 if (desc != NULL) { 82 device_set_desc(dev, desc); 83 return (BUS_PROBE_DEFAULT); 84 } 85 86 return (ENXIO); 87 } 88 89 static int 90 ipmi_pci_attach(device_t dev) 91 { 92 struct ipmi_softc *sc = device_get_softc(dev); 93 struct ipmi_get_info info; 94 const char *mode; 95 int error, type; 96 97 /* Look for an IPMI entry in the SMBIOS table. */ 98 if (!ipmi_smbios_identify(&info)) 99 return (ENXIO); 100 101 sc->ipmi_dev = dev; 102 103 switch (info.iface_type) { 104 case KCS_MODE: 105 mode = "KCS"; 106 break; 107 case SMIC_MODE: 108 mode = "SMIC"; 109 break; 110 case BT_MODE: 111 device_printf(dev, "BT mode is unsupported\n"); 112 return (ENXIO); 113 default: 114 device_printf(dev, "No IPMI interface found\n"); 115 return (ENXIO); 116 } 117 118 device_printf(dev, "%s mode found at %s 0x%jx alignment 0x%x on %s\n", 119 mode, info.io_mode ? "io" : "mem", 120 (uintmax_t)info.address, info.offset, 121 device_get_name(device_get_parent(dev))); 122 if (info.io_mode) 123 type = SYS_RES_IOPORT; 124 else 125 type = SYS_RES_MEMORY; 126 127 sc->ipmi_io_rid = PCIR_BAR(0); 128 sc->ipmi_io_res[0] = bus_alloc_resource_any(dev, type, 129 &sc->ipmi_io_rid, RF_ACTIVE); 130 sc->ipmi_io_type = type; 131 sc->ipmi_io_spacing = info.offset; 132 133 if (sc->ipmi_io_res[0] == NULL) { 134 device_printf(dev, "couldn't configure pci io res\n"); 135 return (ENXIO); 136 } 137 138 sc->ipmi_irq_rid = 0; 139 sc->ipmi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 140 &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE); 141 142 switch (info.iface_type) { 143 case KCS_MODE: 144 error = ipmi_kcs_attach(sc); 145 if (error) 146 goto bad; 147 break; 148 case SMIC_MODE: 149 error = ipmi_smic_attach(sc); 150 if (error) 151 goto bad; 152 break; 153 } 154 error = ipmi_attach(dev); 155 if (error) 156 goto bad; 157 158 return (0); 159 bad: 160 ipmi_release_resources(dev); 161 return (error); 162 } 163 164 static device_method_t ipmi_methods[] = { 165 /* Device interface */ 166 DEVMETHOD(device_probe, ipmi_pci_probe), 167 DEVMETHOD(device_attach, ipmi_pci_attach), 168 DEVMETHOD(device_detach, ipmi_detach), 169 { 0, 0 } 170 }; 171 172 static driver_t ipmi_pci_driver = { 173 "ipmi", 174 ipmi_methods, 175 sizeof(struct ipmi_softc) 176 }; 177 178 DRIVER_MODULE(ipmi_pci, pci, ipmi_pci_driver, ipmi_devclass, 0, 0); 179 180 /* Native IPMI on PCI driver. */ 181 182 static int 183 ipmi2_pci_probe(device_t dev) 184 { 185 186 if (pci_get_class(dev) == PCIC_SERIALBUS && 187 pci_get_subclass(dev) == PCIS_SERIALBUS_IPMI) { 188 device_set_desc(dev, "IPMI System Interface"); 189 return (BUS_PROBE_GENERIC); 190 } 191 192 return (ENXIO); 193 } 194 195 static int 196 ipmi2_pci_attach(device_t dev) 197 { 198 struct ipmi_softc *sc; 199 int error, iface, type; 200 201 sc = device_get_softc(dev); 202 sc->ipmi_dev = dev; 203 204 /* Interface is determined by progif. */ 205 switch (pci_get_progif(dev)) { 206 case PCIP_SERIALBUS_IPMI_SMIC: 207 iface = SMIC_MODE; 208 break; 209 case PCIP_SERIALBUS_IPMI_KCS: 210 iface = KCS_MODE; 211 break; 212 case PCIP_SERIALBUS_IPMI_BT: 213 iface = BT_MODE; 214 device_printf(dev, "BT interface unsupported\n"); 215 return (ENXIO); 216 default: 217 device_printf(dev, "Unsupported interface: %d\n", 218 pci_get_progif(dev)); 219 return (ENXIO); 220 } 221 222 /* Check the BAR to determine our resource type. */ 223 sc->ipmi_io_rid = PCIR_BAR(0); 224 if (PCI_BAR_IO(pci_read_config(dev, PCIR_BAR(0), 4))) 225 type = SYS_RES_IOPORT; 226 else 227 type = SYS_RES_MEMORY; 228 sc->ipmi_io_type = type; 229 sc->ipmi_io_spacing = 1; 230 sc->ipmi_io_res[0] = bus_alloc_resource_any(dev, type, 231 &sc->ipmi_io_rid, RF_ACTIVE); 232 if (sc->ipmi_io_res[0] == NULL) { 233 device_printf(dev, "couldn't map ports/memory\n"); 234 return (ENXIO); 235 } 236 237 sc->ipmi_irq_rid = 0; 238 sc->ipmi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 239 &sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE); 240 241 switch (iface) { 242 case KCS_MODE: 243 device_printf(dev, "using KSC interface\n"); 244 245 /* 246 * We have to examine the resource directly to determine the 247 * alignment. 248 */ 249 if (!ipmi_kcs_probe_align(sc)) { 250 device_printf(dev, "Unable to determine alignment\n"); 251 error = ENXIO; 252 goto bad; 253 } 254 255 error = ipmi_kcs_attach(sc); 256 if (error) 257 goto bad; 258 break; 259 case SMIC_MODE: 260 device_printf(dev, "using SMIC interface\n"); 261 262 error = ipmi_smic_attach(sc); 263 if (error) 264 goto bad; 265 break; 266 } 267 error = ipmi_attach(dev); 268 if (error) 269 goto bad; 270 271 return (0); 272 bad: 273 ipmi_release_resources(dev); 274 return (error); 275 } 276 277 static device_method_t ipmi2_methods[] = { 278 /* Device interface */ 279 DEVMETHOD(device_probe, ipmi2_pci_probe), 280 DEVMETHOD(device_attach, ipmi2_pci_attach), 281 DEVMETHOD(device_detach, ipmi_detach), 282 { 0, 0 } 283 }; 284 285 static driver_t ipmi2_pci_driver = { 286 "ipmi", 287 ipmi2_methods, 288 sizeof(struct ipmi_softc) 289 }; 290 291 DRIVER_MODULE(ipmi2_pci, pci, ipmi2_pci_driver, ipmi_devclass, 0, 0); 292