1 /*- 2 * Copyright (c) 2012 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Matt Thomas of 3am Software Foundry. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * 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 IN 25 * 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 THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #define _ARM32_BUS_DMA_PRIVATE 31 #define PCIE_PRIVATE 32 33 #include "locators.h" 34 35 #include <sys/cdefs.h> 36 37 __KERNEL_RCSID(1, "$NetBSD: bcm53xx_pax.c,v 1.22 2021/08/07 16:18:43 thorpej Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/bus.h> 41 #include <sys/device.h> 42 #include <sys/intr.h> 43 #include <sys/kmem.h> 44 #include <sys/systm.h> 45 46 #include <dev/pci/pcireg.h> 47 #include <dev/pci/pcivar.h> 48 #include <dev/pci/pciconf.h> 49 50 #include <arm/locore.h> 51 52 #include <arm/broadcom/bcm53xx_reg.h> 53 #include <arm/broadcom/bcm53xx_var.h> 54 55 #ifndef __HAVE_PCI_CONF_HOOK 56 #error __HAVE_PCI_CONF_HOOK must be defined 57 #endif 58 59 static const struct { 60 paddr_t owin_base; 61 psize_t owin_size; 62 } bcmpax_owins[] = { 63 [0] = { BCM53XX_PCIE0_OWIN_PBASE, BCM53XX_PCIE0_OWIN_SIZE }, 64 [1] = { BCM53XX_PCIE1_OWIN_PBASE, BCM53XX_PCIE1_OWIN_SIZE }, 65 [2] = { BCM53XX_PCIE2_OWIN_PBASE, BCM53XX_PCIE2_OWIN_SIZE }, 66 }; 67 68 static int bcmpax_ccb_match(device_t, cfdata_t, void *); 69 static void bcmpax_ccb_attach(device_t, device_t, void *); 70 71 struct bcmpax_intrhand { 72 TAILQ_ENTRY(bcmpax_intrhand) ih_link; 73 int (*ih_func)(void *); 74 void *ih_arg; 75 int ih_ipl; 76 }; 77 78 TAILQ_HEAD(bcmpax_ihqh, bcmpax_intrhand); 79 80 struct bcmpax_softc { 81 device_t sc_dev; 82 bus_space_tag_t sc_bst; 83 bus_space_handle_t sc_bsh; 84 bus_dma_tag_t sc_dmat; 85 kmutex_t *sc_lock; 86 kmutex_t *sc_cfg_lock; 87 bool sc_linkup; 88 int sc_pba_flags; 89 uint32_t sc_intrgen; 90 struct arm32_pci_chipset sc_pc; 91 struct bcmpax_ihqh sc_intrs; 92 void *sc_ih[6]; 93 int sc_port; 94 }; 95 96 static inline uint32_t 97 bcmpax_read_4(struct bcmpax_softc *sc, bus_size_t o) 98 { 99 return bus_space_read_4(sc->sc_bst, sc->sc_bsh, o); 100 } 101 102 static inline void 103 bcmpax_write_4(struct bcmpax_softc *sc, bus_size_t o, uint32_t v) 104 { 105 bus_space_write_4(sc->sc_bst, sc->sc_bsh, o, v); 106 } 107 108 static void bcmpax_attach_hook(device_t, device_t, struct pcibus_attach_args *); 109 static int bcmpax_bus_maxdevs(void *, int); 110 static pcitag_t bcmpax_make_tag(void *, int, int, int); 111 static void bcmpax_decompose_tag(void *, pcitag_t, int *, int *, int *); 112 static pcireg_t bcmpax_conf_read(void *, pcitag_t, int); 113 static void bcmpax_conf_write(void *, pcitag_t, int, pcireg_t); 114 115 static int bcmpax_intr_map(const struct pci_attach_args *, pci_intr_handle_t *); 116 static const char *bcmpax_intr_string(void *, pci_intr_handle_t, char *, size_t); 117 static const struct evcnt *bcmpax_intr_evcnt(void *, pci_intr_handle_t); 118 static void *bcmpax_intr_establish(void *, pci_intr_handle_t, int, 119 int (*)(void *), void *, const char *); 120 static void bcmpax_intr_disestablish(void *, void *); 121 122 static int bcmpax_conf_hook(void *, int, int, int, pcireg_t); 123 static void bcmpax_conf_interrupt(void *, int, int, int, int, int *); 124 125 static int bcmpax_intr(void *); 126 127 CFATTACH_DECL_NEW(bcmpax_ccb, sizeof(struct bcmpax_softc), 128 bcmpax_ccb_match, bcmpax_ccb_attach, NULL, NULL); 129 130 static int 131 bcmpax_ccb_match(device_t parent, cfdata_t cf, void *aux) 132 { 133 struct bcmccb_attach_args * const ccbaa = aux; 134 const struct bcm_locators * const loc = &ccbaa->ccbaa_loc; 135 136 if (strcmp(cf->cf_name, loc->loc_name)) 137 return 0; 138 139 #ifdef DIAGNOSTIC 140 const int port = cf->cf_loc[BCMCCBCF_PORT]; 141 #endif 142 KASSERT(port == BCMCCBCF_PORT_DEFAULT || port == loc->loc_port); 143 144 return 1; 145 } 146 147 static int 148 bcmpax_iwin_init(struct bcmpax_softc *sc) 149 { 150 #if 0 151 uint32_t megs = (physical_end + 0xfffff - physical_start) >> 20; 152 uint32_t iwin_megs = uimin(256, megs); 153 #if 1 154 bus_addr_t iwin1_start = physical_start; 155 #else 156 bus_addr_t iwin1_start = 0; 157 #endif 158 #if 1 159 bcmpax_write_4(sc, PCIE_IARR_1_LOWER, iwin1_start | uimin(megs, 128)); 160 bcmpax_write_4(sc, PCIE_FUNC0_IMAP1, iwin1_start | 1); 161 #else 162 bcmpax_write_4(sc, PCIE_FUNC0_IMAP1, iwin1_start | uimin(megs, 128)); 163 bcmpax_write_4(sc, PCIE_IARR_1_LOWER, iwin1_start | 1); 164 #endif 165 bcmpax_conf_write(sc, 0, PCI_MAPREG_START+4, iwin1_start); 166 if (iwin_megs > 128) { 167 bus_addr_t iwin2_start = iwin1_start + 128*1024*1024; 168 #if 1 169 bcmpax_write_4(sc, PCIE_IARR_2_LOWER, iwin2_start | uimin(megs - 128, 128)); 170 bcmpax_write_4(sc, PCIE_FUNC0_IMAP2, iwin2_start | 1); 171 #else 172 bcmpax_write_4(sc, PCIE_FUNC0_IMAP2, iwin2_start | uimin(megs - 128, 128)); 173 bcmpax_write_4(sc, PCIE_IARR_2_LOWER, iwin2_start | 1); 174 #endif 175 bcmpax_conf_write(sc, 0, PCI_MAPREG_START+8, iwin2_start); 176 } 177 178 if (megs <= iwin_megs) { 179 /* 180 * We could can DMA to all of memory so we don't need to subregion! 181 */ 182 return 0; 183 } 184 185 return bus_dmatag_subregion(sc->sc_dmat, physical_start, 186 physical_start + (iwin_megs << 20) - 1, &sc->sc_dmat, 0); 187 #else 188 bcmpax_write_4(sc, PCIE_IARR_1_LOWER, 0); 189 bcmpax_write_4(sc, PCIE_FUNC0_IMAP1, 0); 190 bcmpax_write_4(sc, PCIE_IARR_2_LOWER, 0); 191 bcmpax_write_4(sc, PCIE_FUNC0_IMAP2, 0); 192 return 0; 193 #endif 194 } 195 196 static void 197 bcmpax_ccb_attach(device_t parent, device_t self, void *aux) 198 { 199 struct bcmpax_softc * const sc = device_private(self); 200 struct bcmccb_attach_args * const ccbaa = aux; 201 const struct bcm_locators * const loc = &ccbaa->ccbaa_loc; 202 cfdata_t cf = device_cfdata(self); 203 204 sc->sc_dev = self; 205 sc->sc_dmat = &bcm53xx_coherent_dma_tag; 206 #ifdef _ARM32_NEED_BUS_DMA_BOUNCE 207 if (cf->cf_flags & 2) { 208 sc->sc_dmat = &bcm53xx_bounce_dma_tag; 209 } 210 #endif 211 212 sc->sc_bst = ccbaa->ccbaa_ccb_bst; 213 bus_space_subregion(sc->sc_bst, ccbaa->ccbaa_ccb_bsh, 214 loc->loc_offset, loc->loc_size, &sc->sc_bsh); 215 216 /* 217 * Kick the hardware into RC mode. 218 */ 219 bcmpax_write_4(sc, PCIE_CLK_CONTROL, 3); 220 delay(250); 221 bcmpax_write_4(sc, PCIE_CLK_CONTROL, 1); 222 223 uint32_t v = bcmpax_read_4(sc, PCIE_STRAP_STATUS); 224 const bool enabled = (v & STRAP_PCIE_IF_ENABLE) != 0; 225 const bool is_v2_p = (v & STRAP_PCIE_USER_FOR_CE_GEN1) == 0; 226 const bool is_x2_p = (v & STRAP_PCIE_USER_FOR_CE_1LANE) == 0; 227 const bool is_rc_p = (v & STRAP_PCIE_USER_RC_MODE) != 0; 228 229 aprint_naive("\n"); 230 aprint_normal(": PCI Express V%u %u-lane %s Controller%s\n", 231 is_v2_p ? 2 : 1, 232 is_x2_p ? 2 : 1, 233 is_rc_p ? "RC" : "EP", 234 enabled ? "" : "(disabled)"); 235 if (!enabled || !is_rc_p) 236 return; 237 238 sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_VM); 239 sc->sc_cfg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_VM); 240 241 TAILQ_INIT(&sc->sc_intrs); 242 243 sc->sc_pc.pc_conf_v = sc; 244 sc->sc_pc.pc_attach_hook = bcmpax_attach_hook; 245 sc->sc_pc.pc_bus_maxdevs = bcmpax_bus_maxdevs; 246 sc->sc_pc.pc_make_tag = bcmpax_make_tag; 247 sc->sc_pc.pc_decompose_tag = bcmpax_decompose_tag; 248 sc->sc_pc.pc_conf_read = bcmpax_conf_read; 249 sc->sc_pc.pc_conf_write = bcmpax_conf_write; 250 251 sc->sc_pc.pc_intr_v = sc; 252 sc->sc_pc.pc_intr_map = bcmpax_intr_map; 253 sc->sc_pc.pc_intr_string = bcmpax_intr_string; 254 sc->sc_pc.pc_intr_evcnt = bcmpax_intr_evcnt; 255 sc->sc_pc.pc_intr_establish = bcmpax_intr_establish; 256 sc->sc_pc.pc_intr_disestablish = bcmpax_intr_disestablish; 257 258 sc->sc_pc.pc_conf_hook = bcmpax_conf_hook; 259 sc->sc_pc.pc_conf_interrupt = bcmpax_conf_interrupt; 260 261 sc->sc_pba_flags |= PCI_FLAGS_MRL_OKAY; 262 sc->sc_pba_flags |= PCI_FLAGS_MRM_OKAY; 263 sc->sc_pba_flags |= PCI_FLAGS_MWI_OKAY; 264 // sc->sc_pba_flags |= PCI_FLAGS_MSI_OKAY; 265 // sc->sc_pba_flags |= PCI_FLAGS_MSIX_OKAY; 266 267 for (size_t i = 0; i < loc->loc_nintrs; i++) { 268 sc->sc_ih[i] = intr_establish(loc->loc_intrs[0] + i, IPL_VM, 269 IST_LEVEL, bcmpax_intr, sc); 270 if (sc->sc_ih[i] == NULL) { 271 aprint_error_dev(self, 272 "failed to establish interrupt #%zu (%zu)\n", i, 273 loc->loc_intrs[0] + i); 274 while (i-- > 0) { 275 intr_disestablish(sc->sc_ih[i]); 276 } 277 return; 278 } 279 } 280 aprint_normal_dev(self, "interrupting on irqs %d-%d\n", 281 loc->loc_intrs[0], loc->loc_intrs[0] + loc->loc_nintrs - 1); 282 283 /* 284 * Enable INTA-INTD 285 */ 286 bcmpax_write_4(sc, PCIE_SYS_RC_INTX_EN, 0x0f); 287 288 int offset; 289 const bool ok = pci_get_capability(&sc->sc_pc, 0, PCI_CAP_PCIEXPRESS, 290 &offset, NULL); 291 KASSERT(ok); 292 293 /* 294 * This will force the device to negotiate to a max of gen1. 295 */ 296 if (cf->cf_flags & 1) { 297 bcmpax_conf_write(sc, 0, offset + PCIE_LCSR2, 1); 298 } 299 300 /* 301 * Now we wait (.25 sec) for the link to come up. 302 */ 303 offset += PCIE_LCSR; 304 for (size_t timo = 0;; timo++) { 305 const pcireg_t lcsr = bcmpax_conf_read(sc, 0, offset); 306 sc->sc_linkup = __SHIFTOUT(lcsr, PCIE_LCSR_NLW) != 0 307 && (1 || (lcsr & PCIE_LCSR_DLACTIVE) != 0); 308 if (sc->sc_linkup || timo == 250) { 309 aprint_debug_dev(self, 310 "lcsr=%#x nlw=%jd linkup=%d, timo=%zu\n", 311 lcsr, __SHIFTOUT(lcsr, PCIE_LCSR_NLW), 312 sc->sc_linkup, timo); 313 break; 314 } 315 DELAY(1000); 316 } 317 318 if (sc->sc_linkup) { 319 /* 320 * Enable the inbound (device->memory) map. 321 */ 322 int error = bcmpax_iwin_init(sc); 323 if (error) { 324 aprint_error_dev(sc->sc_dev, 325 "failed to subregion dma tag: %d\n", error); 326 return; 327 } 328 329 aprint_normal_dev(self, "iwin[1]=%#x/%#x iwin[2]=%#x/%#x\n", 330 bcmpax_read_4(sc, PCIE_FUNC0_IMAP1), 331 bcmpax_read_4(sc, PCIE_IARR_1_LOWER), 332 bcmpax_read_4(sc, PCIE_FUNC0_IMAP2), 333 bcmpax_read_4(sc, PCIE_IARR_2_LOWER)); 334 335 paddr_t base = bcmpax_owins[loc->loc_port].owin_base; 336 psize_t size = bcmpax_owins[loc->loc_port].owin_size; 337 KASSERT((size & ~PCIE_OARR_ADDR) == 0); 338 if (size > 0) { 339 bcmpax_write_4(sc, PCIE_OARR_0, base); 340 bcmpax_write_4(sc, PCIE_OMAP_0_LOWER, base | 1); 341 } 342 if (size > __LOWEST_SET_BIT(PCIE_OARR_ADDR)) { 343 paddr_t base1 = base + __LOWEST_SET_BIT(PCIE_OARR_ADDR); 344 bcmpax_write_4(sc, PCIE_OARR_1, base1); 345 bcmpax_write_4(sc, PCIE_OMAP_1_LOWER, base1 | 1); 346 } 347 348 struct pciconf_resources *pcires = pciconf_resource_init(); 349 pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM, 350 base, size); 351 error = pci_configure_bus(&sc->sc_pc, pcires, 352 0, arm_pcache.dcache_line_size); 353 pciconf_resource_fini(pcires); 354 355 if (error) { 356 aprint_normal_dev(self, "configuration failed\n"); 357 return; 358 } 359 } 360 361 struct pcibus_attach_args pba; 362 memset(&pba, 0, sizeof(pba)); 363 364 pba.pba_flags = sc->sc_pba_flags; 365 pba.pba_flags |= PCI_FLAGS_MEM_OKAY; 366 pba.pba_memt = sc->sc_bst; 367 pba.pba_dmat = sc->sc_dmat; 368 pba.pba_pc = &sc->sc_pc; 369 pba.pba_bus = 0; 370 371 config_found(self, &pba, pcibusprint, CFARGS_NONE); 372 } 373 374 static void 375 bcmpax_attach_hook(device_t parent, device_t self, 376 struct pcibus_attach_args *pba) 377 { 378 } 379 380 static int 381 bcmpax_bus_maxdevs(void *v, int bus) 382 { 383 struct bcmpax_softc * const sc = v; 384 385 if (__predict_true(sc->sc_linkup)) 386 return bus > 1 ? 32 : 1; 387 388 return bus ? 0 : 1; 389 } 390 391 static void 392 bcmpax_decompose_tag(void *v, pcitag_t tag, int *busp, int *devp, int *funcp) 393 { 394 if (busp) 395 *busp = __SHIFTOUT(tag, CFG_ADDR_BUS); 396 if (devp) 397 *devp = __SHIFTOUT(tag, CFG_ADDR_DEV); 398 if (funcp) 399 *funcp = __SHIFTOUT(tag, CFG_ADDR_FUNC); 400 } 401 402 static pcitag_t 403 bcmpax_make_tag(void *v, int bus, int dev, int func) 404 { 405 return __SHIFTIN(bus, CFG_ADDR_BUS) 406 | __SHIFTIN(dev, CFG_ADDR_DEV) 407 | __SHIFTIN(func, CFG_ADDR_FUNC) 408 | (bus == 0 ? CFG_ADDR_TYPE0 : CFG_ADDR_TYPE1); 409 } 410 411 static inline bus_size_t 412 bcmpax_conf_addr_write(struct bcmpax_softc *sc, pcitag_t tag) 413 { 414 if ((tag & (CFG_ADDR_BUS|CFG_ADDR_DEV)) == 0) { 415 uint32_t reg = __SHIFTOUT(tag, CFG_ADDR_REG); 416 uint32_t func = __SHIFTOUT(tag, CFG_ADDR_FUNC); 417 bcmpax_write_4(sc, PCIE_CFG_IND_ADDR, 418 __SHIFTIN(func, CFG_IND_ADDR_FUNC) 419 | __SHIFTIN(reg, CFG_IND_ADDR_REG)); 420 dsb(sy); 421 return PCIE_CFG_IND_DATA; 422 } 423 if (sc->sc_linkup) { 424 bcmpax_write_4(sc, PCIE_CFG_ADDR, tag); 425 dsb(sy); 426 return PCIE_CFG_DATA; 427 } 428 return 0; 429 } 430 431 static pcireg_t 432 bcmpax_conf_read(void *v, pcitag_t tag, int reg) 433 { 434 struct bcmpax_softc * const sc = v; 435 436 if ((unsigned int)reg >= PCI_CONF_SIZE) 437 return 0xffffffff; 438 439 /* 440 * Even in RC mode, the PCI Express Root Complex return itself 441 * as BCM Ethernet Controller!. We could change ppb.c to match it 442 * but we'll just lie and say we are a PPB bridge. 443 */ 444 if ((tag & (CFG_ADDR_BUS|CFG_ADDR_DEV|CFG_ADDR_FUNC)) == 0 445 && reg == PCI_CLASS_REG) { 446 return PCI_CLASS_CODE(PCI_CLASS_BRIDGE, 447 PCI_SUBCLASS_BRIDGE_PCI, 0); 448 } 449 450 //printf("%s: tag %#lx reg %#x:", __func__, tag, reg); 451 452 mutex_enter(sc->sc_cfg_lock); 453 bus_size_t data_reg = bcmpax_conf_addr_write(sc, tag | reg); 454 455 //printf(" [from %#lx]:\n", data_reg); 456 457 pcireg_t rv; 458 if (data_reg) 459 rv = bcmpax_read_4(sc, data_reg); 460 else 461 rv = 0xffffffff; 462 463 mutex_exit(sc->sc_cfg_lock); 464 465 //printf(" %#x\n", rv); 466 467 return rv; 468 } 469 470 static void 471 bcmpax_conf_write(void *v, pcitag_t tag, int reg, pcireg_t val) 472 { 473 struct bcmpax_softc * const sc = v; 474 475 if ((unsigned int)reg >= PCI_CONF_SIZE) 476 return; 477 478 mutex_enter(sc->sc_cfg_lock); 479 bus_size_t data_reg = bcmpax_conf_addr_write(sc, tag | reg); 480 481 //printf("%s: tag %#lx reg %#x:", __func__, tag, reg); 482 483 if (data_reg) { 484 //printf(" [to %#lx]:\n", data_reg); 485 bcmpax_write_4(sc, data_reg, val); 486 //printf(" %#x\n", val); 487 } 488 489 mutex_exit(sc->sc_cfg_lock); 490 } 491 492 static void 493 bcmpax_conf_interrupt(void *v, int bus, int dev, int ipin, int swiz, int *ilinep) 494 { 495 *ilinep = 5; /* (ipin + swiz) & 3; */ 496 } 497 498 static int 499 bcmpax_conf_hook(void *v, int bus, int dev, int func, pcireg_t id) 500 { 501 if (func > 0) 502 return 0; 503 504 return PCI_CONF_ENABLE_MEM | PCI_CONF_MAP_MEM | PCI_CONF_ENABLE_BM; 505 } 506 507 static int 508 bcmpax_intr(void *v) 509 { 510 struct bcmpax_softc * const sc = v; 511 512 while (bcmpax_read_4(sc, PCIE_SYS_RC_INTX_CSR)) { 513 struct bcmpax_intrhand *ih; 514 mutex_enter(sc->sc_lock); 515 const uint32_t lastgen = sc->sc_intrgen; 516 TAILQ_FOREACH(ih, &sc->sc_intrs, ih_link) { 517 int (* const func)(void *) = ih->ih_func; 518 void * const arg = ih->ih_arg; 519 mutex_exit(sc->sc_lock); 520 int rv = (*func)(arg); 521 if (rv) { 522 return rv; 523 } 524 mutex_enter(sc->sc_lock); 525 /* 526 * Check to see if the interrupt list changed. 527 * If so, restart from the beginning. 528 */ 529 if (lastgen != sc->sc_intrgen) 530 break; 531 } 532 mutex_exit(sc->sc_lock); 533 } 534 535 return 0; 536 } 537 538 static int 539 bcmpax_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *pihp) 540 { 541 if (pa->pa_intrpin == 0) 542 return EINVAL; 543 544 *pihp = pa->pa_intrpin; 545 return 0; 546 } 547 548 static const char * 549 bcmpax_intr_string(void *v, pci_intr_handle_t pih, char *buf, size_t len) 550 { 551 struct bcmpax_softc * const sc = v; 552 553 if (pih) { 554 snprintf(buf, len, "%s int%c", 555 device_xname(sc->sc_dev), 556 (char) ('a' + pih - PCI_INTERRUPT_PIN_A)); 557 return buf; 558 } 559 560 return NULL; 561 } 562 563 static const struct evcnt * 564 bcmpax_intr_evcnt(void *v, pci_intr_handle_t pih) 565 { 566 return NULL; 567 } 568 569 static void * 570 bcmpax_intr_establish(void *v, pci_intr_handle_t pih, int ipl, 571 int (*func)(void *), void *arg, const char *xname) 572 { 573 struct bcmpax_softc * const sc = v; 574 575 KASSERT(!cpu_intr_p()); 576 KASSERT(!cpu_softintr_p()); 577 KASSERT(ipl == IPL_VM); 578 KASSERT(func != NULL); 579 KASSERT(arg != NULL); 580 581 if (pih == 0) 582 return NULL; 583 584 struct bcmpax_intrhand * const ih = kmem_alloc(sizeof(*ih), KM_SLEEP); 585 586 ih->ih_func = func; 587 ih->ih_arg = arg; 588 589 mutex_enter(sc->sc_lock); 590 TAILQ_INSERT_TAIL(&sc->sc_intrs, ih, ih_link); 591 mutex_exit(sc->sc_lock); 592 593 return ih; 594 } 595 596 static void 597 bcmpax_intr_disestablish(void *v, void *vih) 598 { 599 struct bcmpax_softc * const sc = v; 600 struct bcmpax_intrhand * const ih = vih; 601 602 mutex_enter(sc->sc_lock); 603 TAILQ_REMOVE(&sc->sc_intrs, ih, ih_link); 604 sc->sc_intrgen++; 605 mutex_exit(sc->sc_lock); 606 607 kmem_free(ih, sizeof(*ih)); 608 } 609