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/conf.h> 29 #include <sys/sunddi.h> 30 #include <sys/ddi_impldefs.h> 31 #include <sys/kmem.h> 32 #include <sys/dma_i8237A.h> 33 #include <sys/isadma.h> 34 #include <sys/nexusdebug.h> 35 36 /* Bitfield debugging definitions for this file */ 37 #define ISADMA_MAP_DEBUG 0x1 38 #define ISADMA_REGACCESS_DEBUG 0x2 39 40 /* 41 * The isadam nexus serves two functions. The first is to represent a 42 * a placeholder in the device tree for a shared dma controller register 43 * for the SuperIO floppy and parallel ports. 44 * The second function is to virtualize the shared dma controller register 45 * for those two drivers. Rather than creating new ddi routines to manage 46 * the shared register, we will use the ddi register mapping functions to 47 * do this. The two child devices will use ddi_regs_map_setup to map in 48 * their device registers. The isadma nexus will have an aliased entry in 49 * it's own registers property for the shared dma controller register. When 50 * the isadma detects the fact that it's children are trying to map the shared 51 * register, it will intercept this mapping and provide it's own register 52 * access routine to be used to access the register when the child devices 53 * use the ddi_{get,put} calls. 54 * 55 * Sigh, the 82C37 has a weird quirk (BUG?) where when DMA is active on the 56 * the bus, PIO's cannot happen. If they do, they generate bus faults and 57 * cause the system to panic. On PC's, the Intel processor has special 58 * req/grnt lines that prevent PIO's from occuring while DMA is in flight, 59 * unfortunately, hummingbird doesn't support this special req/grnt pair. 60 * I'm going to try and work around this by implementing a cv to stop PIO's 61 * from occuring while DMA is in flight. When each child wants to do DMA, 62 * they need to mask out all other channels using the allmask register. 63 * This nexus keys on this access and locks down the hardware using a cv. 64 * Once the driver's interrupt handler is called it needs to clear 65 * the allmask register. The nexus keys off of this an issues cv wakeups 66 * if necessary. 67 */ 68 /* 69 * Function prototypes for busops routines: 70 */ 71 static int isadma_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 72 off_t off, off_t len, caddr_t *addrp); 73 74 /* 75 * function prototypes for dev ops routines: 76 */ 77 static int isadma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 78 static int isadma_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 79 80 /* 81 * general function prototypes: 82 */ 83 84 /* 85 * bus ops and dev ops structures: 86 */ 87 static struct bus_ops isadma_bus_ops = { 88 BUSO_REV, 89 isadma_map, 90 NULL, 91 NULL, 92 NULL, 93 i_ddi_map_fault, 94 ddi_dma_map, 95 ddi_dma_allochdl, 96 ddi_dma_freehdl, 97 ddi_dma_bindhdl, 98 ddi_dma_unbindhdl, 99 ddi_dma_flush, 100 ddi_dma_win, 101 ddi_dma_mctl, 102 ddi_ctlops, 103 ddi_bus_prop_op, 104 0, /* (*bus_get_eventcookie)(); */ 105 0, /* (*bus_add_eventcall)(); */ 106 0, /* (*bus_remove_eventcall)(); */ 107 0, /* (*bus_post_event)(); */ 108 0, /* (*bus_intr_control)(); */ 109 0, /* (*bus_config)(); */ 110 0, /* (*bus_unconfig)(); */ 111 0, /* (*bus_fm_init)(); */ 112 0, /* (*bus_fm_fini)(); */ 113 0, /* (*bus_fm_access_enter)(); */ 114 0, /* (*bus_fm_access_exit)(); */ 115 0, /* (*bus_power)(); */ 116 i_ddi_intr_ops /* (*bus_intr_op(); */ 117 }; 118 119 static struct dev_ops isadma_ops = { 120 DEVO_REV, 121 0, 122 ddi_no_info, 123 nulldev, 124 0, 125 isadma_attach, 126 isadma_detach, 127 nodev, 128 (struct cb_ops *)0, 129 &isadma_bus_ops 130 }; 131 132 /* 133 * module definitions: 134 */ 135 #include <sys/modctl.h> 136 137 static struct modldrv modldrv = { 138 &mod_driverops, /* Type of module. This one is a driver */ 139 "isadma nexus driver", /* Name of module. */ 140 &isadma_ops, /* driver ops */ 141 }; 142 143 static struct modlinkage modlinkage = { 144 MODREV_1, (void *)&modldrv, NULL 145 }; 146 147 /* 148 * driver global data: 149 */ 150 static void *per_isadma_state; /* per-isadma soft state pointer */ 151 152 /* Global debug data */ 153 uint64_t isadma_sleep_cnt = 0; 154 uint64_t isadma_wakeup_cnt = 0; 155 #ifdef DEBUG 156 int64_t isadma_max_waiter = 0; 157 int64_t isadma_min_waiter = 0xffffll; 158 uint64_t isadma_punt = 0; 159 uint64_t isadma_setting_wdip = 0; 160 uint64_t isadma_clearing_wdip = 0; 161 #endif 162 163 int 164 _init(void) 165 { 166 int e; 167 168 /* 169 * Initialize per-isadma soft state pointer. 170 */ 171 e = ddi_soft_state_init(&per_isadma_state, 172 sizeof (isadma_devstate_t), 1); 173 if (e != 0) 174 return (e); 175 176 /* 177 * Install the module. 178 */ 179 e = mod_install(&modlinkage); 180 if (e != 0) 181 ddi_soft_state_fini(&per_isadma_state); 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_isadma_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 static int 216 isadma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 217 { 218 isadma_devstate_t *isadmap; /* per isadma state pointer */ 219 int32_t instance; 220 int ret = DDI_SUCCESS; 221 222 #ifdef DEBUG 223 debug_print_level = 0; 224 debug_info = 1; 225 #endif 226 switch (cmd) { 227 case DDI_ATTACH: { 228 /* 229 * Allocate soft state for this instance. 230 */ 231 instance = ddi_get_instance(dip); 232 if (ddi_soft_state_zalloc(per_isadma_state, instance) 233 != DDI_SUCCESS) { 234 ret = DDI_FAILURE; 235 goto exit; 236 } 237 isadmap = ddi_get_soft_state(per_isadma_state, instance); 238 isadmap->isadma_dip = dip; 239 240 /* Cache our register property */ 241 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 242 "reg", (caddr_t)&isadmap->isadma_regp, 243 &isadmap->isadma_reglen) != DDI_SUCCESS) { 244 ret = DDI_FAILURE; 245 goto fail_get_prop; 246 } 247 248 /* Initialize our mutex */ 249 mutex_init(&isadmap->isadma_access_lock, NULL, MUTEX_DRIVER, 250 NULL); 251 252 /* Initialize our condition variable */ 253 cv_init(&isadmap->isadma_access_cv, NULL, CV_DRIVER, NULL); 254 255 ddi_report_dev(dip); 256 goto exit; 257 258 } 259 case DDI_RESUME: 260 default: 261 goto exit; 262 } 263 264 fail_get_prop: 265 ddi_soft_state_free(per_isadma_state, instance); 266 267 exit: 268 return (ret); 269 } 270 271 /* 272 * detach entry point: 273 */ 274 static int 275 isadma_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 276 { 277 int instance = ddi_get_instance(dip); 278 isadma_devstate_t *isadmap = 279 ddi_get_soft_state(per_isadma_state, instance); 280 281 switch (cmd) { 282 case DDI_DETACH: 283 cv_destroy(&isadmap->isadma_access_cv); 284 285 mutex_destroy(&isadmap->isadma_access_lock); 286 287 /* free the cached register property */ 288 kmem_free(isadmap->isadma_regp, isadmap->isadma_reglen); 289 290 ddi_soft_state_free(per_isadma_state, instance); 291 return (DDI_SUCCESS); 292 293 case DDI_SUSPEND: 294 return (DDI_SUCCESS); 295 } 296 return (DDI_FAILURE); 297 } 298 299 300 #ifdef DEBUG 301 static void 302 isadma_check_waiters(isadma_devstate_t *isadmap) 303 { 304 if (isadmap->isadma_want > isadma_max_waiter) 305 isadma_max_waiter = isadmap->isadma_want; 306 307 if (isadmap->isadma_want < isadma_min_waiter) 308 isadma_min_waiter = isadmap->isadma_want; 309 } 310 #endif 311 312 static void 313 isadma_dmawait(isadma_devstate_t *isadmap) 314 { 315 316 ASSERT(mutex_owned(&isadmap->isadma_access_lock)); 317 318 /* Wait loop, if the locking dip is set, we wait. */ 319 while (isadmap->isadma_ldip != NULL) { 320 321 isadmap->isadma_want++; 322 cv_wait(&isadmap->isadma_access_cv, 323 &isadmap->isadma_access_lock); 324 isadmap->isadma_want--; 325 isadma_sleep_cnt++; 326 } 327 } 328 329 static void 330 isadma_wakeup(isadma_devstate_t *isadmap) 331 { 332 333 ASSERT(mutex_owned(&isadmap->isadma_access_lock)); 334 335 /* 336 * If somebody wants register access and the lock dip is not set 337 * signal the waiters. 338 */ 339 if (isadmap->isadma_want > 0 && isadmap->isadma_ldip == NULL) { 340 cv_signal(&isadmap->isadma_access_cv); 341 isadma_wakeup_cnt++; 342 } 343 344 } 345 346 /* 347 * Register access vectors 348 */ 349 350 /*ARGSUSED*/ 351 void 352 isadma_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 353 uint8_t *dev_addr, size_t repcount, uint_t flags) 354 { 355 } 356 357 /*ARGSUSED*/ 358 void 359 isadma_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 360 uint16_t *dev_addr, size_t repcount, uint_t flags) 361 { 362 } 363 364 /*ARGSUSED*/ 365 void 366 isadma_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 367 uint32_t *dev_addr, size_t repcount, uint_t flags) 368 { 369 } 370 371 /*ARGSUSED*/ 372 void 373 isadma_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 374 uint64_t *dev_addr, size_t repcount, uint_t flags) 375 { 376 } 377 378 /*ARGSUSED*/ 379 void 380 isadma_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 381 uint8_t *dev_addr, size_t repcount, uint_t flags) 382 { 383 } 384 385 /*ARGSUSED*/ 386 void 387 isadma_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 388 uint16_t *dev_addr, size_t repcount, uint_t flags) 389 { 390 } 391 392 /*ARGSUSED*/ 393 void 394 isadma_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 395 uint32_t *dev_addr, size_t repcount, uint_t flags) 396 { 397 } 398 399 /*ARGSUSED*/ 400 void 401 isadma_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 402 uint64_t *dev_addr, size_t repcount, uint_t flags) 403 { 404 } 405 406 /*ARGSUSED*/ 407 uint8_t 408 isadma_get8(ddi_acc_impl_t *hdlp, uint8_t *addr) 409 { 410 ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private; 411 isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private; 412 off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr; 413 uint8_t ret = 0xff; 414 415 if (IN_CHILD_SPACE(offset)) { /* Pass to parent */ 416 #ifdef DEBUG 417 isadma_punt++; 418 #endif 419 return (ddi_get8(phdl, addr)); 420 } 421 #ifdef DEBUG 422 isadma_check_waiters(isadmap); 423 #endif 424 mutex_enter(&isadmap->isadma_access_lock); 425 isadma_dmawait(isadmap); /* wait until on-going dma completes */ 426 427 /* No 8 bit access to 16 bit address or count registers */ 428 if (IN_16BIT_SPACE(offset)) 429 goto exit; 430 431 /* No 8 bit access to first/last flip-flop registers */ 432 if (IS_SEQREG(offset)) 433 goto exit; 434 435 ret = ddi_get8(phdl, addr); /* Pass to parent */ 436 exit: 437 isadma_wakeup(isadmap); 438 mutex_exit(&isadmap->isadma_access_lock); 439 return (ret); 440 } 441 442 /* 443 * Allow child devices to access this shared register set as if it were 444 * a real 16 bit register. The ISA bridge defines the access to this 445 * 16 bit dma controller & count register by programming an 8 byte register. 446 */ 447 /*ARGSUSED*/ 448 uint16_t 449 isadma_get16(ddi_acc_impl_t *hdlp, uint16_t *addr) 450 { 451 ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private; 452 isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private; 453 off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr; 454 uint16_t ret = 0xffff; 455 456 if (IN_CHILD_SPACE(offset)) { /* Pass to parent */ 457 #ifdef DEBUG 458 isadma_punt++; 459 #endif 460 return (ddi_get16(phdl, addr)); 461 } 462 #ifdef DEBUG 463 isadma_check_waiters(isadmap); 464 #endif 465 mutex_enter(&isadmap->isadma_access_lock); 466 isadma_dmawait(isadmap); /* wait until on-going dma completes */ 467 468 /* Only Allow access to the 16 bit count and address registers */ 469 if (!IN_16BIT_SPACE(offset)) 470 goto exit; 471 472 /* Set the sequencing register to the low byte */ 473 ddi_put8(phdl, (uint8_t *)HDL_TO_SEQREG_ADDR(hdlp, offset), 0); 474 475 /* Read the low byte, then high byte */ 476 ret = ddi_get8(phdl, (uint8_t *)addr); 477 ret = (ddi_get8(phdl, (uint8_t *)addr) << 8) | ret; 478 exit: 479 isadma_wakeup(isadmap); 480 mutex_exit(&isadmap->isadma_access_lock); 481 return (ret); 482 } 483 484 /*ARGSUSED*/ 485 uint32_t 486 isadma_noget32(ddi_acc_impl_t *hdlp, uint32_t *addr) 487 { 488 return (UINT32_MAX); 489 } 490 491 /*ARGSUSED*/ 492 uint64_t 493 isadma_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr) 494 { 495 return (UINT64_MAX); 496 } 497 498 /* 499 * Here's where we do our locking magic. The dma all mask register is an 8 500 * bit register in the dma space, so we look for the access to the 501 * DMAC1_ALLMASK register. When somebody is masking out the dma channels 502 * we lock down the dma engine from further PIO accesses. When the driver 503 * calls back into this routine to clear the allmask register, we wakeup 504 * any blocked threads. 505 */ 506 /*ARGSUSED*/ 507 void 508 isadma_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 509 { 510 ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private; 511 isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private; 512 off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr; 513 514 if (IN_CHILD_SPACE(offset)) { /* Pass to parent */ 515 #ifdef DEBUG 516 isadma_punt++; 517 #endif 518 ddi_put8(phdl, addr, value); 519 return; 520 } 521 #ifdef DEBUG 522 isadma_check_waiters(isadmap); 523 #endif 524 mutex_enter(&isadmap->isadma_access_lock); 525 526 if (isadmap->isadma_ldip == hdlp->ahi_common.ah_dip) { /* owned lock? */ 527 if (END_ISADMA(offset, value)) { 528 isadmap->isadma_ldip = NULL; /* reset lock owner */ 529 #ifdef DEBUG 530 isadma_clearing_wdip++; 531 #endif 532 } 533 } else { /* we don't own the lock */ 534 /* wait until on-going dma completes */ 535 isadma_dmawait(isadmap); 536 537 if (BEGIN_ISADMA(offset, value)) { 538 isadmap->isadma_ldip = hdlp->ahi_common.ah_dip; 539 #ifdef DEBUG 540 isadma_setting_wdip++; 541 #endif 542 } 543 } 544 545 /* No 8 bit access to 16 bit address or count registers */ 546 if (IN_16BIT_SPACE(offset)) 547 goto exit; 548 549 /* No 8 bit access to first/last flip-flop registers */ 550 if (IS_SEQREG(offset)) 551 goto exit; 552 553 ddi_put8(phdl, addr, value); /* Pass to parent */ 554 exit: 555 isadma_wakeup(isadmap); 556 mutex_exit(&isadmap->isadma_access_lock); 557 } 558 559 /* 560 * Allow child devices to access this shared register set as if it were 561 * a real 16 bit register. The ISA bridge defines the access to this 562 * 16 bit dma controller & count register by programming an 8 byte register. 563 */ 564 /*ARGSUSED*/ 565 void 566 isadma_put16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 567 { 568 ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private; 569 isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private; 570 off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr; 571 572 if (IN_CHILD_SPACE(offset)) { /* Pass to parent */ 573 #ifdef DEBUG 574 isadma_punt++; 575 #endif 576 ddi_put16(phdl, addr, value); 577 return; 578 } 579 #ifdef DEBUG 580 isadma_check_waiters(isadmap); 581 #endif 582 mutex_enter(&isadmap->isadma_access_lock); 583 isadma_dmawait(isadmap); /* wait until on-going dma completes */ 584 585 /* Only Allow access to the 16 bit count and address registers */ 586 if (!IN_16BIT_SPACE(offset)) 587 goto exit; 588 589 /* Set the sequencing register to the low byte */ 590 ddi_put8(phdl, (uint8_t *)HDL_TO_SEQREG_ADDR(hdlp, offset), 0); 591 592 /* Write the low byte, then the high byte */ 593 ddi_put8(phdl, (uint8_t *)addr, value & 0xff); 594 ddi_put8(phdl, (uint8_t *)addr, (value >> 8) & 0xff); 595 exit: 596 isadma_wakeup(isadmap); 597 mutex_exit(&isadmap->isadma_access_lock); 598 } 599 600 /*ARGSUSED*/ 601 void 602 isadma_noput32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) {} 603 604 /*ARGSUSED*/ 605 void 606 isadma_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) {} 607 608 #define IS_SAME_REG(r1, r2) (((r1)->ebus_addr_hi == (r2)->ebus_addr_hi) && \ 609 ((r1)->ebus_addr_low == (r2)->ebus_addr_low)) 610 611 /* 612 * The isadma_map routine determines if it's child is attempting to map a 613 * shared reg. If it is, it installs it's own vectors and bus private pointer 614 * and stacks those ops that were already defined. 615 */ 616 static int 617 isadma_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 618 off_t off, off_t len, caddr_t *addrp) 619 { 620 isadma_devstate_t *isadmap = ddi_get_soft_state(per_isadma_state, 621 ddi_get_instance(dip)); 622 dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 623 ebus_regspec_t *child_regp, *regp; 624 int32_t rnumber = mp->map_obj.rnumber; 625 int32_t reglen; 626 int ret; 627 ddi_acc_impl_t *hp; 628 629 /* 630 * Get child regspec since the mapping struct may not have it yet 631 */ 632 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 633 "reg", (caddr_t)®p, ®len) != DDI_SUCCESS) { 634 return (DDI_FAILURE); 635 } 636 637 child_regp = regp + rnumber; 638 639 DPRINTF(ISADMA_MAP_DEBUG, ("isadma_map: child regp %p " 640 "parent regp %p Child reg array %p\n", (void *)child_regp, 641 (void *)isadmap->isadma_regp, (void *)regp)); 642 643 /* Figure out if we're mapping or unmapping */ 644 switch (mp->map_op) { 645 case DDI_MO_MAP_LOCKED: 646 /* Call up device tree to establish mapping */ 647 ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 648 (pdip, rdip, mp, off, len, addrp); 649 650 if ((ret != DDI_SUCCESS) || 651 !IS_SAME_REG(child_regp, isadmap->isadma_regp)) 652 break; 653 654 /* Post-process the mapping request. */ 655 hp = kmem_alloc(sizeof (ddi_acc_impl_t), KM_SLEEP); 656 *hp = *(ddi_acc_impl_t *)mp->map_handlep; 657 impl_acc_hdl_get((ddi_acc_handle_t)mp->map_handlep)-> 658 ah_platform_private = hp; 659 hp = (ddi_acc_impl_t *)mp->map_handlep; 660 hp->ahi_common.ah_bus_private = isadmap; 661 hp->ahi_get8 = isadma_get8; 662 hp->ahi_get16 = isadma_get16; 663 hp->ahi_get32 = isadma_noget32; 664 hp->ahi_get64 = isadma_noget64; 665 hp->ahi_put8 = isadma_put8; 666 hp->ahi_put16 = isadma_put16; 667 hp->ahi_put32 = isadma_noput32; 668 hp->ahi_put64 = isadma_noput64; 669 hp->ahi_rep_get8 = isadma_norep_get8; 670 hp->ahi_rep_get16 = isadma_norep_get16; 671 hp->ahi_rep_get32 = isadma_norep_get32; 672 hp->ahi_rep_get64 = isadma_norep_get64; 673 hp->ahi_rep_put8 = isadma_norep_put8; 674 hp->ahi_rep_put16 = isadma_norep_put16; 675 hp->ahi_rep_put32 = isadma_norep_put32; 676 hp->ahi_rep_put64 = isadma_norep_put64; 677 break; 678 679 case DDI_MO_UNMAP: 680 if (IS_SAME_REG(child_regp, isadmap->isadma_regp)) { 681 hp = impl_acc_hdl_get( 682 (ddi_acc_handle_t)mp->map_handlep)-> 683 ah_platform_private; 684 *(ddi_acc_impl_t *)mp->map_handlep = *hp; 685 kmem_free(hp, sizeof (ddi_acc_impl_t)); 686 } 687 688 /* Call up tree to tear down mapping */ 689 ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 690 (pdip, rdip, mp, off, len, addrp); 691 break; 692 693 default: 694 ret = DDI_FAILURE; 695 break; 696 } 697 698 kmem_free(regp, reglen); 699 return (ret); 700 } 701