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