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