1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27 */ 28 29 30 #include <sys/types.h> 31 #include <sys/conf.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/ddi_impldefs.h> 35 #include <sys/ddi_subrdefs.h> 36 #include <sys/pci.h> 37 #include <sys/autoconf.h> 38 #include <sys/cmn_err.h> 39 #include <sys/errno.h> 40 #include <sys/kmem.h> 41 #include <sys/debug.h> 42 #include <sys/sysmacros.h> 43 #include <sys/pmubus.h> 44 45 #include <sys/nexusdebug.h> 46 /* Bitfield debugging definitions for this file */ 47 #define PMUBUS_MAP_DEBUG 0x1 48 #define PMUBUS_REGACCESS_DEBUG 0x2 49 #define PMUBUS_RW_DEBUG 0x4 50 51 /* 52 * The pmubus nexus is used to manage a shared register space. Rather 53 * than having several driver's physically alias register mappings and 54 * have potential problems with register collisions, this nexus will 55 * serialize the access to this space. 56 * 57 * There are two types of sharing going on here: 58 * 1) Registers within the address space may be shared, however the registers 59 * themselves are unique. The upper bit of the child's high address being zero 60 * signifies this register type. 61 * 62 * 2) The second type of register is one where a device may only own a few 63 * bits in the register. I'll term this as "bit lane" access. This is a more 64 * complicated scenario. The drivers themselves are responsible for knowing 65 * which bit lanes in the register they own. The read of a register only 66 * guarantees that those bits the driver is interested in are valid. If a 67 * driver needs to set bits in a register, a read must be done first to 68 * identify the state of the drivers bits. Depending on which way a bit needs 69 * to be driven, the driver will write a 1 to the bit to toggle it. If a bit 70 * is to remain unchanged, a 0 is written to the bit. So the access to the 71 * bit lane is an xor operation. 72 */ 73 /* 74 * Function prototypes for busops routines: 75 */ 76 static int pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 77 off_t off, off_t len, caddr_t *addrp); 78 static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 79 ddi_ctl_enum_t op, void *arg, void *result); 80 81 /* 82 * function prototypes for dev ops routines: 83 */ 84 static int pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 85 static int pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 86 87 /* 88 * general function prototypes: 89 */ 90 91 /* 92 * bus ops and dev ops structures: 93 */ 94 static struct bus_ops pmubus_bus_ops = { 95 BUSO_REV, 96 pmubus_map, 97 NULL, 98 NULL, 99 NULL, 100 i_ddi_map_fault, 101 NULL, 102 ddi_dma_allochdl, 103 ddi_dma_freehdl, 104 ddi_dma_bindhdl, 105 ddi_dma_unbindhdl, 106 ddi_dma_flush, 107 ddi_dma_win, 108 ddi_dma_mctl, 109 pmubus_ctlops, 110 ddi_bus_prop_op, 111 0, /* (*bus_get_eventcookie)(); */ 112 0, /* (*bus_add_eventcall)(); */ 113 0, /* (*bus_remove_eventcall)(); */ 114 0, /* (*bus_post_event)(); */ 115 0, /* interrupt control */ 116 0, /* bus_config */ 117 0, /* bus_unconfig */ 118 0, /* bus_fm_init */ 119 0, /* bus_fm_fini */ 120 0, /* bus_fm_access_enter */ 121 0, /* bus_fm_access_exit */ 122 0, /* bus_power */ 123 i_ddi_intr_ops /* bus_intr_op */ 124 }; 125 126 static struct dev_ops pmubus_ops = { 127 DEVO_REV, 128 0, 129 ddi_no_info, 130 nulldev, 131 0, 132 pmubus_attach, 133 pmubus_detach, 134 nodev, 135 (struct cb_ops *)0, 136 &pmubus_bus_ops, 137 NULL, 138 ddi_quiesce_not_needed, /* quiesce */ 139 }; 140 141 /* 142 * module definitions: 143 */ 144 #include <sys/modctl.h> 145 extern struct mod_ops mod_driverops; 146 147 static struct modldrv modldrv = { 148 &mod_driverops, /* Type of module. This one is a driver */ 149 "pmubus nexus driver", /* Name of module. */ 150 &pmubus_ops, /* driver ops */ 151 }; 152 153 static struct modlinkage modlinkage = { 154 MODREV_1, (void *)&modldrv, NULL 155 }; 156 157 /* 158 * driver global data: 159 */ 160 static void *per_pmubus_state; /* per-pmubus soft state pointer */ 161 162 int 163 _init(void) 164 { 165 int e; 166 167 /* 168 * Initialize per-pmubus soft state pointer. 169 */ 170 e = ddi_soft_state_init(&per_pmubus_state, 171 sizeof (pmubus_devstate_t), 1); 172 if (e != 0) 173 return (e); 174 175 /* 176 * Install the module. 177 */ 178 e = mod_install(&modlinkage); 179 if (e != 0) 180 ddi_soft_state_fini(&per_pmubus_state); 181 182 return (e); 183 } 184 185 int 186 _fini(void) 187 { 188 int e; 189 190 /* 191 * Remove the module. 192 */ 193 e = mod_remove(&modlinkage); 194 if (e != 0) 195 return (e); 196 197 /* 198 * Free the soft state info. 199 */ 200 ddi_soft_state_fini(&per_pmubus_state); 201 return (e); 202 } 203 204 int 205 _info(struct modinfo *modinfop) 206 { 207 return (mod_info(&modlinkage, modinfop)); 208 } 209 210 /* device driver entry points */ 211 212 /* 213 * attach entry point: 214 * 215 * normal attach: 216 * 217 * create soft state structure (dip, reg, nreg and state fields) 218 * map in configuration header 219 * make sure device is properly configured 220 * report device 221 */ 222 static int 223 pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 224 { 225 pmubus_devstate_t *pmubusp; /* per pmubus state pointer */ 226 int32_t instance; 227 228 switch (cmd) { 229 case DDI_ATTACH: 230 /* 231 * Allocate soft state for this instance. 232 */ 233 instance = ddi_get_instance(dip); 234 if (ddi_soft_state_zalloc(per_pmubus_state, instance) != 235 DDI_SUCCESS) { 236 cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft " 237 "state.\n"); 238 goto fail_exit; 239 } 240 241 pmubusp = ddi_get_soft_state(per_pmubus_state, instance); 242 pmubusp->pmubus_dip = dip; 243 244 /* Cache our register property */ 245 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 246 "reg", (caddr_t)&pmubusp->pmubus_regp, 247 &pmubusp->pmubus_reglen) != DDI_SUCCESS) { 248 cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg " 249 "property.\n"); 250 goto fail_get_regs; 251 } 252 253 /* Cache our ranges property */ 254 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 255 "ranges", (caddr_t)&pmubusp->pmubus_rangep, 256 &pmubusp->pmubus_rnglen) != DDI_SUCCESS) { 257 cmn_err(CE_WARN, "pmubus_attach: Can't acquire the " 258 "ranges property.\n"); 259 goto fail_get_ranges; 260 261 } 262 263 /* Calculate the number of ranges */ 264 pmubusp->pmubus_nranges = 265 pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t); 266 267 /* Set up the mapping to our registers */ 268 if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) != 269 DDI_SUCCESS) { 270 cmn_err(CE_WARN, "pmubus_attach: Can't map in " 271 "register space.\n"); 272 goto fail_map_regs; 273 } 274 275 /* Initialize our register access mutex */ 276 mutex_init(&pmubusp->pmubus_reg_access_lock, NULL, 277 MUTEX_DRIVER, NULL); 278 279 ddi_report_dev(dip); 280 return (DDI_SUCCESS); 281 282 case DDI_RESUME: 283 return (DDI_SUCCESS); 284 } 285 286 fail_map_regs: 287 kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 288 289 fail_get_ranges: 290 kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 291 292 fail_get_regs: 293 ddi_soft_state_free(per_pmubus_state, instance); 294 295 fail_exit: 296 return (DDI_FAILURE); 297 } 298 299 /* 300 * detach entry point: 301 */ 302 static int 303 pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 304 { 305 int instance = ddi_get_instance(dip); 306 pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 307 instance); 308 309 switch (cmd) { 310 case DDI_DETACH: 311 mutex_destroy(&pmubusp->pmubus_reg_access_lock); 312 313 /* Tear down our register mappings */ 314 pci_config_teardown(&pmubusp->pmubus_reghdl); 315 316 /* Free our ranges property */ 317 kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 318 319 /* Free the register property */ 320 kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 321 322 ddi_soft_state_free(per_pmubus_state, instance); 323 break; 324 325 case DDI_SUSPEND: 326 default: 327 break; 328 } 329 330 return (DDI_SUCCESS); 331 } 332 333 /*ARGSUSED*/ 334 void 335 pmubus_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 336 uint8_t *dev_addr, size_t repcount, uint_t flags) 337 { 338 } 339 340 /*ARGSUSED*/ 341 void 342 pmubus_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 343 uint16_t *dev_addr, size_t repcount, uint_t flags) 344 { 345 } 346 347 /*ARGSUSED*/ 348 void 349 pmubus_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 350 uint32_t *dev_addr, size_t repcount, uint_t flags) 351 { 352 } 353 354 /*ARGSUSED*/ 355 void 356 pmubus_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 357 uint64_t *dev_addr, size_t repcount, uint_t flags) 358 { 359 } 360 361 /*ARGSUSED*/ 362 void 363 pmubus_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 364 uint8_t *dev_addr, size_t repcount, uint_t flags) 365 { 366 } 367 368 /*ARGSUSED*/ 369 void 370 pmubus_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 371 uint16_t *dev_addr, size_t repcount, uint_t flags) 372 { 373 } 374 375 /*ARGSUSED*/ 376 void 377 pmubus_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 378 uint32_t *dev_addr, size_t repcount, uint_t flags) 379 { 380 } 381 382 /*ARGSUSED*/ 383 void 384 pmubus_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 385 uint64_t *dev_addr, size_t repcount, uint_t flags) 386 { 387 } 388 389 /*ARGSUSED*/ 390 uint8_t 391 pmubus_get8(ddi_acc_impl_t *hdlp, uint8_t *addr) 392 { 393 ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 394 pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 395 pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 396 off_t offset; 397 uint8_t value; 398 uint8_t mask; 399 400 offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 401 offset &= PMUBUS_REGOFFSET; 402 403 if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 404 if (addr != 0 || 405 pmubus_mapreqp->mapreq_size != sizeof (value)) { 406 cmn_err(CE_WARN, "pmubus_get8: load discarded, " 407 "incorrect access addr/size"); 408 return ((uint8_t)-1); 409 } 410 mask = pmubus_mapreqp->mapreq_mask; 411 } else { 412 mask = (uint8_t)-1; 413 } 414 415 /* gets are simple, we just issue them no locking necessary */ 416 value = pci_config_get8(softsp->pmubus_reghdl, offset) & mask; 417 418 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get8: addr=%p offset=%lx value=%x " 419 "mask=%x\n", (void *)addr, offset, value, mask)); 420 421 return (value); 422 } 423 424 425 /*ARGSUSED*/ 426 uint16_t 427 pmubus_noget16(ddi_acc_impl_t *hdlp, uint16_t *addr) 428 { 429 return ((uint16_t)-1); 430 } 431 432 /*ARGSUSED*/ 433 uint32_t 434 pmubus_get32(ddi_acc_impl_t *hdlp, uint32_t *addr) 435 { 436 ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 437 pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 438 pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 439 off_t offset = (uintptr_t)addr & PMUBUS_REGOFFSET; 440 uint32_t value; 441 uint32_t mask; 442 443 offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 444 offset &= PMUBUS_REGOFFSET; 445 446 if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 447 if (addr != 0 || 448 pmubus_mapreqp->mapreq_size != sizeof (value)) { 449 cmn_err(CE_WARN, "pmubus_get32: load discarded, " 450 "incorrect access addr/size"); 451 return ((uint32_t)-1); 452 } 453 mask = pmubus_mapreqp->mapreq_mask; 454 } else { 455 mask = (uint32_t)-1; 456 } 457 458 /* gets are simple, we just issue them no locking necessary */ 459 value = pci_config_get32(softsp->pmubus_reghdl, offset) & mask; 460 461 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get32: addr=%p offset=%lx value=%x " 462 "mask=%x\n", (void *)addr, offset, value, mask)); 463 464 return (value); 465 } 466 467 /*ARGSUSED*/ 468 uint64_t 469 pmubus_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr) 470 { 471 return ((uint64_t)-1); 472 } 473 474 /*ARGSUSED*/ 475 void 476 pmubus_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 477 { 478 ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 479 pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 480 pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 481 off_t offset; 482 uint8_t tmp; 483 484 offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 485 offset &= PMUBUS_REGOFFSET; 486 487 if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 488 /* 489 * Process "bit lane" register 490 */ 491 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx " 492 "value=%x mask=%lx\n", (void *)addr, offset, value, 493 pmubus_mapreqp->mapreq_mask)); 494 495 if (addr != 0 || 496 pmubus_mapreqp->mapreq_size != sizeof (value)) { 497 cmn_err(CE_WARN, "pmubus_put8: store discarded, " 498 "incorrect access addr/size"); 499 return; 500 } 501 502 mutex_enter(&softsp->pmubus_reg_access_lock); 503 tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 504 tmp &= ~pmubus_mapreqp->mapreq_mask; 505 value &= pmubus_mapreqp->mapreq_mask; 506 tmp |= value; 507 pci_config_put8(softsp->pmubus_reghdl, offset, tmp); 508 mutex_exit(&softsp->pmubus_reg_access_lock); 509 } else { 510 /* 511 * Process shared register 512 */ 513 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx " 514 "value=%x\n", (void *)addr, offset, value)); 515 pci_config_put8(softsp->pmubus_reghdl, offset, value); 516 } 517 518 /* Flush store buffers XXX Should let drivers do this. */ 519 tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 520 } 521 522 /*ARGSUSED*/ 523 void 524 pmubus_noput16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 525 { 526 } 527 528 /*ARGSUSED*/ 529 void 530 pmubus_put32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 531 { 532 ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 533 pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 534 pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 535 off_t offset; 536 uint32_t tmp; 537 538 offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 539 offset &= PMUBUS_REGOFFSET; 540 541 if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 542 /* 543 * Process "bit lane" register 544 */ 545 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx " 546 "value=%x mask=%lx\n", (void *)addr, offset, value, 547 pmubus_mapreqp->mapreq_mask)); 548 549 if (addr != 0 || 550 pmubus_mapreqp->mapreq_size != sizeof (value)) { 551 cmn_err(CE_WARN, "pmubus_put32: store discarded, " 552 "incorrect access addr/size"); 553 return; 554 } 555 556 mutex_enter(&softsp->pmubus_reg_access_lock); 557 tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 558 tmp &= ~pmubus_mapreqp->mapreq_mask; 559 value &= pmubus_mapreqp->mapreq_mask; 560 tmp |= value; 561 pci_config_put32(softsp->pmubus_reghdl, offset, tmp); 562 mutex_exit(&softsp->pmubus_reg_access_lock); 563 } else { 564 /* 565 * Process shared register 566 */ 567 DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx " 568 "value=%x\n", (void *)addr, offset, value)); 569 pci_config_put32(softsp->pmubus_reghdl, offset, value); 570 } 571 572 /* Flush store buffers XXX Should let drivers do this. */ 573 tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 574 } 575 576 /*ARGSUSED*/ 577 void 578 pmubus_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 579 { 580 } 581 582 /* 583 * This routine is used to translate our children's register properties. 584 * The return value specifies which type of register has been translated. 585 */ 586 /*ARGSUSED*/ 587 int 588 pmubus_apply_range(pmubus_devstate_t *pmubusp, dev_info_t *rdip, 589 pmubus_regspec_t *regp, pci_regspec_t *pci_regp) 590 { 591 pmu_rangespec_t *rangep; 592 int nranges = pmubusp->pmubus_nranges; 593 int i; 594 off_t offset; 595 int ret = DDI_ME_REGSPEC_RANGE; 596 uint64_t addr; 597 598 addr = regp->reg_addr & ~MAPPING_SHARED_BITS_MASK; 599 600 /* Scan the ranges for a match */ 601 for (i = 0, rangep = pmubusp->pmubus_rangep; i < nranges; i++, rangep++) 602 if ((rangep->rng_child <= addr) && 603 ((addr + regp->reg_size) <= 604 (rangep->rng_child + rangep->rng_size))) { 605 ret = DDI_SUCCESS; 606 break; 607 } 608 609 if (ret != DDI_SUCCESS) 610 return (ret); 611 612 /* Get the translated register */ 613 offset = addr - rangep->rng_child; 614 pci_regp->pci_phys_hi = rangep->rng_parent_hi; 615 pci_regp->pci_phys_mid = rangep->rng_parent_mid; 616 pci_regp->pci_phys_low = rangep->rng_parent_low + offset; 617 pci_regp->pci_size_hi = 0; 618 pci_regp->pci_size_low = MIN(regp->reg_size, rangep->rng_size); 619 620 /* Figure out the type of reg space we have */ 621 if (pci_regp->pci_phys_hi == pmubusp->pmubus_regp->pci_phys_hi) { 622 ret = MAPREQ_SHARED_REG; 623 if (regp->reg_addr & MAPPING_SHARED_BITS_MASK) 624 ret |= MAPREQ_SHARED_BITS; 625 } 626 627 return (ret); 628 } 629 630 static uint64_t 631 pmubus_mask(pmubus_obpregspec_t *regs, int32_t rnumber, 632 uint64_t *masks) 633 { 634 int i; 635 long n = -1; 636 637 for (i = 0; i <= rnumber; i++) 638 if (regs[i].reg_addr_hi & 0x80000000) 639 n++; 640 641 if (n == -1) { 642 cmn_err(CE_WARN, "pmubus_mask: missing mask"); 643 return (0); 644 } 645 646 return (masks[n]); 647 } 648 649 /* 650 * The pmubus_map routine determines if it's child is attempting to map a 651 * shared reg. If it is, it installs it's own vectors and bus private pointer. 652 */ 653 static int 654 pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 655 off_t off, off_t len, caddr_t *addrp) 656 { 657 pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 658 ddi_get_instance(dip)); 659 dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 660 pmubus_regspec_t pmubus_rp; 661 pmubus_obpregspec_t *pmubus_regs = NULL; 662 int pmubus_regs_size; 663 uint64_t *pmubus_regmask = NULL; 664 int pmubus_regmask_size; 665 pci_regspec_t pci_reg; 666 int32_t rnumber = mp->map_obj.rnumber; 667 pmubus_mapreq_t *pmubus_mapreqp; 668 int ret = DDI_SUCCESS; 669 char *map_fail1 = "Map Type Unknown"; 670 char *map_fail2 = "DDI_MT_REGSPEC"; 671 char *s = map_fail1; 672 673 *addrp = NULL; 674 675 /* 676 * Handle the mapping according to its type. 677 */ 678 DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%lx len=%lx\n", 679 ddi_get_name(rdip), ddi_get_instance(rdip), off, len)); 680 switch (mp->map_type) { 681 case DDI_MT_RNUMBER: { 682 int n; 683 684 /* 685 * Get the "reg" property from the device node and convert 686 * it to our parent's format. 687 */ 688 rnumber = mp->map_obj.rnumber; 689 DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x " 690 "handlep=%p\n", ddi_get_name(rdip), ddi_get_instance(rdip), 691 rnumber, (void *)mp->map_handlep)); 692 693 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 694 "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) != 695 DDI_SUCCESS) { 696 DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg " 697 "property\n")); 698 ret = DDI_ME_RNUMBER_RANGE; 699 goto done; 700 } 701 n = pmubus_regs_size / sizeof (pmubus_obpregspec_t); 702 703 if (rnumber < 0 || rnumber >= n) { 704 DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n")); 705 ret = DDI_ME_RNUMBER_RANGE; 706 goto done; 707 } 708 709 pmubus_rp.reg_addr = ((uint64_t) 710 pmubus_regs[rnumber].reg_addr_hi << 32) | 711 (uint64_t)pmubus_regs[rnumber].reg_addr_lo; 712 pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size; 713 714 (void) ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 715 "register-mask", (caddr_t)&pmubus_regmask, 716 &pmubus_regmask_size); 717 718 /* Create our own mapping private structure */ 719 break; 720 721 } 722 case DDI_MT_REGSPEC: 723 /* 724 * This bus has no bus children that have to map in an address 725 * space, so we can assume that we'll never see an 726 * DDI_MT_REGSPEC request 727 */ 728 s = map_fail2; 729 ret = DDI_ME_REGSPEC_RANGE; 730 /*FALLTHROUGH*/ 731 732 default: 733 if (ret == DDI_SUCCESS) 734 ret = DDI_ME_INVAL; 735 DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: " 736 "%s is an invalid map type.\nmap request handlep=0x%p\n", 737 ddi_get_name(rdip), ddi_get_instance(rdip), s, (void *)mp)); 738 739 ret = DDI_ME_RNUMBER_RANGE; 740 goto done; 741 } 742 743 /* Adjust our reg property with offset and length */ 744 if ((pmubus_rp.reg_addr + off) > 745 (pmubus_rp.reg_addr + pmubus_rp.reg_size)) { 746 ret = DDI_ME_INVAL; 747 goto done; 748 } 749 750 pmubus_rp.reg_addr += off; 751 if (len && (len < pmubus_rp.reg_size)) 752 pmubus_rp.reg_size = len; 753 754 /* Translate our child regspec into our parents address domain */ 755 ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg); 756 757 /* Check if the apply range failed */ 758 if (ret < DDI_SUCCESS) 759 goto done; 760 761 /* 762 * If our childs xlated address falls into our shared address range, 763 * setup our mapping handle. 764 */ 765 if (ret > DDI_SUCCESS) { 766 /* Figure out if we're mapping or unmapping */ 767 switch (mp->map_op) { 768 case DDI_MO_MAP_LOCKED: { 769 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 770 771 pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp), 772 KM_SLEEP); 773 774 pmubus_mapreqp->mapreq_flags = ret; 775 pmubus_mapreqp->mapreq_softsp = pmubusp; 776 pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr; 777 pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size; 778 779 if (ret & MAPREQ_SHARED_BITS) { 780 pmubus_mapreqp->mapreq_mask = 781 pmubus_mask(pmubus_regs, rnumber, 782 pmubus_regmask); 783 DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d " 784 "mask=%lx\n", rnumber, 785 pmubus_mapreqp->mapreq_mask)); 786 if (pmubus_mapreqp->mapreq_mask == 0) { 787 kmem_free(pmubus_mapreqp, 788 sizeof (pmubus_mapreq_t)); 789 ret = DDI_ME_INVAL; 790 break; 791 } 792 } 793 794 hp->ahi_common.ah_bus_private = pmubus_mapreqp; 795 796 /* Initialize the access vectors */ 797 hp->ahi_get8 = pmubus_get8; 798 hp->ahi_get16 = pmubus_noget16; 799 hp->ahi_get32 = pmubus_get32; 800 hp->ahi_get64 = pmubus_noget64; 801 hp->ahi_put8 = pmubus_put8; 802 hp->ahi_put16 = pmubus_noput16; 803 hp->ahi_put32 = pmubus_put32; 804 hp->ahi_put64 = pmubus_noput64; 805 hp->ahi_rep_get8 = pmubus_norep_get8; 806 hp->ahi_rep_get16 = pmubus_norep_get16; 807 hp->ahi_rep_get32 = pmubus_norep_get32; 808 hp->ahi_rep_get64 = pmubus_norep_get64; 809 hp->ahi_rep_put8 = pmubus_norep_put8; 810 hp->ahi_rep_put16 = pmubus_norep_put16; 811 hp->ahi_rep_put32 = pmubus_norep_put32; 812 hp->ahi_rep_put64 = pmubus_norep_put64; 813 814 ret = DDI_SUCCESS; 815 break; 816 } 817 818 case DDI_MO_UNMAP: { 819 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 820 821 pmubus_mapreqp = hp->ahi_common.ah_bus_private; 822 823 /* Free the our map request struct */ 824 kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t)); 825 826 ret = DDI_SUCCESS; 827 break; 828 } 829 830 default: 831 ret = DDI_ME_UNSUPPORTED; 832 } 833 } else { 834 /* Prepare the map request struct for a call to our parent */ 835 mp->map_type = DDI_MT_REGSPEC; 836 mp->map_obj.rp = (struct regspec *)&pci_reg; 837 838 /* Pass the mapping operation up the device tree */ 839 ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 840 (pdip, rdip, mp, off, len, addrp); 841 } 842 843 done: 844 if (pmubus_regs != NULL) 845 kmem_free(pmubus_regs, pmubus_regs_size); 846 if (pmubus_regmask != NULL) 847 kmem_free(pmubus_regmask, pmubus_regmask_size); 848 return (ret); 849 } 850 851 static int 852 pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 853 ddi_ctl_enum_t op, void *arg, void *result) 854 { 855 dev_info_t *child = (dev_info_t *)arg; 856 pmubus_obpregspec_t *pmubus_rp; 857 char name[9]; 858 int reglen; 859 860 switch (op) { 861 case DDI_CTLOPS_INITCHILD: 862 863 if (ddi_getlongprop(DDI_DEV_T_ANY, child, 864 DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp, 865 ®len) != DDI_SUCCESS) { 866 867 return (DDI_FAILURE); 868 } 869 870 if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) { 871 cmn_err(CE_WARN, 872 "pmubus: reg property not well-formed for " 873 "%s size=%d\n", ddi_node_name(child), reglen); 874 kmem_free(pmubus_rp, reglen); 875 876 return (DDI_FAILURE); 877 } 878 (void) snprintf(name, sizeof (name), "%x,%x", 879 pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo); 880 ddi_set_name_addr(child, name); 881 kmem_free(pmubus_rp, reglen); 882 883 return (DDI_SUCCESS); 884 885 case DDI_CTLOPS_UNINITCHILD: 886 887 ddi_set_name_addr(child, NULL); 888 ddi_remove_minor_node(child, NULL); 889 impl_rem_dev_props(child); 890 891 return (DDI_SUCCESS); 892 default: 893 break; 894 } 895 896 return (ddi_ctlops(dip, rdip, op, arg, result)); 897 } 898