1 /*- 2 * Copyright (c) 2003-2008 M. Warner Losh. All Rights Reserved. 3 * Copyright (c) 2000,2001 Jonathan Chen. 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/systm.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/kernel.h> 35 #include <sys/sysctl.h> 36 37 #include <sys/bus.h> 38 #include <machine/bus.h> 39 #include <sys/rman.h> 40 #include <machine/resource.h> 41 42 #include <sys/pciio.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcireg.h> 45 #include <dev/pci/pci_private.h> 46 47 #include <dev/cardbus/cardbusreg.h> 48 #include <dev/cardbus/cardbusvar.h> 49 #include <dev/cardbus/cardbus_cis.h> 50 #include <dev/pccard/pccard_cis.h> 51 #include <dev/pccard/pccardvar.h> 52 53 #include "power_if.h" 54 #include "pcib_if.h" 55 56 /* sysctl vars */ 57 SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters"); 58 59 int cardbus_debug = 0; 60 TUNABLE_INT("hw.cardbus.debug", &cardbus_debug); 61 SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW, 62 &cardbus_debug, 0, 63 "CardBus debug"); 64 65 int cardbus_cis_debug = 0; 66 TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug); 67 SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW, 68 &cardbus_cis_debug, 0, 69 "CardBus CIS debug"); 70 71 #define DPRINTF(a) if (cardbus_debug) printf a 72 #define DEVPRINTF(x) if (cardbus_debug) device_printf x 73 74 static int cardbus_attach(device_t cbdev); 75 static int cardbus_attach_card(device_t cbdev); 76 static int cardbus_detach(device_t cbdev); 77 static int cardbus_detach_card(device_t cbdev); 78 static void cardbus_device_setup_regs(pcicfgregs *cfg); 79 static void cardbus_driver_added(device_t cbdev, driver_t *driver); 80 static int cardbus_probe(device_t cbdev); 81 static int cardbus_read_ivar(device_t cbdev, device_t child, int which, 82 uintptr_t *result); 83 84 /************************************************************************/ 85 /* Probe/Attach */ 86 /************************************************************************/ 87 88 static int 89 cardbus_probe(device_t cbdev) 90 { 91 device_set_desc(cbdev, "CardBus bus"); 92 return (0); 93 } 94 95 static int 96 cardbus_attach(device_t cbdev) 97 { 98 struct cardbus_softc *sc; 99 100 sc = device_get_softc(cbdev); 101 sc->sc_dev = cbdev; 102 return (0); 103 } 104 105 static int 106 cardbus_detach(device_t cbdev) 107 { 108 109 cardbus_detach_card(cbdev); 110 return (0); 111 } 112 113 static int 114 cardbus_suspend(device_t self) 115 { 116 117 cardbus_detach_card(self); 118 return (0); 119 } 120 121 static int 122 cardbus_resume(device_t self) 123 { 124 125 return (0); 126 } 127 128 /************************************************************************/ 129 /* Attach/Detach card */ 130 /************************************************************************/ 131 132 static void 133 cardbus_device_setup_regs(pcicfgregs *cfg) 134 { 135 device_t dev = cfg->dev; 136 int i; 137 138 /* 139 * Some cards power up with garbage in their BARs. This 140 * code clears all that junk out. 141 */ 142 for (i = 0; i < PCIR_MAX_BAR_0; i++) 143 pci_write_config(dev, PCIR_BAR(i), 0, 4); 144 145 cfg->intline = 146 pci_get_irq(device_get_parent(device_get_parent(dev))); 147 pci_write_config(dev, PCIR_INTLINE, cfg->intline, 1); 148 pci_write_config(dev, PCIR_CACHELNSZ, 0x08, 1); 149 pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1); 150 pci_write_config(dev, PCIR_MINGNT, 0x14, 1); 151 pci_write_config(dev, PCIR_MAXLAT, 0x14, 1); 152 } 153 154 static int 155 cardbus_attach_card(device_t cbdev) 156 { 157 device_t brdev = device_get_parent(cbdev); 158 device_t child; 159 int bus, domain, slot, func; 160 int cardattached = 0; 161 int cardbusfunchigh = 0; 162 struct cardbus_softc *sc; 163 164 sc = device_get_softc(cbdev); 165 cardbus_detach_card(cbdev); /* detach existing cards */ 166 POWER_ENABLE_SOCKET(brdev, cbdev); 167 domain = pcib_get_domain(cbdev); 168 bus = pcib_get_bus(cbdev); 169 slot = 0; 170 /* For each function, set it up and try to attach a driver to it */ 171 for (func = 0; func <= cardbusfunchigh; func++) { 172 struct cardbus_devinfo *dinfo; 173 174 dinfo = (struct cardbus_devinfo *) 175 pci_read_device(brdev, domain, bus, slot, func, 176 sizeof(struct cardbus_devinfo)); 177 if (dinfo == NULL) 178 continue; 179 if (dinfo->pci.cfg.mfdev) 180 cardbusfunchigh = PCI_FUNCMAX; 181 182 child = device_add_child(cbdev, NULL, -1); 183 if (child == NULL) { 184 DEVPRINTF((cbdev, "Cannot add child!\n")); 185 pci_freecfg((struct pci_devinfo *)dinfo); 186 continue; 187 } 188 dinfo->pci.cfg.dev = child; 189 resource_list_init(&dinfo->pci.resources); 190 device_set_ivars(child, dinfo); 191 cardbus_device_create(sc, dinfo, cbdev, child); 192 if (cardbus_do_cis(cbdev, child) != 0) 193 DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n")); 194 pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0); 195 pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); 196 cardbus_device_setup_regs(&dinfo->pci.cfg); 197 pci_add_resources(cbdev, child, 1, dinfo->mprefetchable); 198 pci_print_verbose(&dinfo->pci); 199 if (device_probe_and_attach(child) == 0) 200 cardattached++; 201 else 202 pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1); 203 } 204 if (cardattached > 0) 205 return (0); 206 /* POWER_DISABLE_SOCKET(brdev, cbdev); */ 207 return (ENOENT); 208 } 209 210 static int 211 cardbus_detach_card(device_t cbdev) 212 { 213 int numdevs; 214 device_t *devlist; 215 int tmp; 216 int err = 0; 217 218 if (device_get_children(cbdev, &devlist, &numdevs) != 0) 219 return (ENOENT); 220 if (numdevs == 0) { 221 free(devlist, M_TEMP); 222 return (ENOENT); 223 } 224 225 for (tmp = 0; tmp < numdevs; tmp++) { 226 struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]); 227 228 if (dinfo->pci.cfg.dev != devlist[tmp]) 229 device_printf(cbdev, "devinfo dev mismatch\n"); 230 cardbus_device_destroy(dinfo); 231 pci_delete_child(cbdev, devlist[tmp]); 232 } 233 POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); 234 free(devlist, M_TEMP); 235 return (err); 236 } 237 238 static void 239 cardbus_driver_added(device_t cbdev, driver_t *driver) 240 { 241 int numdevs; 242 device_t *devlist; 243 device_t dev; 244 int i; 245 struct cardbus_devinfo *dinfo; 246 247 DEVICE_IDENTIFY(driver, cbdev); 248 if (device_get_children(cbdev, &devlist, &numdevs) != 0) 249 return; 250 251 /* 252 * If there are no drivers attached, but there are children, 253 * then power the card up. 254 */ 255 for (i = 0; i < numdevs; i++) { 256 dev = devlist[i]; 257 if (device_get_state(dev) != DS_NOTPRESENT) 258 break; 259 } 260 if (i > 0 && i == numdevs) 261 POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev); 262 for (i = 0; i < numdevs; i++) { 263 dev = devlist[i]; 264 if (device_get_state(dev) != DS_NOTPRESENT) 265 continue; 266 dinfo = device_get_ivars(dev); 267 pci_print_verbose(&dinfo->pci); 268 if (bootverbose) 269 printf("pci%d:%d:%d:%d: reprobing on driver added\n", 270 dinfo->pci.cfg.domain, dinfo->pci.cfg.bus, 271 dinfo->pci.cfg.slot, dinfo->pci.cfg.func); 272 pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); 273 if (device_probe_and_attach(dev) != 0) 274 pci_cfg_save(dev, &dinfo->pci, 1); 275 } 276 free(devlist, M_TEMP); 277 } 278 279 /************************************************************************/ 280 /* Other Bus Methods */ 281 /************************************************************************/ 282 283 static int 284 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result) 285 { 286 struct cardbus_devinfo *dinfo; 287 pcicfgregs *cfg; 288 289 dinfo = device_get_ivars(child); 290 cfg = &dinfo->pci.cfg; 291 292 switch (which) { 293 case PCI_IVAR_ETHADDR: 294 /* 295 * The generic accessor doesn't deal with failure, so 296 * we set the return value, then return an error. 297 */ 298 if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) { 299 *((uint8_t **) result) = dinfo->funce.lan.nid; 300 break; 301 } 302 *((uint8_t **) result) = NULL; 303 return (EINVAL); 304 default: 305 return (pci_read_ivar(cbdev, child, which, result)); 306 } 307 return 0; 308 } 309 310 static device_method_t cardbus_methods[] = { 311 /* Device interface */ 312 DEVMETHOD(device_probe, cardbus_probe), 313 DEVMETHOD(device_attach, cardbus_attach), 314 DEVMETHOD(device_detach, cardbus_detach), 315 DEVMETHOD(device_suspend, cardbus_suspend), 316 DEVMETHOD(device_resume, cardbus_resume), 317 318 /* Bus interface */ 319 DEVMETHOD(bus_read_ivar, cardbus_read_ivar), 320 DEVMETHOD(bus_write_ivar, pci_write_ivar), 321 DEVMETHOD(bus_driver_added, cardbus_driver_added), 322 323 /* Card Interface */ 324 DEVMETHOD(card_attach_card, cardbus_attach_card), 325 DEVMETHOD(card_detach_card, cardbus_detach_card), 326 327 {0,0} 328 }; 329 330 DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 331 sizeof(struct cardbus_softc), pci_driver); 332 333 static devclass_t cardbus_devclass; 334 335 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0); 336 MODULE_VERSION(cardbus, 1); 337