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