xref: /onnv-gate/usr/src/uts/sun4/io/ebus.c (revision 0)
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/types.h>
30*0Sstevel@tonic-gate #include <sys/conf.h>
31*0Sstevel@tonic-gate #include <sys/ddi.h>
32*0Sstevel@tonic-gate #include <sys/sunddi.h>
33*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
35*0Sstevel@tonic-gate #include <sys/pci.h>
36*0Sstevel@tonic-gate #include <sys/autoconf.h>
37*0Sstevel@tonic-gate #include <sys/cmn_err.h>
38*0Sstevel@tonic-gate #include <sys/errno.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/debug.h>
41*0Sstevel@tonic-gate #include <sys/sysmacros.h>
42*0Sstevel@tonic-gate #include <sys/ebus.h>
43*0Sstevel@tonic-gate #include <sys/open.h>
44*0Sstevel@tonic-gate #include <sys/stat.h>
45*0Sstevel@tonic-gate #include <sys/file.h>
46*0Sstevel@tonic-gate #include <sys/sunndi.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #ifdef DEBUG
49*0Sstevel@tonic-gate uint64_t ebus_debug_flags = 0;
50*0Sstevel@tonic-gate #endif
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * The values of the following variables are used to initialize
54*0Sstevel@tonic-gate  * the cache line size and latency timer registers in the ebus
55*0Sstevel@tonic-gate  * configuration header.  Variables are used instead of constants
56*0Sstevel@tonic-gate  * to allow tuning from the /etc/system file.
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10;	/* 64 bytes */
59*0Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40;	/* 64 PCI cycles */
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * function prototypes for bus ops routines:
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate static int
65*0Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
66*0Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
67*0Sstevel@tonic-gate static int
68*0Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
69*0Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
70*0Sstevel@tonic-gate static int
71*0Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
72*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result);
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * function prototypes for dev ops routines:
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
78*0Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
79*0Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
80*0Sstevel@tonic-gate 	void *arg, void **result);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  * general function prototypes:
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p);
86*0Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
87*0Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp);
88*0Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
89*0Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, struct regspec *rp);
90*0Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
93*0Sstevel@tonic-gate 		ddi_getlongprop(DDI_DEV_T_NONE, (dip), DDI_PROP_DONTPASS, \
94*0Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp);
97*0Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp);
98*0Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
99*0Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
100*0Sstevel@tonic-gate struct cb_ops ebus_cb_ops = {
101*0Sstevel@tonic-gate 	ebus_open,			/* open */
102*0Sstevel@tonic-gate 	ebus_close,			/* close */
103*0Sstevel@tonic-gate 	nodev,				/* strategy */
104*0Sstevel@tonic-gate 	nodev,				/* print */
105*0Sstevel@tonic-gate 	nodev,				/* dump */
106*0Sstevel@tonic-gate 	nodev,				/* read */
107*0Sstevel@tonic-gate 	nodev,				/* write */
108*0Sstevel@tonic-gate 	ebus_ioctl,			/* ioctl */
109*0Sstevel@tonic-gate 	nodev,				/* devmap */
110*0Sstevel@tonic-gate 	nodev,				/* mmap */
111*0Sstevel@tonic-gate 	nodev,				/* segmap */
112*0Sstevel@tonic-gate 	nochpoll,			/* poll */
113*0Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
114*0Sstevel@tonic-gate 	NULL,				/* streamtab */
115*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
116*0Sstevel@tonic-gate 	CB_REV,				/* rev */
117*0Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
118*0Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
119*0Sstevel@tonic-gate };
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*
122*0Sstevel@tonic-gate  * bus ops and dev ops structures:
123*0Sstevel@tonic-gate  */
124*0Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = {
125*0Sstevel@tonic-gate 	BUSO_REV,
126*0Sstevel@tonic-gate 	ebus_map,
127*0Sstevel@tonic-gate 	NULL,
128*0Sstevel@tonic-gate 	NULL,
129*0Sstevel@tonic-gate 	NULL,
130*0Sstevel@tonic-gate 	i_ddi_map_fault,
131*0Sstevel@tonic-gate 	ddi_dma_map,
132*0Sstevel@tonic-gate 	ddi_dma_allochdl,
133*0Sstevel@tonic-gate 	ddi_dma_freehdl,
134*0Sstevel@tonic-gate 	ddi_dma_bindhdl,
135*0Sstevel@tonic-gate 	ddi_dma_unbindhdl,
136*0Sstevel@tonic-gate 	ddi_dma_flush,
137*0Sstevel@tonic-gate 	ddi_dma_win,
138*0Sstevel@tonic-gate 	ddi_dma_mctl,
139*0Sstevel@tonic-gate 	ebus_ctlops,
140*0Sstevel@tonic-gate 	ddi_bus_prop_op,
141*0Sstevel@tonic-gate 	ndi_busop_get_eventcookie,
142*0Sstevel@tonic-gate 	ndi_busop_add_eventcall,
143*0Sstevel@tonic-gate 	ndi_busop_remove_eventcall,
144*0Sstevel@tonic-gate 	ndi_post_event,
145*0Sstevel@tonic-gate 	0,
146*0Sstevel@tonic-gate 	0,
147*0Sstevel@tonic-gate 	0,
148*0Sstevel@tonic-gate 	0,
149*0Sstevel@tonic-gate 	0,
150*0Sstevel@tonic-gate 	0,
151*0Sstevel@tonic-gate 	0,
152*0Sstevel@tonic-gate 	0,
153*0Sstevel@tonic-gate 	ebus_intr_ops
154*0Sstevel@tonic-gate };
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate static struct dev_ops ebus_ops = {
157*0Sstevel@tonic-gate 	DEVO_REV,
158*0Sstevel@tonic-gate 	0,
159*0Sstevel@tonic-gate 	ebus_info,
160*0Sstevel@tonic-gate 	nulldev,
161*0Sstevel@tonic-gate 	nulldev,
162*0Sstevel@tonic-gate 	ebus_attach,
163*0Sstevel@tonic-gate 	ebus_detach,
164*0Sstevel@tonic-gate 	nodev,
165*0Sstevel@tonic-gate 	&ebus_cb_ops,
166*0Sstevel@tonic-gate 	&ebus_bus_ops
167*0Sstevel@tonic-gate };
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate /*
170*0Sstevel@tonic-gate  * module definitions:
171*0Sstevel@tonic-gate  */
172*0Sstevel@tonic-gate #include <sys/modctl.h>
173*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate static struct modldrv modldrv = {
176*0Sstevel@tonic-gate 	&mod_driverops, 	/* Type of module.  This one is a driver */
177*0Sstevel@tonic-gate 	"ebus nexus driver %I%", /* Name of module. */
178*0Sstevel@tonic-gate 	&ebus_ops,		/* driver ops */
179*0Sstevel@tonic-gate };
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
182*0Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
183*0Sstevel@tonic-gate };
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate /*
186*0Sstevel@tonic-gate  * driver global data:
187*0Sstevel@tonic-gate  */
188*0Sstevel@tonic-gate static void *per_ebus_state;		/* per-ebus soft state pointer */
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate int
192*0Sstevel@tonic-gate _init(void)
193*0Sstevel@tonic-gate {
194*0Sstevel@tonic-gate 	int e;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	/*
197*0Sstevel@tonic-gate 	 * Initialize per-ebus soft state pointer.
198*0Sstevel@tonic-gate 	 */
199*0Sstevel@tonic-gate 	e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1);
200*0Sstevel@tonic-gate 	if (e != 0)
201*0Sstevel@tonic-gate 		return (e);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/*
204*0Sstevel@tonic-gate 	 * Install the module.
205*0Sstevel@tonic-gate 	 */
206*0Sstevel@tonic-gate 	e = mod_install(&modlinkage);
207*0Sstevel@tonic-gate 	if (e != 0)
208*0Sstevel@tonic-gate 		ddi_soft_state_fini(&per_ebus_state);
209*0Sstevel@tonic-gate 	return (e);
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate int
213*0Sstevel@tonic-gate _fini(void)
214*0Sstevel@tonic-gate {
215*0Sstevel@tonic-gate 	int e;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/*
218*0Sstevel@tonic-gate 	 * Remove the module.
219*0Sstevel@tonic-gate 	 */
220*0Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
221*0Sstevel@tonic-gate 	if (e != 0)
222*0Sstevel@tonic-gate 		return (e);
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/*
225*0Sstevel@tonic-gate 	 * Free the soft state info.
226*0Sstevel@tonic-gate 	 */
227*0Sstevel@tonic-gate 	ddi_soft_state_fini(&per_ebus_state);
228*0Sstevel@tonic-gate 	return (e);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate int
232*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate /* device driver entry points */
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate /*ARGSUSED*/
240*0Sstevel@tonic-gate static int
241*0Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
242*0Sstevel@tonic-gate {
243*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
244*0Sstevel@tonic-gate 	int instance;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	instance = getminor((dev_t)arg);
247*0Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(instance);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	switch (infocmd) {
250*0Sstevel@tonic-gate 	default:
251*0Sstevel@tonic-gate 		return (DDI_FAILURE);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
254*0Sstevel@tonic-gate 		*result = (void *)instance;
255*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
258*0Sstevel@tonic-gate 		if (ebus_p == NULL)
259*0Sstevel@tonic-gate 			return (DDI_FAILURE);
260*0Sstevel@tonic-gate 		*result = (void *)ebus_p->dip;
261*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate /*
266*0Sstevel@tonic-gate  * attach entry point:
267*0Sstevel@tonic-gate  *
268*0Sstevel@tonic-gate  * normal attach:
269*0Sstevel@tonic-gate  *
270*0Sstevel@tonic-gate  *	create soft state structure (dip, reg, nreg and state fields)
271*0Sstevel@tonic-gate  *	map in configuration header
272*0Sstevel@tonic-gate  *	make sure device is properly configured
273*0Sstevel@tonic-gate  *	report device
274*0Sstevel@tonic-gate  */
275*0Sstevel@tonic-gate static int
276*0Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
277*0Sstevel@tonic-gate {
278*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
279*0Sstevel@tonic-gate 	int instance;
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	DBG1(D_ATTACH, NULL, "dip=%p\n", dip);
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	switch (cmd) {
284*0Sstevel@tonic-gate 	case DDI_ATTACH:
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 		/*
287*0Sstevel@tonic-gate 		 * Allocate soft state for this instance.
288*0Sstevel@tonic-gate 		 */
289*0Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
290*0Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(per_ebus_state, instance)
291*0Sstevel@tonic-gate 				!= DDI_SUCCESS) {
292*0Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to alloc soft state\n");
293*0Sstevel@tonic-gate 			return (DDI_FAILURE);
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
296*0Sstevel@tonic-gate 		ebus_p->dip = dip;
297*0Sstevel@tonic-gate 		mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL);
298*0Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 		/* Set ebus type field based on ddi name info */
301*0Sstevel@tonic-gate 		if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) {
302*0Sstevel@tonic-gate 			ebus_p->type = FEBUS_TYPE;
303*0Sstevel@tonic-gate 		} else {
304*0Sstevel@tonic-gate 			ebus_p->type = EBUS_TYPE;
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
308*0Sstevel@tonic-gate 			DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0);
309*0Sstevel@tonic-gate 		/* Get our ranges property for mapping child registers. */
310*0Sstevel@tonic-gate 		if (get_ranges_prop(ebus_p) != DDI_SUCCESS) {
311*0Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
312*0Sstevel@tonic-gate 			free_ebus_soft_state(instance);
313*0Sstevel@tonic-gate 			return (DDI_FAILURE);
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		/*
317*0Sstevel@tonic-gate 		 * create minor node for devctl interfaces
318*0Sstevel@tonic-gate 		 */
319*0Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
320*0Sstevel@tonic-gate 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
321*0Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
322*0Sstevel@tonic-gate 			free_ebus_soft_state(instance);
323*0Sstevel@tonic-gate 			return (DDI_FAILURE);
324*0Sstevel@tonic-gate 		}
325*0Sstevel@tonic-gate 		/*
326*0Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
327*0Sstevel@tonic-gate 		 * bits are set in the config command register.
328*0Sstevel@tonic-gate 		 */
329*0Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
330*0Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
331*0Sstevel@tonic-gate 				ddi_remove_minor_node(dip, "devctl");
332*0Sstevel@tonic-gate 				mutex_destroy(&ebus_p->ebus_mutex);
333*0Sstevel@tonic-gate 				free_ebus_soft_state(instance);
334*0Sstevel@tonic-gate 				return (DDI_FAILURE);
335*0Sstevel@tonic-gate 			}
336*0Sstevel@tonic-gate 		}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 		/*
339*0Sstevel@tonic-gate 		 * Make the pci_report_pmcap() call only for RIO
340*0Sstevel@tonic-gate 		 * implementations.
341*0Sstevel@tonic-gate 		 */
342*0Sstevel@tonic-gate 		if (IS_RIO(dip)) {
343*0Sstevel@tonic-gate 			(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED,
344*0Sstevel@tonic-gate 			    (void *)EBUS_4MHZ);
345*0Sstevel@tonic-gate 		}
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 		/*
348*0Sstevel@tonic-gate 		 * Make the state as attached and report the device.
349*0Sstevel@tonic-gate 		 */
350*0Sstevel@tonic-gate 		ebus_p->state = ATTACHED;
351*0Sstevel@tonic-gate 		ddi_report_dev(dip);
352*0Sstevel@tonic-gate 		DBG(D_ATTACH, ebus_p, "returning\n");
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	case DDI_RESUME:
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
359*0Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 		/*
362*0Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
363*0Sstevel@tonic-gate 		 * bits are set in the config command register.
364*0Sstevel@tonic-gate 		 */
365*0Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
366*0Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
367*0Sstevel@tonic-gate 				free_ebus_soft_state(instance);
368*0Sstevel@tonic-gate 				return (DDI_FAILURE);
369*0Sstevel@tonic-gate 			}
370*0Sstevel@tonic-gate 		}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 		ebus_p->state = RESUMED;
373*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
374*0Sstevel@tonic-gate 	}
375*0Sstevel@tonic-gate 	return (DDI_FAILURE);
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /*
379*0Sstevel@tonic-gate  * detach entry point:
380*0Sstevel@tonic-gate  */
381*0Sstevel@tonic-gate static int
382*0Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
385*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(instance);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	switch (cmd) {
388*0Sstevel@tonic-gate 	case DDI_DETACH:
389*0Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 		switch (ebus_p->type) {
392*0Sstevel@tonic-gate 		case EBUS_TYPE:
393*0Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt *
394*0Sstevel@tonic-gate 				sizeof (struct ebus_pci_rangespec));
395*0Sstevel@tonic-gate 			break;
396*0Sstevel@tonic-gate 		case FEBUS_TYPE:
397*0Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.ferangep,
398*0Sstevel@tonic-gate 				ebus_p->range_cnt *
399*0Sstevel@tonic-gate 				sizeof (struct febus_rangespec));
400*0Sstevel@tonic-gate 			break;
401*0Sstevel@tonic-gate 		default:
402*0Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to recognize ebus type\n");
403*0Sstevel@tonic-gate 			return (DDI_FAILURE);
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, "devctl");
407*0Sstevel@tonic-gate 		mutex_destroy(&ebus_p->ebus_mutex);
408*0Sstevel@tonic-gate 		free_ebus_soft_state(instance);
409*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	case DDI_SUSPEND:
412*0Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip);
413*0Sstevel@tonic-gate 		ebus_p->state = SUSPENDED;
414*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 	DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n");
417*0Sstevel@tonic-gate 	return (DDI_FAILURE);
418*0Sstevel@tonic-gate }
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate int
422*0Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p)
423*0Sstevel@tonic-gate {
424*0Sstevel@tonic-gate 	int nrange, range_len;
425*0Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep;
426*0Sstevel@tonic-gate 	struct febus_rangespec *ferangep;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	switch (ebus_p->type) {
429*0Sstevel@tonic-gate 	case EBUS_TYPE:
430*0Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
431*0Sstevel@tonic-gate 			ebus_p->dip, DDI_PROP_DONTPASS,
432*0Sstevel@tonic-gate 			"ranges", (caddr_t)&rangep,
433*0Sstevel@tonic-gate 			&range_len) != DDI_SUCCESS) {
434*0Sstevel@tonic-gate 				cmn_err(CE_WARN, "Can't get %s ranges property",
435*0Sstevel@tonic-gate 					ddi_get_name(ebus_p->dip));
436*0Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
437*0Sstevel@tonic-gate 		}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 		nrange = range_len / sizeof (struct ebus_pci_rangespec);
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 		if (nrange == 0)  {
442*0Sstevel@tonic-gate 			kmem_free(rangep, range_len);
443*0Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "range is equal to zero\n");
444*0Sstevel@tonic-gate 			return (DDI_FAILURE);
445*0Sstevel@tonic-gate 		}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate #ifdef DEBUG
448*0Sstevel@tonic-gate 		{
449*0Sstevel@tonic-gate 			int i;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
452*0Sstevel@tonic-gate 				DBG5(D_MAP, ebus_p,
453*0Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x PCI range "
454*0Sstevel@tonic-gate 					"addr 0x%x.0x%x.0x%x ",
455*0Sstevel@tonic-gate 					rangep[i].ebus_phys_hi,
456*0Sstevel@tonic-gate 					rangep[i].ebus_phys_low,
457*0Sstevel@tonic-gate 					rangep[i].pci_phys_hi,
458*0Sstevel@tonic-gate 					rangep[i].pci_phys_mid,
459*0Sstevel@tonic-gate 					rangep[i].pci_phys_low);
460*0Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p,
461*0Sstevel@tonic-gate 					"Size 0x%x\n", rangep[i].rng_size);
462*0Sstevel@tonic-gate 			}
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate #endif /* DEBUG */
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 		ebus_p->rangespec.rangep = rangep;
467*0Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
468*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	case FEBUS_TYPE:
471*0Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip,
472*0Sstevel@tonic-gate 			DDI_PROP_DONTPASS, "ranges",
473*0Sstevel@tonic-gate 			(caddr_t)&ferangep, &range_len) != DDI_SUCCESS) {
474*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "Can't get %s ranges property",
475*0Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip));
476*0Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 		nrange = range_len / sizeof (struct febus_rangespec);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		if (nrange == 0)  {
482*0Sstevel@tonic-gate 			kmem_free(ferangep, range_len);
483*0Sstevel@tonic-gate 			return (DDI_FAILURE);
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate #ifdef	DEBUG
487*0Sstevel@tonic-gate 		{
488*0Sstevel@tonic-gate 			int i;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
491*0Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p,
492*0Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x"
493*0Sstevel@tonic-gate 					" Parent range "
494*0Sstevel@tonic-gate 					"addr 0x%x.0x%x ",
495*0Sstevel@tonic-gate 					ferangep[i].febus_phys_hi,
496*0Sstevel@tonic-gate 					ferangep[i].febus_phys_low,
497*0Sstevel@tonic-gate 					ferangep[i].parent_phys_hi,
498*0Sstevel@tonic-gate 					ferangep[i].parent_phys_low);
499*0Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p, "Size 0x%x\n",
500*0Sstevel@tonic-gate 					ferangep[i].rng_size);
501*0Sstevel@tonic-gate 			}
502*0Sstevel@tonic-gate 		}
503*0Sstevel@tonic-gate #endif /* DEBUG */
504*0Sstevel@tonic-gate 		ebus_p->rangespec.ferangep = ferangep;
505*0Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
506*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	default:
509*0Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
510*0Sstevel@tonic-gate 		return (DDI_FAILURE);
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate }
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate /* bus driver entry points */
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate /*
517*0Sstevel@tonic-gate  * bus map entry point:
518*0Sstevel@tonic-gate  *
519*0Sstevel@tonic-gate  * 	if map request is for an rnumber
520*0Sstevel@tonic-gate  *		get the corresponding regspec from device node
521*0Sstevel@tonic-gate  * 	build a new regspec in our parent's format
522*0Sstevel@tonic-gate  *	build a new map_req with the new regspec
523*0Sstevel@tonic-gate  *	call up the tree to complete the mapping
524*0Sstevel@tonic-gate  */
525*0Sstevel@tonic-gate static int
526*0Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
527*0Sstevel@tonic-gate 	off_t off, off_t len, caddr_t *addrp)
528*0Sstevel@tonic-gate {
529*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
530*0Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp, *ebus_regs;
531*0Sstevel@tonic-gate 	struct regspec reg;
532*0Sstevel@tonic-gate 	pci_regspec_t pci_reg;
533*0Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
534*0Sstevel@tonic-gate 	int rnumber, i, n;
535*0Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	/*
538*0Sstevel@tonic-gate 	 * Handle the mapping according to its type.
539*0Sstevel@tonic-gate 	 */
540*0Sstevel@tonic-gate 	DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n",
541*0Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len);
542*0Sstevel@tonic-gate 	switch (mp->map_type) {
543*0Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 		/*
546*0Sstevel@tonic-gate 		 * We assume the register specification is in ebus format.
547*0Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
548*0Sstevel@tonic-gate 		 * the request to our parent.
549*0Sstevel@tonic-gate 		 */
550*0Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n",
551*0Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
552*0Sstevel@tonic-gate 			mp->map_handlep);
553*0Sstevel@tonic-gate 		ebus_rp = (ebus_regspec_t *)mp->map_obj.rp;
554*0Sstevel@tonic-gate 		break;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 		/*
559*0Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
560*0Sstevel@tonic-gate 		 * it to our parent's format.
561*0Sstevel@tonic-gate 		 */
562*0Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
563*0Sstevel@tonic-gate 		DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n",
564*0Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
565*0Sstevel@tonic-gate 			rnumber, mp->map_handlep);
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) {
568*0Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "can't get reg property\n");
569*0Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
570*0Sstevel@tonic-gate 		}
571*0Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
574*0Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
575*0Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
576*0Sstevel@tonic-gate 		}
577*0Sstevel@tonic-gate 		ebus_rp = &ebus_regs[rnumber];
578*0Sstevel@tonic-gate 		break;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	default:
581*0Sstevel@tonic-gate 		return (DDI_ME_INVAL);
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/* Adjust our reg property with offset and length */
586*0Sstevel@tonic-gate 	ebus_rp->addr_low += off;
587*0Sstevel@tonic-gate 	if (len)
588*0Sstevel@tonic-gate 		ebus_rp->size = len;
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	/*
591*0Sstevel@tonic-gate 	 * Now we have a copy the "reg" entry we're attempting to map.
592*0Sstevel@tonic-gate 	 * Translate this into our parents PCI address using the ranges
593*0Sstevel@tonic-gate 	 * property.
594*0Sstevel@tonic-gate 	 */
595*0Sstevel@tonic-gate 	switch (ebus_p->type) {
596*0Sstevel@tonic-gate 	case EBUS_TYPE:
597*0Sstevel@tonic-gate 		rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg);
598*0Sstevel@tonic-gate 		break;
599*0Sstevel@tonic-gate 	case FEBUS_TYPE:
600*0Sstevel@tonic-gate 		rval = febus_apply_range(ebus_p, rdip, ebus_rp, &reg);
601*0Sstevel@tonic-gate 		break;
602*0Sstevel@tonic-gate 	default:
603*0Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
604*0Sstevel@tonic-gate 		rval = DDI_FAILURE;
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
608*0Sstevel@tonic-gate 		kmem_free(ebus_regs, i);
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
611*0Sstevel@tonic-gate 		return (rval);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate #ifdef DEBUG
614*0Sstevel@tonic-gate 	switch (ebus_p->type) {
615*0Sstevel@tonic-gate 	case EBUS_TYPE:
616*0Sstevel@tonic-gate 		DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n",
617*0Sstevel@tonic-gate 			pci_reg.pci_phys_hi,
618*0Sstevel@tonic-gate 			pci_reg.pci_phys_mid,
619*0Sstevel@tonic-gate 			pci_reg.pci_phys_low,
620*0Sstevel@tonic-gate 			pci_reg.pci_size_hi,
621*0Sstevel@tonic-gate 			pci_reg.pci_size_low);
622*0Sstevel@tonic-gate 		break;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	case FEBUS_TYPE:
625*0Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "%x,%x,%x\n",
626*0Sstevel@tonic-gate 			reg.regspec_bustype,
627*0Sstevel@tonic-gate 			reg.regspec_addr,
628*0Sstevel@tonic-gate 			reg.regspec_size);
629*0Sstevel@tonic-gate 		break;
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate #endif
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	p_map_request = *mp;
634*0Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	switch (ebus_p->type) {
637*0Sstevel@tonic-gate 	case EBUS_TYPE:
638*0Sstevel@tonic-gate 		p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
639*0Sstevel@tonic-gate 		break;
640*0Sstevel@tonic-gate 	case FEBUS_TYPE:
641*0Sstevel@tonic-gate 		p_map_request.map_obj.rp = &reg;
642*0Sstevel@tonic-gate 		break;
643*0Sstevel@tonic-gate 	default:
644*0Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
645*0Sstevel@tonic-gate 		return (DDI_FAILURE);
646*0Sstevel@tonic-gate 	}
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
649*0Sstevel@tonic-gate 	DBG1(D_MAP, ebus_p, "parent returned %x\n", rval);
650*0Sstevel@tonic-gate 	return (rval);
651*0Sstevel@tonic-gate }
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate static int
655*0Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
656*0Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp)
657*0Sstevel@tonic-gate {
658*0Sstevel@tonic-gate 	int b;
659*0Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
660*0Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep;
661*0Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
662*0Sstevel@tonic-gate 	static char out_of_range[] =
663*0Sstevel@tonic-gate 	    "Out of range register specification from device node <%s>";
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
666*0Sstevel@tonic-gate 	    ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 		/* Check for the correct space */
671*0Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->ebus_phys_hi)
672*0Sstevel@tonic-gate 			/* See if we fit in this range */
673*0Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
674*0Sstevel@tonic-gate 			    rangep->ebus_phys_low) &&
675*0Sstevel@tonic-gate 			    ((ebus_rp->addr_low + ebus_rp->size - 1)
676*0Sstevel@tonic-gate 				<= (rangep->ebus_phys_low +
677*0Sstevel@tonic-gate 				    rangep->rng_size - 1))) {
678*0Sstevel@tonic-gate 				uint_t addr_offset = ebus_rp->addr_low -
679*0Sstevel@tonic-gate 				    rangep->ebus_phys_low;
680*0Sstevel@tonic-gate 				/*
681*0Sstevel@tonic-gate 				 * Use the range entry to translate
682*0Sstevel@tonic-gate 				 * the EBUS physical address into the
683*0Sstevel@tonic-gate 				 * parents PCI space.
684*0Sstevel@tonic-gate 				 */
685*0Sstevel@tonic-gate 				rp->pci_phys_hi =
686*0Sstevel@tonic-gate 				rangep->pci_phys_hi;
687*0Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
688*0Sstevel@tonic-gate 				rp->pci_phys_low =
689*0Sstevel@tonic-gate 					rangep->pci_phys_low + addr_offset;
690*0Sstevel@tonic-gate 				rp->pci_size_hi = 0;
691*0Sstevel@tonic-gate 				rp->pci_size_low =
692*0Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
693*0Sstevel@tonic-gate 					addr_offset));
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
696*0Sstevel@tonic-gate 					rangep->ebus_phys_hi,
697*0Sstevel@tonic-gate 					rangep->ebus_phys_low);
698*0Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p, "Parent hi0x%x "
699*0Sstevel@tonic-gate 					"mid0x%x lo0x%x size 0x%x\n",
700*0Sstevel@tonic-gate 					rangep->pci_phys_hi,
701*0Sstevel@tonic-gate 					rangep->pci_phys_mid,
702*0Sstevel@tonic-gate 					rangep->pci_phys_low,
703*0Sstevel@tonic-gate 					rangep->rng_size);
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 				break;
706*0Sstevel@tonic-gate 			}
707*0Sstevel@tonic-gate 	}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	if (b == nrange)  {
710*0Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
711*0Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
712*0Sstevel@tonic-gate 	}
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	return (rval);
715*0Sstevel@tonic-gate }
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate static int
718*0Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
719*0Sstevel@tonic-gate 		ebus_regspec_t *ebus_rp, struct regspec *rp) {
720*0Sstevel@tonic-gate 	int b;
721*0Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
722*0Sstevel@tonic-gate 	struct febus_rangespec *rangep = ebus_p->rangespec.ferangep;
723*0Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
724*0Sstevel@tonic-gate 	static char out_of_range[] =
725*0Sstevel@tonic-gate 		"Out of range register specification from device node <%s>";
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
728*0Sstevel@tonic-gate 	ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
731*0Sstevel@tonic-gate 		/* Check for the correct space */
732*0Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->febus_phys_hi)
733*0Sstevel@tonic-gate 			/* See if we fit in this range */
734*0Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
735*0Sstevel@tonic-gate 				rangep->febus_phys_low) &&
736*0Sstevel@tonic-gate 				((ebus_rp->addr_low + ebus_rp->size - 1)
737*0Sstevel@tonic-gate 				<= (rangep->febus_phys_low +
738*0Sstevel@tonic-gate 				rangep->rng_size - 1))) {
739*0Sstevel@tonic-gate 					uint_t addr_offset = ebus_rp->addr_low -
740*0Sstevel@tonic-gate 					rangep->febus_phys_low;
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 				/*
743*0Sstevel@tonic-gate 				 * Use the range entry to translate
744*0Sstevel@tonic-gate 				 * the FEBUS physical address into the
745*0Sstevel@tonic-gate 				 * parents space.
746*0Sstevel@tonic-gate 				 */
747*0Sstevel@tonic-gate 				rp->regspec_bustype =
748*0Sstevel@tonic-gate 					rangep->parent_phys_hi;
749*0Sstevel@tonic-gate 				rp->regspec_addr =
750*0Sstevel@tonic-gate 				rangep->parent_phys_low + addr_offset;
751*0Sstevel@tonic-gate 				rp->regspec_size =
752*0Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
753*0Sstevel@tonic-gate 					addr_offset));
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
756*0Sstevel@tonic-gate 					rangep->febus_phys_hi,
757*0Sstevel@tonic-gate 					rangep->febus_phys_low);
758*0Sstevel@tonic-gate 				DBG3(D_MAP, ebus_p, "Parent hi0x%x "
759*0Sstevel@tonic-gate 					"lo0x%x size 0x%x\n",
760*0Sstevel@tonic-gate 					rangep->parent_phys_hi,
761*0Sstevel@tonic-gate 					rangep->parent_phys_low,
762*0Sstevel@tonic-gate 					rangep->rng_size);
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 				break;
765*0Sstevel@tonic-gate 			}
766*0Sstevel@tonic-gate 	}
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	if (b == nrange)  {
769*0Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
770*0Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	return (rval);
774*0Sstevel@tonic-gate }
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate static int
778*0Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen)
779*0Sstevel@tonic-gate {
780*0Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
781*0Sstevel@tonic-gate 	int reglen;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	/*
784*0Sstevel@tonic-gate 	 * Get the address portion of the node name based on the
785*0Sstevel@tonic-gate 	 * address/offset.
786*0Sstevel@tonic-gate 	 */
787*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
788*0Sstevel@tonic-gate 	    "reg", (caddr_t)&ebus_rp, &reglen) != DDI_SUCCESS) {
789*0Sstevel@tonic-gate 		return (DDI_FAILURE);
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi,
793*0Sstevel@tonic-gate 	    ebus_rp->addr_low);
794*0Sstevel@tonic-gate 	kmem_free(ebus_rp, reglen);
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
797*0Sstevel@tonic-gate }
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate /*
800*0Sstevel@tonic-gate  * control ops entry point:
801*0Sstevel@tonic-gate  *
802*0Sstevel@tonic-gate  * Requests handled completely:
803*0Sstevel@tonic-gate  *	DDI_CTLOPS_INITCHILD
804*0Sstevel@tonic-gate  *	DDI_CTLOPS_UNINITCHILD
805*0Sstevel@tonic-gate  *	DDI_CTLOPS_REPORTDEV
806*0Sstevel@tonic-gate  *	DDI_CTLOPS_REGSIZE
807*0Sstevel@tonic-gate  *	DDI_CTLOPS_NREGS
808*0Sstevel@tonic-gate  *
809*0Sstevel@tonic-gate  * All others passed to parent.
810*0Sstevel@tonic-gate  */
811*0Sstevel@tonic-gate static int
812*0Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
813*0Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result)
814*0Sstevel@tonic-gate {
815*0Sstevel@tonic-gate #ifdef DEBUG
816*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
817*0Sstevel@tonic-gate #endif
818*0Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
819*0Sstevel@tonic-gate 	int i, n;
820*0Sstevel@tonic-gate 	char name[10];
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	switch (op) {
823*0Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
824*0Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
825*0Sstevel@tonic-gate 		/*
826*0Sstevel@tonic-gate 		 * Set the address portion of the node name based on the
827*0Sstevel@tonic-gate 		 * address/offset.
828*0Sstevel@tonic-gate 		 */
829*0Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
830*0Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_instance(child));
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 		if (ebus_name_child(child, name, 10) != DDI_SUCCESS) {
833*0Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't name child\n");
834*0Sstevel@tonic-gate 			return (DDI_FAILURE);
835*0Sstevel@tonic-gate 		}
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 		ddi_set_name_addr(child, name);
838*0Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
839*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
843*0Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
844*0Sstevel@tonic-gate 			ddi_get_name((dev_info_t *)arg),
845*0Sstevel@tonic-gate 			ddi_get_instance((dev_info_t *)arg));
846*0Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
847*0Sstevel@tonic-gate 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
848*0Sstevel@tonic-gate 		impl_rem_dev_props((dev_info_t *)arg);
849*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
854*0Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
855*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
856*0Sstevel@tonic-gate 			ddi_driver_name(rdip), ddi_get_instance(rdip),
857*0Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip),
858*0Sstevel@tonic-gate 			ddi_get_name_addr(rdip));
859*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
864*0Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
865*0Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
866*0Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
867*0Sstevel@tonic-gate 			return (DDI_FAILURE);
868*0Sstevel@tonic-gate 		}
869*0Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
870*0Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
871*0Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
872*0Sstevel@tonic-gate 			kmem_free(ebus_rp, i);
873*0Sstevel@tonic-gate 			return (DDI_FAILURE);
874*0Sstevel@tonic-gate 		}
875*0Sstevel@tonic-gate 		*((off_t *)result) = ebus_rp[*(int *)arg].size;
876*0Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
877*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
882*0Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
883*0Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
884*0Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
885*0Sstevel@tonic-gate 			return (DDI_FAILURE);
886*0Sstevel@tonic-gate 		}
887*0Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (ebus_regspec_t);
888*0Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
889*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
890*0Sstevel@tonic-gate 	}
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	/*
893*0Sstevel@tonic-gate 	 * Now pass the request up to our parent.
894*0Sstevel@tonic-gate 	 */
895*0Sstevel@tonic-gate 	DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n",
896*0Sstevel@tonic-gate 		ddi_get_name(rdip), ddi_get_instance(rdip));
897*0Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
898*0Sstevel@tonic-gate }
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate struct ebus_string_to_pil {
901*0Sstevel@tonic-gate 	int8_t *string;
902*0Sstevel@tonic-gate 	uint32_t pil;
903*0Sstevel@tonic-gate };
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9},
906*0Sstevel@tonic-gate 							{"audio", 9},
907*0Sstevel@tonic-gate 							{"fdthree", 8},
908*0Sstevel@tonic-gate 							{"floppy", 8},
909*0Sstevel@tonic-gate 							{"ecpp", 3},
910*0Sstevel@tonic-gate 							{"parallel", 3},
911*0Sstevel@tonic-gate 							{"su", 12},
912*0Sstevel@tonic-gate 							{"se", 12},
913*0Sstevel@tonic-gate 							{"serial", 12},
914*0Sstevel@tonic-gate 							{"power", 14}};
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12},
917*0Sstevel@tonic-gate 								{"block", 8}};
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate static int
920*0Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
921*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
922*0Sstevel@tonic-gate {
923*0Sstevel@tonic-gate #ifdef DEBUG
924*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
925*0Sstevel@tonic-gate #endif
926*0Sstevel@tonic-gate 	ddi_ispec_t		*ip = (ddi_ispec_t *)hdlp->ih_private;
927*0Sstevel@tonic-gate 	int32_t			i, max_children, max_device_types, len;
928*0Sstevel@tonic-gate 	char			*name_p, *device_type_p;
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip);
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	/*
933*0Sstevel@tonic-gate 	 * NOTE: These ops below will never be supported in this nexus
934*0Sstevel@tonic-gate 	 * driver, hence they always return immediately.
935*0Sstevel@tonic-gate 	 */
936*0Sstevel@tonic-gate 	switch (intr_op) {
937*0Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
938*0Sstevel@tonic-gate 		*(int *)result = 0;
939*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
940*0Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
941*0Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
942*0Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
943*0Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
944*0Sstevel@tonic-gate 		return (DDI_ENOTSUP);
945*0Sstevel@tonic-gate 	default:
946*0Sstevel@tonic-gate 		break;
947*0Sstevel@tonic-gate 	}
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil)
950*0Sstevel@tonic-gate 		goto done;
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	/*
953*0Sstevel@tonic-gate 	 * This is a hack to set the PIL for the devices under ebus.
954*0Sstevel@tonic-gate 	 * We first look up a device by it's specific name, if we can't
955*0Sstevel@tonic-gate 	 * match the name, we try and match it's device_type property.
956*0Sstevel@tonic-gate 	 * Lastly we default a PIL level of 1.
957*0Sstevel@tonic-gate 	 */
958*0Sstevel@tonic-gate 	name_p = ddi_node_name(rdip);
959*0Sstevel@tonic-gate 	max_children = sizeof (ebus_name_to_pil) /
960*0Sstevel@tonic-gate 	    sizeof (struct ebus_string_to_pil);
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	for (i = 0; i < max_children; i++) {
963*0Sstevel@tonic-gate 		if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) {
964*0Sstevel@tonic-gate 			DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n",
965*0Sstevel@tonic-gate 			    ebus_name_to_pil[i].string,
966*0Sstevel@tonic-gate 			    ebus_name_to_pil[i].pil);
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 			ip->is_pil = ebus_name_to_pil[i].pil;
969*0Sstevel@tonic-gate 			goto done;
970*0Sstevel@tonic-gate 		}
971*0Sstevel@tonic-gate 	}
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS,
974*0Sstevel@tonic-gate 	    "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) {
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 		max_device_types = sizeof (ebus_device_type_to_pil) /
977*0Sstevel@tonic-gate 		    sizeof (struct ebus_string_to_pil);
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 		for (i = 0; i < max_device_types; i++) {
980*0Sstevel@tonic-gate 			if (strcmp(ebus_device_type_to_pil[i].string,
981*0Sstevel@tonic-gate 			    device_type_p) == 0) {
982*0Sstevel@tonic-gate 				DBG2(D_INTR, ebus_p, "Device type %s; match "
983*0Sstevel@tonic-gate 				    "PIL %d\n", ebus_device_type_to_pil[i].
984*0Sstevel@tonic-gate 				    string, ebus_device_type_to_pil[i].pil);
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 				ip->is_pil = ebus_device_type_to_pil[i].pil;
987*0Sstevel@tonic-gate 				break;
988*0Sstevel@tonic-gate 			}
989*0Sstevel@tonic-gate 		}
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 		kmem_free(device_type_p, len);
992*0Sstevel@tonic-gate 	}
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	/*
995*0Sstevel@tonic-gate 	 * If we get here, we need to set a default value
996*0Sstevel@tonic-gate 	 * for the PIL.
997*0Sstevel@tonic-gate 	 */
998*0Sstevel@tonic-gate 	if (ip->is_pil == 0) {
999*0Sstevel@tonic-gate 		ip->is_pil = 1;
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d assigning default interrupt level %d "
1002*0Sstevel@tonic-gate 		    "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip),
1003*0Sstevel@tonic-gate 		    ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip));
1004*0Sstevel@tonic-gate 	}
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate done:
1007*0Sstevel@tonic-gate 	/* Pass up the request to our parent. */
1008*0Sstevel@tonic-gate 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
1009*0Sstevel@tonic-gate }
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate static int
1013*0Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p)
1014*0Sstevel@tonic-gate {
1015*0Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
1016*0Sstevel@tonic-gate 	uint16_t comm;
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	/*
1019*0Sstevel@tonic-gate 	 * Make sure the master enable and memory access enable
1020*0Sstevel@tonic-gate 	 * bits are set in the config command register.
1021*0Sstevel@tonic-gate 	 */
1022*0Sstevel@tonic-gate 	if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS)
1023*0Sstevel@tonic-gate 		return (0);
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM),
1026*0Sstevel@tonic-gate #ifdef DEBUG
1027*0Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm);
1028*0Sstevel@tonic-gate #endif
1029*0Sstevel@tonic-gate 	comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE|
1030*0Sstevel@tonic-gate 	    PCI_COMM_PARITY_DETECT);
1031*0Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm),
1032*0Sstevel@tonic-gate #ifdef DEBUG
1033*0Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm);
1034*0Sstevel@tonic-gate #endif
1035*0Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ,
1036*0Sstevel@tonic-gate 	    (uchar_t)ebus_cache_line_size);
1037*0Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER,
1038*0Sstevel@tonic-gate 	    (uchar_t)ebus_latency_timer);
1039*0Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
1040*0Sstevel@tonic-gate 	return (1);
1041*0Sstevel@tonic-gate }
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate #ifdef DEBUG
1044*0Sstevel@tonic-gate extern void prom_printf(const char *, ...);
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate static void
1047*0Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt,
1048*0Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1049*0Sstevel@tonic-gate {
1050*0Sstevel@tonic-gate 	char *s;
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	if (ebus_debug_flags & flag) {
1053*0Sstevel@tonic-gate 		switch (flag) {
1054*0Sstevel@tonic-gate 		case D_ATTACH:
1055*0Sstevel@tonic-gate 			s = "attach"; break;
1056*0Sstevel@tonic-gate 		case D_DETACH:
1057*0Sstevel@tonic-gate 			s = "detach"; break;
1058*0Sstevel@tonic-gate 		case D_MAP:
1059*0Sstevel@tonic-gate 			s = "map"; break;
1060*0Sstevel@tonic-gate 		case D_CTLOPS:
1061*0Sstevel@tonic-gate 			s = "ctlops"; break;
1062*0Sstevel@tonic-gate 		case D_INTR:
1063*0Sstevel@tonic-gate 			s = "intr"; break;
1064*0Sstevel@tonic-gate 		}
1065*0Sstevel@tonic-gate 		if (ebus_p)
1066*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: %s: ",
1067*0Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip),
1068*0Sstevel@tonic-gate 				ddi_get_instance(ebus_p->dip), s);
1069*0Sstevel@tonic-gate 		else
1070*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "ebus: ");
1071*0Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
1072*0Sstevel@tonic-gate 	}
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate #endif
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate /* ARGSUSED3 */
1077*0Sstevel@tonic-gate static int
1078*0Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1079*0Sstevel@tonic-gate {
1080*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	/*
1083*0Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
1084*0Sstevel@tonic-gate 	 */
1085*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1086*0Sstevel@tonic-gate 		return (EINVAL);
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate 	/*
1089*0Sstevel@tonic-gate 	 * Get the soft state structure for the device.
1090*0Sstevel@tonic-gate 	 */
1091*0Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(*devp));
1092*0Sstevel@tonic-gate 	if (ebus_p == NULL)
1093*0Sstevel@tonic-gate 		return (ENXIO);
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 	/*
1096*0Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
1097*0Sstevel@tonic-gate 	 */
1098*0Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
1099*0Sstevel@tonic-gate 	if (flags & FEXCL) {
1100*0Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) {
1101*0Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
1102*0Sstevel@tonic-gate 			return (EBUSY);
1103*0Sstevel@tonic-gate 		}
1104*0Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL;
1105*0Sstevel@tonic-gate 	} else {
1106*0Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) {
1107*0Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
1108*0Sstevel@tonic-gate 			return (EBUSY);
1109*0Sstevel@tonic-gate 		}
1110*0Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN;
1111*0Sstevel@tonic-gate 	}
1112*0Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
1113*0Sstevel@tonic-gate 	return (0);
1114*0Sstevel@tonic-gate }
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 
1117*0Sstevel@tonic-gate /* ARGSUSED */
1118*0Sstevel@tonic-gate static int
1119*0Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp)
1120*0Sstevel@tonic-gate {
1121*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1124*0Sstevel@tonic-gate 		return (EINVAL);
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
1127*0Sstevel@tonic-gate 	if (ebus_p == NULL)
1128*0Sstevel@tonic-gate 		return (ENXIO);
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
1131*0Sstevel@tonic-gate 	ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
1132*0Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
1133*0Sstevel@tonic-gate 	return (0);
1134*0Sstevel@tonic-gate }
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate /*
1138*0Sstevel@tonic-gate  * ebus_ioctl: devctl hotplug controls
1139*0Sstevel@tonic-gate  */
1140*0Sstevel@tonic-gate /* ARGSUSED */
1141*0Sstevel@tonic-gate static int
1142*0Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1143*0Sstevel@tonic-gate 	int *rvalp)
1144*0Sstevel@tonic-gate {
1145*0Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1146*0Sstevel@tonic-gate 	dev_info_t *self;
1147*0Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
1148*0Sstevel@tonic-gate 	uint_t bus_state;
1149*0Sstevel@tonic-gate 	int rv = 0;
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
1152*0Sstevel@tonic-gate 	if (ebus_p == NULL)
1153*0Sstevel@tonic-gate 		return (ENXIO);
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 	self = ebus_p->dip;
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 	/*
1158*0Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
1159*0Sstevel@tonic-gate 	 */
1160*0Sstevel@tonic-gate 	switch (cmd) {
1161*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
1162*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
1163*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
1164*0Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
1165*0Sstevel@tonic-gate 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
1166*0Sstevel@tonic-gate 	}
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	/*
1169*0Sstevel@tonic-gate 	 * read devctl ioctl data
1170*0Sstevel@tonic-gate 	 */
1171*0Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1172*0Sstevel@tonic-gate 		return (EFAULT);
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	switch (cmd) {
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
1177*0Sstevel@tonic-gate 		rv = ENOTSUP;
1178*0Sstevel@tonic-gate 		break;
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
1181*0Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1182*0Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
1183*0Sstevel@tonic-gate 				break;
1184*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
1185*0Sstevel@tonic-gate 		break;
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
1188*0Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1189*0Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
1190*0Sstevel@tonic-gate 				break;
1191*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1192*0Sstevel@tonic-gate 		break;
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
1195*0Sstevel@tonic-gate 		rv = ENOTSUP;
1196*0Sstevel@tonic-gate 		break;
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
1199*0Sstevel@tonic-gate 		rv = ENOTSUP;
1200*0Sstevel@tonic-gate 		break;
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate 	default:
1203*0Sstevel@tonic-gate 		rv = ENOTTY;
1204*0Sstevel@tonic-gate 	}
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
1207*0Sstevel@tonic-gate 	return (rv);
1208*0Sstevel@tonic-gate }
1209