xref: /illumos-gate/usr/src/uts/sun4u/io/isadma.c (revision 903a11ebdc8df157c4700150f41f1f262f4a8ae8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*903a11ebSrh87107  * Common Development and Distribution License (the "License").
6*903a11ebSrh87107  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*903a11ebSrh87107  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/conf.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/dma_i8237A.h>
337c478bd9Sstevel@tonic-gate #include <sys/isadma.h>
347c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /* Bitfield debugging definitions for this file */
377c478bd9Sstevel@tonic-gate #define	ISADMA_MAP_DEBUG	0x1
387c478bd9Sstevel@tonic-gate #define	ISADMA_REGACCESS_DEBUG	0x2
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * The isadam nexus serves two functions.  The first is to represent a
427c478bd9Sstevel@tonic-gate  * a placeholder in the device tree for a shared dma controller register
437c478bd9Sstevel@tonic-gate  * for the SuperIO floppy and parallel ports.
447c478bd9Sstevel@tonic-gate  * The second function is to virtualize the shared dma controller register
457c478bd9Sstevel@tonic-gate  * for those two drivers.  Rather than creating new ddi routines to manage
467c478bd9Sstevel@tonic-gate  * the shared register, we will use the ddi register mapping functions to
477c478bd9Sstevel@tonic-gate  * do this.  The two child devices will use ddi_regs_map_setup to map in
487c478bd9Sstevel@tonic-gate  * their device registers.  The isadma nexus will have an aliased entry in
497c478bd9Sstevel@tonic-gate  * it's own registers property for the shared dma controller register.  When
507c478bd9Sstevel@tonic-gate  * the isadma detects the fact that it's children are trying to map the shared
517c478bd9Sstevel@tonic-gate  * register, it will intercept this mapping and provide it's own register
527c478bd9Sstevel@tonic-gate  * access routine to be used to access the register when the child devices
537c478bd9Sstevel@tonic-gate  * use the ddi_{get,put} calls.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * Sigh, the 82C37 has a weird quirk (BUG?) where when DMA is active on the
567c478bd9Sstevel@tonic-gate  * the bus, PIO's cannot happen.  If they do, they generate bus faults and
577c478bd9Sstevel@tonic-gate  * cause the system to panic.  On PC's, the Intel processor has special
587c478bd9Sstevel@tonic-gate  * req/grnt lines that prevent PIO's from occuring while DMA is in flight,
597c478bd9Sstevel@tonic-gate  * unfortunately, hummingbird doesn't support this special req/grnt pair.
607c478bd9Sstevel@tonic-gate  * I'm going to try and work around this by implementing a cv to stop PIO's
617c478bd9Sstevel@tonic-gate  * from occuring while DMA is in flight.  When each child wants to do DMA,
627c478bd9Sstevel@tonic-gate  * they need to mask out all other channels using the allmask register.
637c478bd9Sstevel@tonic-gate  * This nexus keys on this access and locks down the hardware using a cv.
647c478bd9Sstevel@tonic-gate  * Once the driver's interrupt handler is called it needs to clear
657c478bd9Sstevel@tonic-gate  * the allmask register.  The nexus keys off of this an issues cv wakeups
667c478bd9Sstevel@tonic-gate  * if necessary.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * Function prototypes for busops routines:
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate static int isadma_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
727c478bd9Sstevel@tonic-gate     off_t off, off_t len, caddr_t *addrp);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * function prototypes for dev ops routines:
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate static int isadma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
787c478bd9Sstevel@tonic-gate static int isadma_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * general function prototypes:
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * bus ops and dev ops structures:
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate static struct bus_ops isadma_bus_ops = {
887c478bd9Sstevel@tonic-gate 	BUSO_REV,
897c478bd9Sstevel@tonic-gate 	isadma_map,
907c478bd9Sstevel@tonic-gate 	NULL,
917c478bd9Sstevel@tonic-gate 	NULL,
927c478bd9Sstevel@tonic-gate 	NULL,
937c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
947c478bd9Sstevel@tonic-gate 	ddi_dma_map,
957c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
967c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
977c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
987c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
997c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
1007c478bd9Sstevel@tonic-gate 	ddi_dma_win,
1017c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,
1027c478bd9Sstevel@tonic-gate 	ddi_ctlops,
1037c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
1047c478bd9Sstevel@tonic-gate 	0,			/* (*bus_get_eventcookie)();	*/
1057c478bd9Sstevel@tonic-gate 	0,			/* (*bus_add_eventcall)();	*/
1067c478bd9Sstevel@tonic-gate 	0,			/* (*bus_remove_eventcall)();	*/
1077c478bd9Sstevel@tonic-gate 	0,			/* (*bus_post_event)();		*/
1087c478bd9Sstevel@tonic-gate 	0,			/* (*bus_intr_control)();	*/
1097c478bd9Sstevel@tonic-gate 	0,			/* (*bus_config)();		*/
1107c478bd9Sstevel@tonic-gate 	0,			/* (*bus_unconfig)();		*/
1117c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_init)();		*/
1127c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_fini)();		*/
1137c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_enter)();	*/
1147c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_exit)();	*/
1157c478bd9Sstevel@tonic-gate 	0,			/* (*bus_power)();		*/
1167c478bd9Sstevel@tonic-gate 	i_ddi_intr_ops		/* (*bus_intr_op();		*/
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static struct dev_ops isadma_ops = {
1207c478bd9Sstevel@tonic-gate 	DEVO_REV,
1217c478bd9Sstevel@tonic-gate 	0,
1227c478bd9Sstevel@tonic-gate 	ddi_no_info,
1237c478bd9Sstevel@tonic-gate 	nulldev,
1247c478bd9Sstevel@tonic-gate 	0,
1257c478bd9Sstevel@tonic-gate 	isadma_attach,
1267c478bd9Sstevel@tonic-gate 	isadma_detach,
1277c478bd9Sstevel@tonic-gate 	nodev,
1287c478bd9Sstevel@tonic-gate 	(struct cb_ops *)0,
1297c478bd9Sstevel@tonic-gate 	&isadma_bus_ops
1307c478bd9Sstevel@tonic-gate };
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * module definitions:
1347c478bd9Sstevel@tonic-gate  */
1357c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1387c478bd9Sstevel@tonic-gate 	&mod_driverops, 	/* Type of module.  This one is a driver */
1397c478bd9Sstevel@tonic-gate 	"isadma nexus driver",	/* Name of module. */
1407c478bd9Sstevel@tonic-gate 	&isadma_ops,		/* driver ops */
1417c478bd9Sstevel@tonic-gate };
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1447c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * driver global data:
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate static void *per_isadma_state;		/* per-isadma soft state pointer */
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /* Global debug data */
1537c478bd9Sstevel@tonic-gate uint64_t isadma_sleep_cnt = 0;
1547c478bd9Sstevel@tonic-gate uint64_t isadma_wakeup_cnt = 0;
1557c478bd9Sstevel@tonic-gate #ifdef DEBUG
1567c478bd9Sstevel@tonic-gate int64_t isadma_max_waiter = 0;
1577c478bd9Sstevel@tonic-gate int64_t isadma_min_waiter = 0xffffll;
1587c478bd9Sstevel@tonic-gate uint64_t isadma_punt = 0;
1597c478bd9Sstevel@tonic-gate uint64_t isadma_setting_wdip = 0;
1607c478bd9Sstevel@tonic-gate uint64_t isadma_clearing_wdip = 0;
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate int
1647c478bd9Sstevel@tonic-gate _init(void)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	int e;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/*
1697c478bd9Sstevel@tonic-gate 	 * Initialize per-isadma soft state pointer.
1707c478bd9Sstevel@tonic-gate 	 */
1717c478bd9Sstevel@tonic-gate 	e = ddi_soft_state_init(&per_isadma_state,
1727c478bd9Sstevel@tonic-gate 	    sizeof (isadma_devstate_t), 1);
1737c478bd9Sstevel@tonic-gate 	if (e != 0)
1747c478bd9Sstevel@tonic-gate 		return (e);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 * Install the module.
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	e = mod_install(&modlinkage);
1807c478bd9Sstevel@tonic-gate 	if (e != 0)
1817c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&per_isadma_state);
1827c478bd9Sstevel@tonic-gate 	return (e);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate int
1867c478bd9Sstevel@tonic-gate _fini(void)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	int e;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/*
1917c478bd9Sstevel@tonic-gate 	 * Remove the module.
1927c478bd9Sstevel@tonic-gate 	 */
1937c478bd9Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
1947c478bd9Sstevel@tonic-gate 	if (e != 0)
1957c478bd9Sstevel@tonic-gate 		return (e);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/*
1987c478bd9Sstevel@tonic-gate 	 * Free the soft state info.
1997c478bd9Sstevel@tonic-gate 	 */
2007c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&per_isadma_state);
2017c478bd9Sstevel@tonic-gate 	return (e);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate int
2057c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /* device driver entry points */
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * attach entry point:
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate static int
2167c478bd9Sstevel@tonic-gate isadma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap;	/* per isadma state pointer */
2197c478bd9Sstevel@tonic-gate 	int32_t instance;
2207c478bd9Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate #ifdef DEBUG
2237c478bd9Sstevel@tonic-gate 	debug_print_level = 0;
2247c478bd9Sstevel@tonic-gate 	debug_info = 1;
2257c478bd9Sstevel@tonic-gate #endif
2267c478bd9Sstevel@tonic-gate 	switch (cmd) {
2277c478bd9Sstevel@tonic-gate 	case DDI_ATTACH: {
2287c478bd9Sstevel@tonic-gate 		/*
2297c478bd9Sstevel@tonic-gate 		 * Allocate soft state for this instance.
2307c478bd9Sstevel@tonic-gate 		 */
2317c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
2327c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(per_isadma_state, instance)
2337c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
2347c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
2357c478bd9Sstevel@tonic-gate 			goto exit;
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 		isadmap = ddi_get_soft_state(per_isadma_state, instance);
2387c478bd9Sstevel@tonic-gate 		isadmap->isadma_dip = dip;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		/* Cache our register property */
241a3282898Scth 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2427c478bd9Sstevel@tonic-gate 		    "reg", (caddr_t)&isadmap->isadma_regp,
2437c478bd9Sstevel@tonic-gate 		    &isadmap->isadma_reglen) != DDI_SUCCESS) {
2447c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
2457c478bd9Sstevel@tonic-gate 			goto fail_get_prop;
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		/* Initialize our mutex */
2497c478bd9Sstevel@tonic-gate 		mutex_init(&isadmap->isadma_access_lock, NULL, MUTEX_DRIVER,
2507c478bd9Sstevel@tonic-gate 		    NULL);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 		/* Initialize our condition variable */
2537c478bd9Sstevel@tonic-gate 		cv_init(&isadmap->isadma_access_cv, NULL, CV_DRIVER, NULL);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 		ddi_report_dev(dip);
2567c478bd9Sstevel@tonic-gate 		goto exit;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
2607c478bd9Sstevel@tonic-gate 	default:
2617c478bd9Sstevel@tonic-gate 		goto exit;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate fail_get_prop:
2657c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(per_isadma_state, instance);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate exit:
2687c478bd9Sstevel@tonic-gate 	return (ret);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * detach entry point:
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate static int
2757c478bd9Sstevel@tonic-gate isadma_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
2787c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap =
2797c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(per_isadma_state, instance);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	switch (cmd) {
2827c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
2837c478bd9Sstevel@tonic-gate 		cv_destroy(&isadmap->isadma_access_cv);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		mutex_destroy(&isadmap->isadma_access_lock);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 		/* free the cached register property */
2887c478bd9Sstevel@tonic-gate 		kmem_free(isadmap->isadma_regp, isadmap->isadma_reglen);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(per_isadma_state, instance);
2917c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
2947c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate #ifdef DEBUG
3017c478bd9Sstevel@tonic-gate static void
3027c478bd9Sstevel@tonic-gate isadma_check_waiters(isadma_devstate_t *isadmap)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	if (isadmap->isadma_want > isadma_max_waiter)
3057c478bd9Sstevel@tonic-gate 		isadma_max_waiter = isadmap->isadma_want;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (isadmap->isadma_want < isadma_min_waiter)
3087c478bd9Sstevel@tonic-gate 		isadma_min_waiter = isadmap->isadma_want;
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate #endif
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static void
3137c478bd9Sstevel@tonic-gate isadma_dmawait(isadma_devstate_t *isadmap)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&isadmap->isadma_access_lock));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	/* Wait loop, if the locking dip is set, we wait. */
3197c478bd9Sstevel@tonic-gate 	while (isadmap->isadma_ldip != NULL) {
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		isadmap->isadma_want++;
3227c478bd9Sstevel@tonic-gate 		cv_wait(&isadmap->isadma_access_cv,
3237c478bd9Sstevel@tonic-gate 		    &isadmap->isadma_access_lock);
3247c478bd9Sstevel@tonic-gate 		isadmap->isadma_want--;
3257c478bd9Sstevel@tonic-gate 		isadma_sleep_cnt++;
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate static void
3307c478bd9Sstevel@tonic-gate isadma_wakeup(isadma_devstate_t *isadmap)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&isadmap->isadma_access_lock));
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * If somebody wants register access and the lock dip is not set
3377c478bd9Sstevel@tonic-gate 	 * signal the waiters.
3387c478bd9Sstevel@tonic-gate 	 */
3397c478bd9Sstevel@tonic-gate 	if (isadmap->isadma_want > 0 && isadmap->isadma_ldip == NULL) {
3407c478bd9Sstevel@tonic-gate 		cv_signal(&isadmap->isadma_access_cv);
3417c478bd9Sstevel@tonic-gate 		isadma_wakeup_cnt++;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate  * Register access vectors
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3517c478bd9Sstevel@tonic-gate void
3527c478bd9Sstevel@tonic-gate isadma_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr,
3537c478bd9Sstevel@tonic-gate     uint8_t *dev_addr, size_t repcount, uint_t flags)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3587c478bd9Sstevel@tonic-gate void
3597c478bd9Sstevel@tonic-gate isadma_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr,
3607c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3657c478bd9Sstevel@tonic-gate void
3667c478bd9Sstevel@tonic-gate isadma_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr,
3677c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3727c478bd9Sstevel@tonic-gate void
3737c478bd9Sstevel@tonic-gate isadma_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr,
3747c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3797c478bd9Sstevel@tonic-gate void
3807c478bd9Sstevel@tonic-gate isadma_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr,
3817c478bd9Sstevel@tonic-gate     uint8_t *dev_addr, size_t repcount, uint_t flags)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3867c478bd9Sstevel@tonic-gate void
3877c478bd9Sstevel@tonic-gate isadma_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr,
3887c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3937c478bd9Sstevel@tonic-gate void
3947c478bd9Sstevel@tonic-gate isadma_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr,
3957c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4007c478bd9Sstevel@tonic-gate void
4017c478bd9Sstevel@tonic-gate isadma_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr,
4027c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4077c478bd9Sstevel@tonic-gate uint8_t
4087c478bd9Sstevel@tonic-gate isadma_get8(ddi_acc_impl_t *hdlp, uint8_t *addr)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
4117c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
4127c478bd9Sstevel@tonic-gate 	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;
4137c478bd9Sstevel@tonic-gate 	uint8_t ret = 0xff;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
4167c478bd9Sstevel@tonic-gate #ifdef DEBUG
4177c478bd9Sstevel@tonic-gate 		isadma_punt++;
4187c478bd9Sstevel@tonic-gate #endif
4197c478bd9Sstevel@tonic-gate 		return (ddi_get8(phdl, addr));
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate #ifdef DEBUG
4227c478bd9Sstevel@tonic-gate 	isadma_check_waiters(isadmap);
4237c478bd9Sstevel@tonic-gate #endif
4247c478bd9Sstevel@tonic-gate 	mutex_enter(&isadmap->isadma_access_lock);
4257c478bd9Sstevel@tonic-gate 	isadma_dmawait(isadmap);	/* wait until on-going dma completes */
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	/* No 8 bit access to 16 bit address or count registers */
4287c478bd9Sstevel@tonic-gate 	if (IN_16BIT_SPACE(offset))
4297c478bd9Sstevel@tonic-gate 		goto exit;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* No 8 bit access to first/last flip-flop registers */
4327c478bd9Sstevel@tonic-gate 	if (IS_SEQREG(offset))
4337c478bd9Sstevel@tonic-gate 		goto exit;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	ret = ddi_get8(phdl, addr);	/* Pass to parent */
4367c478bd9Sstevel@tonic-gate exit:
4377c478bd9Sstevel@tonic-gate 	isadma_wakeup(isadmap);
4387c478bd9Sstevel@tonic-gate 	mutex_exit(&isadmap->isadma_access_lock);
4397c478bd9Sstevel@tonic-gate 	return (ret);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * Allow child devices to access this shared register set as if it were
4447c478bd9Sstevel@tonic-gate  * a real 16 bit register.  The ISA bridge defines the access to this
4457c478bd9Sstevel@tonic-gate  * 16 bit dma controller & count register by programming an 8 byte register.
4467c478bd9Sstevel@tonic-gate  */
4477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4487c478bd9Sstevel@tonic-gate uint16_t
4497c478bd9Sstevel@tonic-gate isadma_get16(ddi_acc_impl_t *hdlp, uint16_t *addr)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
4527c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
4537c478bd9Sstevel@tonic-gate 	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;
4547c478bd9Sstevel@tonic-gate 	uint16_t ret = 0xffff;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
4577c478bd9Sstevel@tonic-gate #ifdef DEBUG
4587c478bd9Sstevel@tonic-gate 		isadma_punt++;
4597c478bd9Sstevel@tonic-gate #endif
4607c478bd9Sstevel@tonic-gate 		return (ddi_get16(phdl, addr));
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate #ifdef DEBUG
4637c478bd9Sstevel@tonic-gate 	isadma_check_waiters(isadmap);
4647c478bd9Sstevel@tonic-gate #endif
4657c478bd9Sstevel@tonic-gate 	mutex_enter(&isadmap->isadma_access_lock);
4667c478bd9Sstevel@tonic-gate 	isadma_dmawait(isadmap);	/* wait until on-going dma completes */
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	/* Only Allow access to the 16 bit count and address registers */
4697c478bd9Sstevel@tonic-gate 	if (!IN_16BIT_SPACE(offset))
4707c478bd9Sstevel@tonic-gate 		goto exit;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* Set the sequencing register to the low byte */
4737c478bd9Sstevel@tonic-gate 	ddi_put8(phdl, (uint8_t *)HDL_TO_SEQREG_ADDR(hdlp, offset), 0);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/* Read the low byte, then high byte */
4767c478bd9Sstevel@tonic-gate 	ret = ddi_get8(phdl, (uint8_t *)addr);
4777c478bd9Sstevel@tonic-gate 	ret = (ddi_get8(phdl, (uint8_t *)addr) << 8) | ret;
4787c478bd9Sstevel@tonic-gate exit:
4797c478bd9Sstevel@tonic-gate 	isadma_wakeup(isadmap);
4807c478bd9Sstevel@tonic-gate 	mutex_exit(&isadmap->isadma_access_lock);
4817c478bd9Sstevel@tonic-gate 	return (ret);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4857c478bd9Sstevel@tonic-gate uint32_t
4867c478bd9Sstevel@tonic-gate isadma_noget32(ddi_acc_impl_t *hdlp, uint32_t *addr)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	return (UINT32_MAX);
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4927c478bd9Sstevel@tonic-gate uint64_t
4937c478bd9Sstevel@tonic-gate isadma_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr)
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 	return (UINT64_MAX);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * Here's where we do our locking magic.  The dma all mask register is an 8
5007c478bd9Sstevel@tonic-gate  * bit register in the dma space, so we look for the access to the
5017c478bd9Sstevel@tonic-gate  * DMAC1_ALLMASK register.  When somebody is masking out the dma channels
5027c478bd9Sstevel@tonic-gate  * we lock down the dma engine from further PIO accesses.  When the driver
5037c478bd9Sstevel@tonic-gate  * calls back into this routine to clear the allmask register, we wakeup
5047c478bd9Sstevel@tonic-gate  * any blocked threads.
5057c478bd9Sstevel@tonic-gate  */
5067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5077c478bd9Sstevel@tonic-gate void
5087c478bd9Sstevel@tonic-gate isadma_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
5117c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
5127c478bd9Sstevel@tonic-gate 	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
5157c478bd9Sstevel@tonic-gate #ifdef DEBUG
5167c478bd9Sstevel@tonic-gate 		isadma_punt++;
5177c478bd9Sstevel@tonic-gate #endif
5187c478bd9Sstevel@tonic-gate 		ddi_put8(phdl, addr, value);
5197c478bd9Sstevel@tonic-gate 		return;
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate #ifdef DEBUG
5227c478bd9Sstevel@tonic-gate 	isadma_check_waiters(isadmap);
5237c478bd9Sstevel@tonic-gate #endif
5247c478bd9Sstevel@tonic-gate 	mutex_enter(&isadmap->isadma_access_lock);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (isadmap->isadma_ldip == hdlp->ahi_common.ah_dip) { /* owned lock? */
5277c478bd9Sstevel@tonic-gate 		if (END_ISADMA(offset, value)) {
5287c478bd9Sstevel@tonic-gate 			isadmap->isadma_ldip = NULL;	/* reset lock owner */
5297c478bd9Sstevel@tonic-gate #ifdef DEBUG
5307c478bd9Sstevel@tonic-gate 			isadma_clearing_wdip++;
5317c478bd9Sstevel@tonic-gate #endif
5327c478bd9Sstevel@tonic-gate 		}
5337c478bd9Sstevel@tonic-gate 	} else	{	/* we don't own the lock */
5347c478bd9Sstevel@tonic-gate 		/* wait until on-going dma completes */
5357c478bd9Sstevel@tonic-gate 		isadma_dmawait(isadmap);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 		if (BEGIN_ISADMA(offset, value)) {
5387c478bd9Sstevel@tonic-gate 			isadmap->isadma_ldip = hdlp->ahi_common.ah_dip;
5397c478bd9Sstevel@tonic-gate #ifdef DEBUG
5407c478bd9Sstevel@tonic-gate 			isadma_setting_wdip++;
5417c478bd9Sstevel@tonic-gate #endif
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* No 8 bit access to 16 bit address or count registers */
5467c478bd9Sstevel@tonic-gate 	if (IN_16BIT_SPACE(offset))
5477c478bd9Sstevel@tonic-gate 		goto exit;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	/* No 8 bit access to first/last flip-flop registers */
5507c478bd9Sstevel@tonic-gate 	if (IS_SEQREG(offset))
5517c478bd9Sstevel@tonic-gate 		goto exit;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	ddi_put8(phdl, addr, value);	/* Pass to parent */
5547c478bd9Sstevel@tonic-gate exit:
5557c478bd9Sstevel@tonic-gate 	isadma_wakeup(isadmap);
5567c478bd9Sstevel@tonic-gate 	mutex_exit(&isadmap->isadma_access_lock);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * Allow child devices to access this shared register set as if it were
5617c478bd9Sstevel@tonic-gate  * a real 16 bit register.  The ISA bridge defines the access to this
5627c478bd9Sstevel@tonic-gate  * 16 bit dma controller & count register by programming an 8 byte register.
5637c478bd9Sstevel@tonic-gate  */
5647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5657c478bd9Sstevel@tonic-gate void
5667c478bd9Sstevel@tonic-gate isadma_put16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
5697c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
5707c478bd9Sstevel@tonic-gate 	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
5737c478bd9Sstevel@tonic-gate #ifdef DEBUG
5747c478bd9Sstevel@tonic-gate 		isadma_punt++;
5757c478bd9Sstevel@tonic-gate #endif
5767c478bd9Sstevel@tonic-gate 		ddi_put16(phdl, addr, value);
5777c478bd9Sstevel@tonic-gate 		return;
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate #ifdef DEBUG
5807c478bd9Sstevel@tonic-gate 	isadma_check_waiters(isadmap);
5817c478bd9Sstevel@tonic-gate #endif
5827c478bd9Sstevel@tonic-gate 	mutex_enter(&isadmap->isadma_access_lock);
5837c478bd9Sstevel@tonic-gate 	isadma_dmawait(isadmap);	/* wait until on-going dma completes */
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	/* Only Allow access to the 16 bit count and address registers */
5867c478bd9Sstevel@tonic-gate 	if (!IN_16BIT_SPACE(offset))
5877c478bd9Sstevel@tonic-gate 		goto exit;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* Set the sequencing register to the low byte */
5907c478bd9Sstevel@tonic-gate 	ddi_put8(phdl, (uint8_t *)HDL_TO_SEQREG_ADDR(hdlp, offset), 0);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	/* Write the low byte, then the high byte */
5937c478bd9Sstevel@tonic-gate 	ddi_put8(phdl, (uint8_t *)addr, value & 0xff);
5947c478bd9Sstevel@tonic-gate 	ddi_put8(phdl, (uint8_t *)addr, (value >> 8) & 0xff);
5957c478bd9Sstevel@tonic-gate exit:
5967c478bd9Sstevel@tonic-gate 	isadma_wakeup(isadmap);
5977c478bd9Sstevel@tonic-gate 	mutex_exit(&isadmap->isadma_access_lock);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6017c478bd9Sstevel@tonic-gate void
6027c478bd9Sstevel@tonic-gate isadma_noput32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) {}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6057c478bd9Sstevel@tonic-gate void
6067c478bd9Sstevel@tonic-gate isadma_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) {}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate #define	IS_SAME_REG(r1, r2) (((r1)->ebus_addr_hi == (r2)->ebus_addr_hi) && \
6097c478bd9Sstevel@tonic-gate 	((r1)->ebus_addr_low == (r2)->ebus_addr_low))
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate /*
6127c478bd9Sstevel@tonic-gate  * The isadma_map routine determines if it's child is attempting to map a
6137c478bd9Sstevel@tonic-gate  * shared reg.  If it is, it installs it's own vectors and bus private pointer
6147c478bd9Sstevel@tonic-gate  * and stacks those ops that were already defined.
6157c478bd9Sstevel@tonic-gate  */
6167c478bd9Sstevel@tonic-gate static int
6177c478bd9Sstevel@tonic-gate isadma_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
6187c478bd9Sstevel@tonic-gate 	off_t off, off_t len, caddr_t *addrp)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 	isadma_devstate_t *isadmap = ddi_get_soft_state(per_isadma_state,
6217c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
6227c478bd9Sstevel@tonic-gate 	dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
6237c478bd9Sstevel@tonic-gate 	ebus_regspec_t *child_regp, *regp;
6247c478bd9Sstevel@tonic-gate 	int32_t rnumber = mp->map_obj.rnumber;
6257c478bd9Sstevel@tonic-gate 	int32_t reglen;
6267c478bd9Sstevel@tonic-gate 	int ret;
6277c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * Get child regspec since the mapping struct may not have it yet
6317c478bd9Sstevel@tonic-gate 	 */
632a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
6337c478bd9Sstevel@tonic-gate 	    "reg", (caddr_t)&regp, &reglen) != DDI_SUCCESS) {
6347c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	child_regp = regp + rnumber;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	DPRINTF(ISADMA_MAP_DEBUG, ("isadma_map: child regp %p "
640*903a11ebSrh87107 	    "parent regp %p Child reg array %p\n", (void *)child_regp,
641*903a11ebSrh87107 	    (void *)isadmap->isadma_regp, (void *)regp));
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/* Figure out if we're mapping or unmapping */
6447c478bd9Sstevel@tonic-gate 	switch (mp->map_op) {
6457c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_LOCKED:
6467c478bd9Sstevel@tonic-gate 		/* Call up device tree to establish mapping */
6477c478bd9Sstevel@tonic-gate 		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
6487c478bd9Sstevel@tonic-gate 		    (pdip, rdip, mp, off, len, addrp);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if ((ret != DDI_SUCCESS) ||
6517c478bd9Sstevel@tonic-gate 		    !IS_SAME_REG(child_regp, isadmap->isadma_regp))
6527c478bd9Sstevel@tonic-gate 			break;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		/* Post-process the mapping request. */
6557c478bd9Sstevel@tonic-gate 		hp = kmem_alloc(sizeof (ddi_acc_impl_t), KM_SLEEP);
6567c478bd9Sstevel@tonic-gate 		*hp = *(ddi_acc_impl_t *)mp->map_handlep;
6577c478bd9Sstevel@tonic-gate 		impl_acc_hdl_get((ddi_acc_handle_t)mp->map_handlep)->
6587c478bd9Sstevel@tonic-gate 		    ah_platform_private = hp;
6597c478bd9Sstevel@tonic-gate 		hp = (ddi_acc_impl_t *)mp->map_handlep;
6607c478bd9Sstevel@tonic-gate 		hp->ahi_common.ah_bus_private = isadmap;
6617c478bd9Sstevel@tonic-gate 		hp->ahi_get8 = isadma_get8;
6627c478bd9Sstevel@tonic-gate 		hp->ahi_get16 = isadma_get16;
6637c478bd9Sstevel@tonic-gate 		hp->ahi_get32 = isadma_noget32;
6647c478bd9Sstevel@tonic-gate 		hp->ahi_get64 = isadma_noget64;
6657c478bd9Sstevel@tonic-gate 		hp->ahi_put8 = isadma_put8;
6667c478bd9Sstevel@tonic-gate 		hp->ahi_put16 = isadma_put16;
6677c478bd9Sstevel@tonic-gate 		hp->ahi_put32 = isadma_noput32;
6687c478bd9Sstevel@tonic-gate 		hp->ahi_put64 = isadma_noput64;
6697c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get8 = isadma_norep_get8;
6707c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get16 = isadma_norep_get16;
6717c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get32 = isadma_norep_get32;
6727c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get64 = isadma_norep_get64;
6737c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put8 = isadma_norep_put8;
6747c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put16 = isadma_norep_put16;
6757c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put32 = isadma_norep_put32;
6767c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put64 = isadma_norep_put64;
6777c478bd9Sstevel@tonic-gate 		break;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	case DDI_MO_UNMAP:
6807c478bd9Sstevel@tonic-gate 		if (IS_SAME_REG(child_regp, isadmap->isadma_regp)) {
6817c478bd9Sstevel@tonic-gate 			hp = impl_acc_hdl_get(
6827c478bd9Sstevel@tonic-gate 			    (ddi_acc_handle_t)mp->map_handlep)->
6837c478bd9Sstevel@tonic-gate 			    ah_platform_private;
6847c478bd9Sstevel@tonic-gate 			*(ddi_acc_impl_t *)mp->map_handlep = *hp;
6857c478bd9Sstevel@tonic-gate 			kmem_free(hp, sizeof (ddi_acc_impl_t));
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		/* Call up tree to tear down mapping */
6897c478bd9Sstevel@tonic-gate 		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
6907c478bd9Sstevel@tonic-gate 		    (pdip, rdip, mp, off, len, addrp);
6917c478bd9Sstevel@tonic-gate 		break;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	default:
6947c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
6957c478bd9Sstevel@tonic-gate 		break;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	kmem_free(regp, reglen);
6997c478bd9Sstevel@tonic-gate 	return (ret);
7007c478bd9Sstevel@tonic-gate }
701