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