1 /* 2 * Copyright (c) 2003 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 * without modification, immediately at the beginning of the file. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 #include <sys/kernel.h> 38 #include <sys/sysctl.h> 39 40 #include <sys/bus.h> 41 #include <machine/bus.h> 42 #include <sys/rman.h> 43 #include <machine/resource.h> 44 45 #include <sys/pciio.h> 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pci_private.h> 49 50 #include <dev/cardbus/cardbusreg.h> 51 #include <dev/cardbus/cardbusvar.h> 52 #include <dev/cardbus/cardbus_cis.h> 53 #include <dev/pccard/pccardvar.h> 54 55 #include "power_if.h" 56 #include "pcib_if.h" 57 58 /* sysctl vars */ 59 SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters"); 60 61 int cardbus_debug = 0; 62 TUNABLE_INT("hw.cardbus.debug", &cardbus_debug); 63 SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW, 64 &cardbus_debug, 0, 65 "CardBus debug"); 66 67 int cardbus_cis_debug = 0; 68 TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug); 69 SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW, 70 &cardbus_cis_debug, 0, 71 "CardBus CIS debug"); 72 73 #define DPRINTF(a) if (cardbus_debug) printf a 74 #define DEVPRINTF(x) if (cardbus_debug) device_printf x 75 76 77 static int cardbus_attach(device_t cbdev); 78 static int cardbus_attach_card(device_t cbdev); 79 static int cardbus_detach(device_t cbdev); 80 static int cardbus_detach_card(device_t cbdev); 81 static void cardbus_device_setup_regs(device_t brdev, int b, int s, int f, 82 pcicfgregs *cfg); 83 static void cardbus_driver_added(device_t cbdev, driver_t *driver); 84 static int cardbus_probe(device_t cbdev); 85 static int cardbus_read_ivar(device_t cbdev, device_t child, int which, 86 uintptr_t *result); 87 static void cardbus_release_all_resources(device_t cbdev, 88 struct cardbus_devinfo *dinfo); 89 static int cardbus_write_ivar(device_t cbdev, device_t child, int which, 90 uintptr_t value); 91 92 /************************************************************************/ 93 /* Probe/Attach */ 94 /************************************************************************/ 95 96 static int 97 cardbus_probe(device_t cbdev) 98 { 99 device_set_desc(cbdev, "CardBus bus"); 100 return 0; 101 } 102 103 static int 104 cardbus_attach(device_t cbdev) 105 { 106 return 0; 107 } 108 109 static int 110 cardbus_detach(device_t cbdev) 111 { 112 cardbus_detach_card(cbdev); 113 return 0; 114 } 115 116 static int 117 cardbus_suspend(device_t self) 118 { 119 cardbus_detach_card(self); 120 return (0); 121 } 122 123 static int 124 cardbus_resume(device_t self) 125 { 126 return (0); 127 } 128 129 /************************************************************************/ 130 /* Attach/Detach card */ 131 /************************************************************************/ 132 133 static void 134 cardbus_device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg) 135 { 136 PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_INTLINE, 137 pci_get_irq(device_get_parent(brdev)), 1); 138 cfg->intline = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_INTLINE, 1); 139 140 PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1); 141 cfg->cachelnsz = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 1); 142 143 PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 0xa8, 1); 144 cfg->lattimer = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 1); 145 146 PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MINGNT, 0x14, 1); 147 cfg->mingnt = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MINGNT, 1); 148 149 PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 0x14, 1); 150 cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1); 151 } 152 153 static int 154 cardbus_attach_card(device_t cbdev) 155 { 156 device_t brdev = device_get_parent(cbdev); 157 int cardattached = 0; 158 int bus, slot, func; 159 160 cardbus_detach_card(cbdev); /* detach existing cards */ 161 POWER_ENABLE_SOCKET(brdev, cbdev); 162 bus = pcib_get_bus(cbdev); 163 /* For each function, set it up and try to attach a driver to it */ 164 for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) { 165 int cardbusfunchigh = 0; 166 for (func = 0; func <= cardbusfunchigh; func++) { 167 struct cardbus_devinfo *dinfo; 168 169 dinfo = (struct cardbus_devinfo *) 170 pci_read_device(brdev, bus, slot, func, 171 sizeof(struct cardbus_devinfo)); 172 if (dinfo == NULL) 173 continue; 174 if (dinfo->pci.cfg.mfdev) 175 cardbusfunchigh = CARDBUS_FUNCMAX; 176 177 cardbus_device_setup_regs(brdev, bus, slot, func, 178 &dinfo->pci.cfg); 179 dinfo->pci.cfg.dev = device_add_child(cbdev, NULL, -1); 180 if (!dinfo->pci.cfg.dev) { 181 DEVPRINTF((cbdev, "Cannot add child!\n")); 182 pci_freecfg((struct pci_devinfo *)dinfo); 183 continue; 184 } 185 resource_list_init(&dinfo->pci.resources); 186 device_set_ivars(dinfo->pci.cfg.dev, dinfo); 187 cardbus_do_cis(cbdev, dinfo->pci.cfg.dev); 188 pci_print_verbose(&dinfo->pci); 189 if (device_probe_and_attach(dinfo->pci.cfg.dev) != 0) 190 cardbus_release_all_resources(cbdev, dinfo); 191 else 192 cardattached++; 193 } 194 } 195 196 if (cardattached > 0) 197 return (0); 198 POWER_DISABLE_SOCKET(brdev, cbdev); 199 return (ENOENT); 200 } 201 202 static int 203 cardbus_detach_card(device_t cbdev) 204 { 205 int numdevs; 206 device_t *devlist; 207 int tmp; 208 int err = 0; 209 210 device_get_children(cbdev, &devlist, &numdevs); 211 212 if (numdevs == 0) { 213 free(devlist, M_TEMP); 214 return (ENOENT); 215 } 216 217 for (tmp = 0; tmp < numdevs; tmp++) { 218 struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]); 219 int status = device_get_state(devlist[tmp]); 220 221 if (dinfo->pci.cfg.dev != devlist[tmp]) 222 device_printf(cbdev, "devinfo dev mismatch\n"); 223 if (status == DS_ATTACHED || status == DS_BUSY) 224 device_detach(devlist[tmp]); 225 cardbus_release_all_resources(cbdev, dinfo); 226 device_delete_child(cbdev, devlist[tmp]); 227 pci_freecfg((struct pci_devinfo *)dinfo); 228 } 229 POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); 230 free(devlist, M_TEMP); 231 return (err); 232 } 233 234 static void 235 cardbus_driver_added(device_t cbdev, driver_t *driver) 236 { 237 int numdevs; 238 device_t *devlist; 239 device_t dev; 240 int i; 241 struct cardbus_devinfo *dinfo; 242 243 DEVICE_IDENTIFY(driver, cbdev); 244 device_get_children(cbdev, &devlist, &numdevs); 245 /* 246 * If there are no drivers attached, but there are children, 247 * then power the card up. 248 */ 249 for (i = 0; i < numdevs; i++) { 250 dev = devlist[i]; 251 if (device_get_state(dev) != DS_NOTPRESENT) 252 break; 253 } 254 if (i > 0 && i == numdevs) 255 POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev); 256 for (i = 0; i < numdevs; i++) { 257 dev = devlist[i]; 258 if (device_get_state(dev) != DS_NOTPRESENT) 259 continue; 260 dinfo = device_get_ivars(dev); 261 pci_print_verbose(&dinfo->pci); 262 resource_list_init(&dinfo->pci.resources); 263 cardbus_do_cis(cbdev, dev); 264 if (device_probe_and_attach(dev) != 0) 265 cardbus_release_all_resources(cbdev, dinfo); 266 } 267 free(devlist, M_TEMP); 268 } 269 270 static void 271 cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo) 272 { 273 struct resource_list_entry *rle; 274 275 /* Free all allocated resources */ 276 SLIST_FOREACH(rle, &dinfo->pci.resources, link) { 277 if (rle->res) { 278 if (rman_get_device(rle->res) != cbdev) 279 device_printf(cbdev, "release_all_resource: " 280 "Resource still owned by child, oops. " 281 "(type=%d, rid=%d, addr=%lx)\n", 282 rle->type, rle->rid, 283 rman_get_start(rle->res)); 284 BUS_RELEASE_RESOURCE(device_get_parent(cbdev), 285 cbdev, rle->type, rle->rid, rle->res); 286 rle->res = NULL; 287 /* 288 * zero out config so the card won't acknowledge 289 * access to the space anymore 290 */ 291 pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4); 292 } 293 } 294 resource_list_free(&dinfo->pci.resources); 295 } 296 297 /************************************************************************/ 298 /* Other Bus Methods */ 299 /************************************************************************/ 300 301 static int 302 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result) 303 { 304 struct cardbus_devinfo *dinfo; 305 pcicfgregs *cfg; 306 307 dinfo = device_get_ivars(child); 308 cfg = &dinfo->pci.cfg; 309 310 switch (which) { 311 case PCI_IVAR_ETHADDR: 312 /* 313 * The generic accessor doesn't deal with failure, so 314 * we set the return value, then return an error. 315 */ 316 if ((dinfo->fepresent & (1 << TPL_FUNCE_LAN_NID)) == 0) { 317 *((uint8_t **) result) = NULL; 318 return (EINVAL); 319 } 320 *((uint8_t **) result) = dinfo->funce.lan.nid; 321 break; 322 default: 323 return (pci_read_ivar(cbdev, child, which, result)); 324 } 325 return 0; 326 } 327 328 static int 329 cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value) 330 { 331 return(pci_write_ivar(cbdev, child, which, value)); 332 } 333 334 static device_method_t cardbus_methods[] = { 335 /* Device interface */ 336 DEVMETHOD(device_probe, cardbus_probe), 337 DEVMETHOD(device_attach, cardbus_attach), 338 DEVMETHOD(device_detach, cardbus_detach), 339 DEVMETHOD(device_suspend, cardbus_suspend), 340 DEVMETHOD(device_resume, cardbus_resume), 341 342 /* Bus interface */ 343 DEVMETHOD(bus_read_ivar, cardbus_read_ivar), 344 DEVMETHOD(bus_write_ivar, cardbus_write_ivar), 345 DEVMETHOD(bus_driver_added, cardbus_driver_added), 346 347 /* Card Interface */ 348 DEVMETHOD(card_attach_card, cardbus_attach_card), 349 DEVMETHOD(card_detach_card, cardbus_detach_card), 350 351 {0,0} 352 }; 353 354 DECLARE_CLASS(pci_driver); 355 DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 0, pci_driver); 356 357 static devclass_t cardbus_devclass; 358 359 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0); 360 MODULE_VERSION(cardbus, 1); 361