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