1 /*- 2 * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org> 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 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD: head/sys/dev/siba/siba_bwn.c 299409 2016-05-11 06:27:46Z adrian $"); 32 33 /* 34 * Sonics Silicon Backplane front-end for bwn(4). 35 */ 36 37 #if defined(__DragonFly__) 38 #include <opt_siba.h> 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/malloc.h> 44 #include <sys/module.h> 45 #include <sys/kernel.h> 46 #include <sys/lock.h> 47 #include <sys/mutex.h> 48 #include <sys/errno.h> 49 #if !defined(__DragonFly__) 50 #include <machine/bus.h> 51 #include <machine/resource.h> 52 #endif 53 #include <sys/bus.h> 54 #include <sys/rman.h> 55 #include <sys/socket.h> 56 57 #include <net/if.h> 58 #include <net/if_media.h> 59 #include <net/if_arp.h> 60 61 #if defined(__DragonFly__) 62 #include <bus/pci/pcivar.h> 63 #include <bus/pci/pcireg.h> 64 #else 65 #include <dev/pci/pcivar.h> 66 #include <dev/pci/pcireg.h> 67 #endif 68 69 #if defined(__DragonFly__) 70 #include "siba_ids.h" 71 #include "sibareg.h" 72 #include "sibavar.h" 73 #else 74 #include <dev/siba/siba_ids.h> 75 #include <dev/siba/sibareg.h> 76 #include <dev/siba/sibavar.h> 77 #endif 78 79 /* 80 * PCI glue. 81 */ 82 83 struct siba_bwn_softc { 84 /* Child driver using MSI. */ 85 device_t ssc_msi_child; 86 struct siba_softc ssc_siba; 87 }; 88 89 #define BS_BAR 0x10 90 #define PCI_VENDOR_BROADCOM 0x14e4 91 #define N(a) (sizeof(a) / sizeof(a[0])) 92 93 static const struct siba_dev { 94 uint16_t vid; 95 uint16_t did; 96 const char *desc; 97 } siba_devices[] = { 98 { PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" }, 99 { PCI_VENDOR_BROADCOM, 0x4306, "Unknown" }, 100 { PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" }, 101 { PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" }, 102 { PCI_VENDOR_BROADCOM, 0x4312, 103 "Broadcom BCM4312 802.11a/b/g Wireless" }, 104 { PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" }, 105 { PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" }, 106 { PCI_VENDOR_BROADCOM, 0x4319, 107 "Broadcom BCM4318 802.11a/b/g Wireless" }, 108 { PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" }, 109 { PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" }, 110 { PCI_VENDOR_BROADCOM, 0x4324, 111 "Broadcom BCM4309 802.11a/b/g Wireless" }, 112 { PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" }, 113 { PCI_VENDOR_BROADCOM, 0x4328, "Broadcom BCM4321 802.11a/b/g Wireless" }, 114 { PCI_VENDOR_BROADCOM, 0x4329, "Unknown" }, 115 { PCI_VENDOR_BROADCOM, 0x432b, "Unknown" } 116 }; 117 118 int siba_core_attach(struct siba_softc *); 119 int siba_core_detach(struct siba_softc *); 120 int siba_core_suspend(struct siba_softc *); 121 int siba_core_resume(struct siba_softc *); 122 123 static int 124 siba_bwn_probe(device_t dev) 125 { 126 int i; 127 uint16_t did, vid; 128 129 did = pci_get_device(dev); 130 vid = pci_get_vendor(dev); 131 132 for (i = 0; i < N(siba_devices); i++) { 133 if (siba_devices[i].did == did && siba_devices[i].vid == vid) { 134 device_set_desc(dev, siba_devices[i].desc); 135 return (BUS_PROBE_DEFAULT); 136 } 137 } 138 return (ENXIO); 139 } 140 141 static int 142 siba_bwn_attach(device_t dev) 143 { 144 struct siba_bwn_softc *ssc = device_get_softc(dev); 145 struct siba_softc *siba = &ssc->ssc_siba; 146 147 siba->siba_dev = dev; 148 siba->siba_type = SIBA_TYPE_PCI; 149 150 /* 151 * Enable bus mastering. 152 */ 153 pci_enable_busmaster(dev); 154 155 /* 156 * Setup memory-mapping of PCI registers. 157 */ 158 siba->siba_mem_rid = SIBA_PCIR_BAR; 159 siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 160 &siba->siba_mem_rid, RF_ACTIVE); 161 if (siba->siba_mem_res == NULL) { 162 device_printf(dev, "cannot map register space\n"); 163 return (ENXIO); 164 } 165 siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res); 166 siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res); 167 168 /* Get more PCI information */ 169 siba->siba_pci_did = pci_get_device(dev); 170 siba->siba_pci_vid = pci_get_vendor(dev); 171 siba->siba_pci_subvid = pci_get_subvendor(dev); 172 siba->siba_pci_subdid = pci_get_subdevice(dev); 173 siba->siba_pci_revid = pci_get_revid(dev); 174 175 return (siba_core_attach(siba)); 176 } 177 178 static int 179 siba_bwn_detach(device_t dev) 180 { 181 struct siba_bwn_softc *ssc = device_get_softc(dev); 182 struct siba_softc *siba = &ssc->ssc_siba; 183 184 /* check if device was removed */ 185 siba->siba_invalid = !bus_child_present(dev); 186 187 pci_disable_busmaster(dev); 188 bus_generic_detach(dev); 189 siba_core_detach(siba); 190 191 bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res); 192 193 return (0); 194 } 195 196 static int 197 siba_bwn_shutdown(device_t dev) 198 { 199 device_t *devlistp; 200 int devcnt, error = 0, i; 201 202 error = device_get_children(dev, &devlistp, &devcnt); 203 if (error != 0) 204 return (error); 205 206 for (i = 0 ; i < devcnt ; i++) 207 device_shutdown(devlistp[i]); 208 kfree(devlistp, M_TEMP); 209 return (0); 210 } 211 212 static int 213 siba_bwn_suspend(device_t dev) 214 { 215 struct siba_bwn_softc *ssc = device_get_softc(dev); 216 struct siba_softc *siba = &ssc->ssc_siba; 217 device_t *devlistp; 218 int devcnt, error = 0, i, j; 219 220 error = device_get_children(dev, &devlistp, &devcnt); 221 if (error != 0) 222 return (error); 223 224 for (i = 0 ; i < devcnt ; i++) { 225 error = DEVICE_SUSPEND(devlistp[i]); 226 if (error) { 227 for (j = 0; j < i; j++) 228 DEVICE_RESUME(devlistp[j]); 229 kfree(devlistp, M_TEMP); 230 return (error); 231 } 232 } 233 kfree(devlistp, M_TEMP); 234 return (siba_core_suspend(siba)); 235 } 236 237 static int 238 siba_bwn_resume(device_t dev) 239 { 240 struct siba_bwn_softc *ssc = device_get_softc(dev); 241 struct siba_softc *siba = &ssc->ssc_siba; 242 device_t *devlistp; 243 int devcnt, error = 0, i; 244 245 error = siba_core_resume(siba); 246 if (error != 0) 247 return (error); 248 249 error = device_get_children(dev, &devlistp, &devcnt); 250 if (error != 0) 251 return (error); 252 253 for (i = 0 ; i < devcnt ; i++) 254 DEVICE_RESUME(devlistp[i]); 255 kfree(devlistp, M_TEMP); 256 return (0); 257 } 258 259 /* proxying to the parent */ 260 #if defined(__DragonFly__) 261 static struct resource * 262 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid, 263 u_long start, u_long end, u_long count, u_int flags, int cpuid) 264 { 265 266 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 267 type, rid, start, end, count, flags, cpuid)); 268 } 269 #else 270 static struct resource * 271 siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid, 272 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 273 { 274 275 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 276 type, rid, start, end, count, flags)); 277 } 278 #endif 279 280 /* proxying to the parent */ 281 static int 282 siba_bwn_release_resource(device_t dev, device_t child, int type, 283 int rid, struct resource *r) 284 { 285 286 return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, 287 rid, r)); 288 } 289 290 #if defined(__DragonFly__) 291 /* proxying to the parent */ 292 static int 293 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq, 294 int flags, driver_intr_t *intr, void *arg, void **cookiep, 295 lwkt_serialize_t serializer) 296 { 297 298 return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags, 299 intr, arg, cookiep, serializer, NULL)); 300 } 301 #else 302 static int 303 siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq, 304 int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, 305 void **cookiep) 306 { 307 308 return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags, 309 filter, intr, arg, cookiep)); 310 } 311 #endif 312 313 /* proxying to the parent */ 314 static int 315 siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq, 316 void *cookie) 317 { 318 319 return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie)); 320 } 321 322 #if !defined(__DragonFly__) 323 static int 324 siba_bwn_find_cap(device_t dev, device_t child, int capability, 325 int *capreg) 326 { 327 328 return (pci_find_cap(dev, capability, capreg)); 329 } 330 #endif 331 332 static int 333 siba_bwn_find_extcap(device_t dev, device_t child, int capability, 334 int *capreg) 335 { 336 337 return (pci_find_extcap(dev, capability, capreg)); 338 } 339 340 #if !defined(__DragonFly__) 341 static int 342 siba_bwn_find_htcap(device_t dev, device_t child, int capability, 343 int *capreg) 344 { 345 346 return (pci_find_htcap(dev, capability, capreg)); 347 } 348 #endif 349 350 #if defined(__DragonFly__) 351 static int 352 siba_bwn_alloc_msi(device_t dev, device_t child, int *rid, int count, 353 int cpuid) 354 #else 355 static int 356 siba_bwn_alloc_msi(device_t dev, device_t child, int *count) 357 #endif 358 { 359 struct siba_bwn_softc *ssc; 360 int error; 361 362 ssc = device_get_softc(dev); 363 if (ssc->ssc_msi_child != NULL) 364 return (EBUSY); 365 #if defined(__DragonFly__) 366 error = pci_alloc_msi(dev, rid, count, cpuid); 367 #else 368 error = pci_alloc_msi(dev, count); 369 #endif 370 if (error == 0) 371 ssc->ssc_msi_child = child; 372 return (error); 373 } 374 375 static int 376 siba_bwn_release_msi(device_t dev, device_t child) 377 { 378 struct siba_bwn_softc *ssc; 379 int error; 380 381 ssc = device_get_softc(dev); 382 if (ssc->ssc_msi_child != child) 383 return (ENXIO); 384 error = pci_release_msi(dev); 385 if (error == 0) 386 ssc->ssc_msi_child = NULL; 387 return (error); 388 } 389 390 static int 391 siba_bwn_msi_count(device_t dev, device_t child) 392 { 393 394 return (pci_msi_count(dev)); 395 } 396 397 static int 398 siba_bwn_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 399 { 400 struct siba_dev_softc *sd; 401 struct siba_softc *siba; 402 403 sd = device_get_ivars(child); 404 siba = sd->sd_bus; 405 406 switch (which) { 407 case SIBA_IVAR_VENDOR: 408 *result = sd->sd_id.sd_vendor; 409 break; 410 case SIBA_IVAR_DEVICE: 411 *result = sd->sd_id.sd_device; 412 break; 413 case SIBA_IVAR_REVID: 414 *result = sd->sd_id.sd_rev; 415 break; 416 case SIBA_IVAR_PCI_VENDOR: 417 *result = siba->siba_pci_vid; 418 break; 419 case SIBA_IVAR_PCI_DEVICE: 420 *result = siba->siba_pci_did; 421 break; 422 case SIBA_IVAR_PCI_SUBVENDOR: 423 *result = siba->siba_pci_subvid; 424 break; 425 case SIBA_IVAR_PCI_SUBDEVICE: 426 *result = siba->siba_pci_subdid; 427 break; 428 case SIBA_IVAR_PCI_REVID: 429 *result = siba->siba_pci_revid; 430 break; 431 case SIBA_IVAR_CHIPID: 432 *result = siba->siba_chipid; 433 break; 434 case SIBA_IVAR_CHIPREV: 435 *result = siba->siba_chiprev; 436 break; 437 case SIBA_IVAR_CHIPPKG: 438 *result = siba->siba_chippkg; 439 break; 440 case SIBA_IVAR_TYPE: 441 *result = siba->siba_type; 442 break; 443 case SIBA_IVAR_CC_PMUFREQ: 444 *result = siba->siba_cc.scc_pmu.freq; 445 break; 446 case SIBA_IVAR_CC_CAPS: 447 *result = siba->siba_cc.scc_caps; 448 break; 449 case SIBA_IVAR_CC_POWERDELAY: 450 *result = siba->siba_cc.scc_powerup_delay; 451 break; 452 case SIBA_IVAR_PCICORE_REVID: 453 *result = siba->siba_pci.spc_dev->sd_id.sd_rev; 454 break; 455 default: 456 return (ENOENT); 457 } 458 459 return (0); 460 } 461 462 static device_method_t siba_bwn_methods[] = { 463 /* Device interface */ 464 DEVMETHOD(device_probe, siba_bwn_probe), 465 DEVMETHOD(device_attach, siba_bwn_attach), 466 DEVMETHOD(device_detach, siba_bwn_detach), 467 DEVMETHOD(device_shutdown, siba_bwn_shutdown), 468 DEVMETHOD(device_suspend, siba_bwn_suspend), 469 DEVMETHOD(device_resume, siba_bwn_resume), 470 471 /* Bus interface */ 472 DEVMETHOD(bus_alloc_resource, siba_bwn_alloc_resource), 473 DEVMETHOD(bus_release_resource, siba_bwn_release_resource), 474 DEVMETHOD(bus_read_ivar, siba_bwn_read_ivar), 475 DEVMETHOD(bus_setup_intr, siba_bwn_setup_intr), 476 DEVMETHOD(bus_teardown_intr, siba_bwn_teardown_intr), 477 478 /* PCI interface */ 479 #if !defined(__DragonFly__) 480 DEVMETHOD(pci_find_cap, siba_bwn_find_cap), 481 #endif 482 DEVMETHOD(pci_find_extcap, siba_bwn_find_extcap), 483 #if !defined(__DragonFly__) 484 DEVMETHOD(pci_find_htcap, siba_bwn_find_htcap), 485 #endif 486 DEVMETHOD(pci_alloc_msi, siba_bwn_alloc_msi), 487 DEVMETHOD(pci_release_msi, siba_bwn_release_msi), 488 DEVMETHOD(pci_msi_count, siba_bwn_msi_count), 489 490 DEVMETHOD_END 491 }; 492 static driver_t siba_bwn_driver = { 493 "siba_bwn", 494 siba_bwn_methods, 495 sizeof(struct siba_bwn_softc) 496 }; 497 static devclass_t siba_bwn_devclass; 498 DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, NULL, NULL); 499 MODULE_VERSION(siba_bwn, 1); 500