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