xref: /titanic_41/usr/src/uts/sun4u/montecarlo/io/acebus.c (revision 5fbb41393be5d63f75952b1d72d4df2642d22557)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/ddi_impldefs.h>
33 #include <sys/ddi_subrdefs.h>
34 #include <sys/pci.h>
35 #include <sys/pci/pci_nexus.h>
36 #include <sys/autoconf.h>
37 #include <sys/cmn_err.h>
38 #include <sys/errno.h>
39 #include <sys/kmem.h>
40 #include <sys/debug.h>
41 #include <sys/sysmacros.h>
42 #include <sys/acebus.h>
43 
44 #ifdef DEBUG
45 static uint_t acebus_debug_flags = 0;
46 #endif
47 
48 /*
49  * The values of the following variables are used to initialize
50  * the cache line size and latency timer registers in the ebus
51  * configuration header.  Variables are used instead of constants
52  * to allow tuning from the /etc/system file.
53  */
54 static uint8_t acebus_cache_line_size = 0x10;	/* 64 bytes */
55 static uint8_t acebus_latency_timer = 0x40;	/* 64 PCI cycles */
56 
57 /*
58  * function prototypes for bus ops routines:
59  */
60 static int
61 acebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
62 	off_t offset, off_t len, caddr_t *addrp);
63 static int
64 acebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
65 	ddi_ctl_enum_t op, void *arg, void *result);
66 static int
67 acebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
68     ddi_intr_handle_impl_t *hdlp, void *result);
69 
70 /*
71  * function prototypes for dev ops routines:
72  */
73 static int acebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
74 static int acebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
75 
76 /*
77  * general function prototypes:
78  */
79 static int acebus_config(ebus_devstate_t *ebus_p);
80 static int acebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
81     ebus_regspec_t *ebus_rp, pci_regspec_t *rp);
82 static int acebus_get_ranges_prop(ebus_devstate_t *ebus_p);
83 #ifdef	ACEBUS_HOTPLUG
84 static int acebus_update_props(ebus_devstate_t *ebus_p);
85 static int acebus_set_imap(dev_info_t *dip);
86 #endif
87 
88 #define	getprop(dip, name, addr, intp)		\
89 		ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
90 				(name), (caddr_t)(addr), (intp))
91 
92 /*
93  * bus ops and dev ops structures:
94  */
95 static struct bus_ops acebus_bus_ops = {
96 	BUSO_REV,
97 	acebus_map,
98 	NULL,
99 	NULL,
100 	NULL,
101 	i_ddi_map_fault,
102 	ddi_dma_map,
103 	ddi_dma_allochdl,
104 	ddi_dma_freehdl,
105 	ddi_dma_bindhdl,
106 	ddi_dma_unbindhdl,
107 	ddi_dma_flush,
108 	ddi_dma_win,
109 	ddi_dma_mctl,
110 	acebus_ctlops,
111 	ddi_bus_prop_op,
112 	0,				/* (*bus_get_eventcookie)();	*/
113 	0,				/* (*bus_add_eventcall)();	*/
114 	0,				/* (*bus_remove_eventcall)();	*/
115 	0,				/* (*bus_post_event)();		*/
116 	0,				/* (*bus_intr_ctl)();		*/
117 	NULL,				/* (*bus_config)();		*/
118 	NULL,				/* (*bus_unconfig)();		*/
119 	NULL,				/* (*bus_fm_init)();		*/
120 	NULL,				/* (*bus_fm_fini)();		*/
121 	NULL,				/* (*bus_fm_access_enter)();	*/
122 	NULL,				/* (*bus_fm_access_fini)();	*/
123 	NULL,				/* (*bus_power)();		*/
124 	acebus_intr_ops			/* (*bus_intr_op)();		*/
125 };
126 
127 static struct dev_ops acebus_ops = {
128 	DEVO_REV,
129 	0,
130 	ddi_no_info,
131 	nulldev,
132 	nulldev,
133 	acebus_attach,
134 	acebus_detach,
135 	nodev,
136 	(struct cb_ops *)0,
137 	&acebus_bus_ops,
138 	NULL,
139 	ddi_quiesce_not_supported,	/* devo_quiesce */
140 };
141 
142 /*
143  * module definitions:
144  */
145 #include <sys/modctl.h>
146 extern struct mod_ops mod_driverops;
147 
148 static struct modldrv modldrv = {
149 	&mod_driverops, 	/* Type of module.  This one is a driver */
150 	"Alarm Card ebus nexus",	/* Name of module. */
151 	&acebus_ops,		/* driver ops */
152 };
153 
154 static struct modlinkage modlinkage = {
155 	MODREV_1, (void *)&modldrv, NULL
156 };
157 
158 /*
159  * driver global data:
160  */
161 static void *per_acebus_state;		/* per-ebus soft state pointer */
162 
163 
164 int
165 _init(void)
166 {
167 	int e;
168 
169 	/*
170 	 * Initialize per-ebus soft state pointer.
171 	 */
172 	e = ddi_soft_state_init(&per_acebus_state, sizeof (ebus_devstate_t), 1);
173 	if (e != 0)
174 		return (e);
175 
176 	/*
177 	 * Install the module.
178 	 */
179 	e = mod_install(&modlinkage);
180 	if (e != 0)
181 		ddi_soft_state_fini(&per_acebus_state);
182 	return (e);
183 }
184 
185 int
186 _fini(void)
187 {
188 	int e;
189 
190 	/*
191 	 * Remove the module.
192 	 */
193 	e = mod_remove(&modlinkage);
194 	if (e != 0)
195 		return (e);
196 
197 	/*
198 	 * Free the soft state info.
199 	 */
200 	ddi_soft_state_fini(&per_acebus_state);
201 	return (e);
202 }
203 
204 int
205 _info(struct modinfo *modinfop)
206 {
207 	return (mod_info(&modlinkage, modinfop));
208 }
209 
210 /* device driver entry points */
211 
212 /*
213  * attach entry point:
214  *
215  * normal attach:
216  *
217  *	create soft state structure (dip, reg, nreg and state fields)
218  *	map in configuration header
219  *	make sure device is properly configured
220  *	report device
221  */
222 static int
223 acebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
224 {
225 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
226 	int instance;
227 
228 	DBG1(D_ATTACH, NULL, "dip=%x\n", dip);
229 	switch (cmd) {
230 	case DDI_ATTACH:
231 
232 		/*
233 		 * Allocate soft state for this instance.
234 		 */
235 		instance = ddi_get_instance(dip);
236 		if (ddi_soft_state_zalloc(per_acebus_state, instance)
237 		    != DDI_SUCCESS) {
238 			DBG(D_ATTACH, NULL, "failed to alloc soft state\n");
239 			return (DDI_FAILURE);
240 		}
241 		ebus_p = get_acebus_soft_state(instance);
242 		ebus_p->dip = dip;
243 
244 		/*
245 		 * Make sure the master enable and memory access enable
246 		 * bits are set in the config command register.
247 		 */
248 		if (!acebus_config(ebus_p)) {
249 			free_acebus_soft_state(instance);
250 			return (DDI_FAILURE);
251 		}
252 
253 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
254 		    DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0);
255 		/* Get our ranges property for mapping child registers. */
256 		if (acebus_get_ranges_prop(ebus_p) != DDI_SUCCESS) {
257 			free_acebus_soft_state(instance);
258 			return (DDI_FAILURE);
259 		}
260 
261 		/*
262 		 * Make the state as attached and report the device.
263 		 */
264 		ebus_p->state = ATTACHED;
265 		ddi_report_dev(dip);
266 		DBG(D_ATTACH, ebus_p, "returning\n");
267 		return (DDI_SUCCESS);
268 
269 	case DDI_RESUME:
270 
271 		instance = ddi_get_instance(dip);
272 		ebus_p = get_acebus_soft_state(instance);
273 
274 		/*
275 		 * Make sure the master enable and memory access enable
276 		 * bits are set in the config command register.
277 		 */
278 		if (!acebus_config(ebus_p)) {
279 			free_acebus_soft_state(instance);
280 			return (DDI_FAILURE);
281 		}
282 
283 		ebus_p->state = RESUMED;
284 		return (DDI_SUCCESS);
285 	}
286 	return (DDI_FAILURE);
287 }
288 
289 /*
290  * detach entry point:
291  */
292 static int
293 acebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
294 {
295 	int instance = ddi_get_instance(dip);
296 	ebus_devstate_t *ebus_p = get_acebus_soft_state(instance);
297 
298 	switch (cmd) {
299 	case DDI_DETACH:
300 		DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip);
301 		ddi_prop_remove_all(dip);
302 		kmem_free(ebus_p->rangep, ebus_p->range_cnt *
303 		    sizeof (struct ebus_pci_rangespec));
304 		free_acebus_soft_state(instance);
305 		return (DDI_SUCCESS);
306 
307 	case DDI_SUSPEND:
308 		DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip);
309 		ebus_p->state = SUSPENDED;
310 		return (DDI_SUCCESS);
311 	}
312 	return (DDI_FAILURE);
313 }
314 
315 
316 static int
317 acebus_get_ranges_prop(ebus_devstate_t *ebus_p)
318 {
319 	struct ebus_pci_rangespec *rangep;
320 	int nrange, range_len;
321 
322 	if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip, DDI_PROP_DONTPASS,
323 	    "ranges", (caddr_t)&rangep, &range_len) != DDI_SUCCESS) {
324 
325 		cmn_err(CE_WARN, "%s%d: can't get ranges property",
326 		    ddi_get_name(ebus_p->dip), ddi_get_instance(ebus_p->dip));
327 		return (DDI_ME_REGSPEC_RANGE);
328 	}
329 
330 	nrange = range_len / sizeof (struct ebus_pci_rangespec);
331 
332 	if (nrange == 0)  {
333 		kmem_free(rangep, range_len);
334 		return (DDI_FAILURE);
335 	}
336 
337 #ifdef	DEBUG
338 	{
339 		int i;
340 
341 		for (i = 0; i < nrange; i++) {
342 			DBG5(D_MAP, ebus_p,
343 			    "ebus range addr 0x%x.0x%x PCI range "
344 			    "addr 0x%x.0x%x.0x%x ", rangep[i].ebus_phys_hi,
345 			    rangep[i].ebus_phys_low, rangep[i].pci_phys_hi,
346 			    rangep[i].pci_phys_mid, rangep[i].pci_phys_low);
347 			DBG1(D_MAP, ebus_p, "Size 0x%x\n", rangep[i].rng_size);
348 		}
349 	}
350 #endif /* DEBUG */
351 
352 	ebus_p->rangep = rangep;
353 	ebus_p->range_cnt = nrange;
354 
355 	return (DDI_SUCCESS);
356 }
357 
358 
359 /* bus driver entry points */
360 
361 /*
362  * bus map entry point:
363  *
364  * 	if map request is for an rnumber
365  *		get the corresponding regspec from device node
366  * 	build a new regspec in our parent's format
367  *	build a new map_req with the new regspec
368  *	call up the tree to complete the mapping
369  */
370 static int
371 acebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
372 	off_t off, off_t len, caddr_t *addrp)
373 {
374 	ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip));
375 	ebus_regspec_t *ebus_rp, *ebus_regs;
376 	pci_regspec_t pci_reg;
377 	ddi_map_req_t p_map_request;
378 	int rnumber, i, n;
379 	int rval = DDI_SUCCESS;
380 
381 	/*
382 	 * Handle the mapping according to its type.
383 	 */
384 	DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n",
385 	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len);
386 	switch (mp->map_type) {
387 	case DDI_MT_REGSPEC:
388 
389 		/*
390 		 * We assume the register specification is in ebus format.
391 		 * We must convert it into a PCI format regspec and pass
392 		 * the request to our parent.
393 		 */
394 		DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%x\n",
395 		    ddi_get_name(rdip), ddi_get_instance(rdip),
396 		    mp->map_handlep);
397 		ebus_rp = (ebus_regspec_t *)mp->map_obj.rp;
398 		break;
399 
400 	case DDI_MT_RNUMBER:
401 
402 		/*
403 		 * Get the "reg" property from the device node and convert
404 		 * it to our parent's format.
405 		 */
406 		rnumber = mp->map_obj.rnumber;
407 		DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%x\n",
408 		    ddi_get_name(rdip), ddi_get_instance(rdip),
409 		    rnumber, mp->map_handlep);
410 
411 		if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) {
412 			DBG(D_MAP, ebus_p, "can't get reg property\n");
413 			return (DDI_ME_RNUMBER_RANGE);
414 		}
415 		n = i / sizeof (ebus_regspec_t);
416 
417 		if (rnumber < 0 || rnumber >= n) {
418 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
419 			return (DDI_ME_RNUMBER_RANGE);
420 		}
421 		ebus_rp = &ebus_regs[rnumber];
422 		break;
423 
424 	default:
425 		return (DDI_ME_INVAL);
426 
427 	}
428 
429 	/* Adjust our reg property with offset and length */
430 	ebus_rp->addr_low += off;
431 	if (len)
432 		ebus_rp->size = len;
433 
434 	/*
435 	 * Now we have a copy the "reg" entry we're attempting to map.
436 	 * Translate this into our parents PCI address using the ranges
437 	 * property.
438 	 */
439 	rval = acebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg);
440 
441 	if (mp->map_type == DDI_MT_RNUMBER)
442 		kmem_free((caddr_t)ebus_regs, i);
443 
444 	if (rval != DDI_SUCCESS)
445 		return (rval);
446 
447 #ifdef	ACEBUS_HOTPLUG
448 	/*
449 	 * The map operation provides a translated (not a re-assigned, or
450 	 * relocated) ebus address for the child in its address space(range).
451 	 * Ebus address space is relocatible but its child address space
452 	 * is not. As specified by their 'reg' properties, they reside
453 	 * at a fixed offset in their parent's (ebus's) space.
454 	 *
455 	 * By setting this bit, we will not run into HostPCI nexus
456 	 * trying to relocate a translated ebus address (which is already
457 	 * relocated) and failing the operation.
458 	 * The reason for doing this here is that the PCI hotplug configurator
459 	 * always marks the ebus space as relocatible (unlike OBP) and that
460 	 * information is implied for the child too, which is wrong.
461 	 */
462 	pci_reg.pci_phys_hi |= PCI_RELOCAT_B;
463 #endif
464 #ifdef DEBUG
465 	DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n",
466 	    pci_reg.pci_phys_hi,
467 	    pci_reg.pci_phys_mid,
468 	    pci_reg.pci_phys_low,
469 	    pci_reg.pci_size_hi,
470 	    pci_reg.pci_size_low);
471 #endif
472 
473 	p_map_request = *mp;
474 	p_map_request.map_type = DDI_MT_REGSPEC;
475 	p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
476 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
477 	DBG1(D_MAP, ebus_p, "parent returned %x\n", rval);
478 	return (rval);
479 }
480 
481 
482 static int
483 acebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
484     ebus_regspec_t *ebus_rp, pci_regspec_t *rp)
485 {
486 	int b;
487 	int rval = DDI_SUCCESS;
488 	struct ebus_pci_rangespec *rangep = ebus_p->rangep;
489 	int nrange = ebus_p->range_cnt;
490 	static const char out_of_range[] =
491 	    "Out of range register specification from device node <%s>";
492 
493 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
494 	    ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
495 
496 	for (b = 0; b < nrange; ++b, ++rangep) {
497 
498 		/* Check for the correct space */
499 		if (ebus_rp->addr_hi == rangep->ebus_phys_hi)
500 			/* See if we fit in this range */
501 			if ((ebus_rp->addr_low >=
502 			    rangep->ebus_phys_low) &&
503 			    ((ebus_rp->addr_low + ebus_rp->size - 1)
504 			    <= (rangep->ebus_phys_low +
505 			    rangep->rng_size - 1))) {
506 				uint_t addr_offset = ebus_rp->addr_low -
507 				    rangep->ebus_phys_low;
508 				/*
509 				 * Use the range entry to translate
510 				 * the EBUS physical address into the
511 				 * parents PCI space.
512 				 */
513 				rp->pci_phys_hi =
514 				    rangep->pci_phys_hi;
515 				rp->pci_phys_mid = rangep->pci_phys_mid;
516 				rp->pci_phys_low =
517 				    rangep->pci_phys_low + addr_offset;
518 				rp->pci_size_hi = 0;
519 				rp->pci_size_low =
520 				    min(ebus_rp->size, (rangep->rng_size -
521 				    addr_offset));
522 
523 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
524 				    rangep->ebus_phys_hi,
525 				    rangep->ebus_phys_low);
526 				DBG4(D_MAP, ebus_p, "Parent hi0x%x "
527 				    "mid0x%x lo0x%x size 0x%x\n",
528 				    rangep->pci_phys_hi,
529 				    rangep->pci_phys_mid,
530 				    rangep->pci_phys_low,
531 				    rangep->rng_size);
532 
533 				break;
534 			}
535 	}
536 
537 	if (b == nrange)  {
538 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
539 		return (DDI_ME_REGSPEC_RANGE);
540 	}
541 
542 	return (rval);
543 }
544 
545 
546 /*
547  * control ops entry point:
548  *
549  * Requests handled completely:
550  *	DDI_CTLOPS_INITCHILD
551  *	DDI_CTLOPS_UNINITCHILD
552  *	DDI_CTLOPS_REPORTDEV
553  *	DDI_CTLOPS_REGSIZE
554  *	DDI_CTLOPS_NREGS
555  *
556  * All others passed to parent.
557  */
558 static int
559 acebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
560 	ddi_ctl_enum_t op, void *arg, void *result)
561 {
562 #ifdef DEBUG
563 	ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip));
564 #endif
565 	ebus_regspec_t *ebus_rp;
566 	int32_t reglen;
567 	int i, n;
568 	char name[10];
569 
570 	switch (op) {
571 	case DDI_CTLOPS_INITCHILD: {
572 		dev_info_t *child = (dev_info_t *)arg;
573 		/*
574 		 * Set the address portion of the node name based on the
575 		 * address/offset.
576 		 */
577 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
578 		    ddi_get_name(child), ddi_get_instance(child));
579 
580 		if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
581 		    "reg", (caddr_t)&ebus_rp, &reglen) != DDI_SUCCESS) {
582 
583 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
584 			return (DDI_FAILURE);
585 
586 		}
587 
588 		(void) sprintf(name, "%x,%x", ebus_rp->addr_hi,
589 		    ebus_rp->addr_low);
590 		ddi_set_name_addr(child, name);
591 		kmem_free((caddr_t)ebus_rp, reglen);
592 
593 		ddi_set_parent_data(child, NULL);
594 
595 		return (DDI_SUCCESS);
596 
597 	}
598 
599 	case DDI_CTLOPS_UNINITCHILD:
600 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
601 		    ddi_get_name((dev_info_t *)arg),
602 		    ddi_get_instance((dev_info_t *)arg));
603 		ddi_set_name_addr((dev_info_t *)arg, NULL);
604 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
605 		impl_rem_dev_props((dev_info_t *)arg);
606 		return (DDI_SUCCESS);
607 
608 	case DDI_CTLOPS_REPORTDEV:
609 
610 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
611 		    ddi_get_name(rdip), ddi_get_instance(rdip));
612 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
613 		    ddi_driver_name(rdip), ddi_get_instance(rdip),
614 		    ddi_driver_name(dip), ddi_get_instance(dip),
615 		    ddi_get_name_addr(rdip));
616 		return (DDI_SUCCESS);
617 
618 	case DDI_CTLOPS_REGSIZE:
619 
620 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
621 		    ddi_get_name(rdip), ddi_get_instance(rdip));
622 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
623 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
624 			return (DDI_FAILURE);
625 		}
626 		n = i / sizeof (ebus_regspec_t);
627 		if (*(int *)arg < 0 || *(int *)arg >= n) {
628 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
629 			kmem_free((caddr_t)ebus_rp, i);
630 			return (DDI_FAILURE);
631 		}
632 		*((off_t *)result) = ebus_rp[*(int *)arg].size;
633 		kmem_free((caddr_t)ebus_rp, i);
634 		return (DDI_SUCCESS);
635 
636 	case DDI_CTLOPS_NREGS:
637 
638 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
639 		    ddi_get_name(rdip), ddi_get_instance(rdip));
640 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
641 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
642 			return (DDI_FAILURE);
643 		}
644 		*((uint_t *)result) = i / sizeof (ebus_regspec_t);
645 		kmem_free((caddr_t)ebus_rp, i);
646 		return (DDI_SUCCESS);
647 	}
648 
649 	/*
650 	 * Now pass the request up to our parent.
651 	 */
652 	DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n",
653 	    ddi_get_name(rdip), ddi_get_instance(rdip));
654 	return (ddi_ctlops(dip, rdip, op, arg, result));
655 }
656 
657 struct ebus_string_to_pil {
658 	int8_t *string;
659 	uint32_t pil;
660 };
661 
662 static struct ebus_string_to_pil acebus_name_to_pil[] = {{"SUNW,CS4231", 9},
663 						    {"fdthree", 8},
664 						    {"ecpp", 3},
665 						    {"su", 12},
666 						    {"se", 12},
667 						    {"power", 14}};
668 
669 static struct ebus_string_to_pil acebus_device_type_to_pil[] = {{"serial", 12},
670 								{"block", 8}};
671 
672 static int
673 acebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
674     ddi_intr_handle_impl_t *hdlp, void *result)
675 {
676 #ifdef DEBUG
677 	ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip));
678 #endif
679 	int8_t		*name, *device_type;
680 	int32_t		i, max_children, max_device_types, len;
681 
682 	/*
683 	 * NOTE: These ops below will never be supported in this nexus
684 	 * driver, hence they always return immediately.
685 	 */
686 	switch (intr_op) {
687 	case DDI_INTROP_GETCAP:
688 		*(int *)result = DDI_INTR_FLAG_LEVEL;
689 		return (DDI_SUCCESS);
690 	case DDI_INTROP_SUPPORTED_TYPES:
691 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
692 		    DDI_INTR_TYPE_FIXED : 0;
693 		return (DDI_SUCCESS);
694 	case DDI_INTROP_SETCAP:
695 	case DDI_INTROP_SETMASK:
696 	case DDI_INTROP_CLRMASK:
697 	case DDI_INTROP_GETPENDING:
698 		return (DDI_ENOTSUP);
699 	default:
700 		break;
701 	}
702 
703 	if (hdlp->ih_pri)
704 		goto done;
705 
706 	/*
707 	 * This is a hack to set the PIL for the devices under ebus.
708 	 * We first look up a device by it's specific name, if we can't
709 	 * match the name, we try and match it's device_type property.
710 	 * Lastly we default a PIL level of 1.
711 	 */
712 	DBG1(D_INTR, ebus_p, "ebus_p %p\n", ebus_p);
713 
714 	name = ddi_get_name(rdip);
715 	max_children = sizeof (acebus_name_to_pil) /
716 	    sizeof (struct ebus_string_to_pil);
717 
718 	for (i = 0; i < max_children; i++) {
719 		if (strcmp(acebus_name_to_pil[i].string, name) == 0) {
720 			DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n",
721 			    acebus_name_to_pil[i].string,
722 			    acebus_name_to_pil[i].pil);
723 
724 			hdlp->ih_pri = acebus_name_to_pil[i].pil;
725 			goto done;
726 		}
727 	}
728 
729 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
730 	    "device_type", (caddr_t)&device_type, &len) == DDI_SUCCESS) {
731 
732 		max_device_types = sizeof (acebus_device_type_to_pil) /
733 		    sizeof (struct ebus_string_to_pil);
734 
735 		for (i = 0; i < max_device_types; i++) {
736 			if (strcmp(acebus_device_type_to_pil[i].string,
737 			    device_type) == 0) {
738 				DBG2(D_INTR, ebus_p,
739 				    "Device type %s; match PIL %d\n",
740 				    acebus_device_type_to_pil[i].string,
741 				    acebus_device_type_to_pil[i].pil);
742 
743 				hdlp->ih_pri = acebus_device_type_to_pil[i].pil;
744 				break;
745 			}
746 		}
747 
748 		kmem_free(device_type, len);
749 	}
750 
751 	/*
752 	 * If we get here, we need to set a default value
753 	 * for the PIL.
754 	 */
755 	if (hdlp->ih_pri == 0) {
756 		hdlp->ih_pri = 1;
757 		cmn_err(CE_WARN, "%s%d assigning default interrupt level %d "
758 		    "for device %s%d", ddi_driver_name(dip),
759 		    ddi_get_instance(dip), hdlp->ih_pri, ddi_driver_name(rdip),
760 		    ddi_get_instance(rdip));
761 	}
762 
763 done:
764 	/* Pass up the request to our parent. */
765 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
766 }
767 
768 
769 static int
770 acebus_config(ebus_devstate_t *ebus_p)
771 {
772 	ddi_acc_handle_t conf_handle;
773 	uint16_t comm;
774 #ifdef	ACEBUS_HOTPLUG
775 	int tcr_reg;
776 	caddr_t csr_io;
777 	ddi_device_acc_attr_t csr_attr = {   /* CSR map attributes */
778 		DDI_DEVICE_ATTR_V0,
779 		DDI_STRUCTURE_LE_ACC,
780 		DDI_STRICTORDER_ACC
781 	};
782 	ddi_acc_handle_t csr_handle;
783 #endif
784 
785 	/*
786 	 * Make sure the master enable and memory access enable
787 	 * bits are set in the config command register.
788 	 */
789 	if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS)
790 		return (0);
791 
792 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM),
793 #ifdef DEBUG
794 	    DBG1(D_ATTACH, ebus_p, "command register was 0x%x\n", comm);
795 #endif
796 	comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE|
797 	    PCI_COMM_PARITY_DETECT);
798 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm),
799 #ifdef DEBUG
800 	    DBG1(D_MAP, ebus_p, "command register is now 0x%x\n",
801 	    pci_config_get16(conf_handle, PCI_CONF_COMM));
802 #endif
803 	pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ,
804 	    (uchar_t)acebus_cache_line_size);
805 	pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER,
806 	    (uchar_t)acebus_latency_timer);
807 	pci_config_teardown(&conf_handle);
808 
809 #ifdef	ACEBUS_HOTPLUG
810 	if (acebus_update_props(ebus_p) != DDI_SUCCESS) {
811 		cmn_err(CE_WARN, "%s%d: Could not update special properties.",
812 		    ddi_driver_name(ebus_p->dip),
813 		    ddi_get_instance(ebus_p->dip));
814 		return (0);
815 	}
816 
817 	if (ddi_regs_map_setup(ebus_p->dip, CSR_IO_RINDEX,
818 	    (caddr_t *)&csr_io, 0, CSR_SIZE, &csr_attr,
819 	    &csr_handle) != DDI_SUCCESS) {
820 		cmn_err(CE_WARN, "%s%d: Could not map Ebus CSR.",
821 		    ddi_driver_name(ebus_p->dip),
822 		    ddi_get_instance(ebus_p->dip));
823 	}
824 #ifdef	DEBUG
825 	if (acebus_debug_flags) {
826 		DBG3(D_ATTACH, ebus_p, "tcr[123] = %x,%x,%x\n",
827 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
828 		    TCR1_OFF)),
829 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
830 		    TCR2_OFF)),
831 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
832 		    TCR3_OFF)));
833 		DBG2(D_ATTACH, ebus_p, "pmd-aux=%x, freq-aux=%x\n",
834 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
835 		    PMD_AUX_OFF)),
836 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
837 		    FREQ_AUX_OFF)));
838 #ifdef ACEBUS_DEBUG
839 		for (comm = 0; comm < 4; comm++)
840 			prom_printf("dcsr%d=%x, dacr%d=%x, dbcr%d=%x\n", comm,
841 			    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
842 			    0x700000+(0x2000*comm))), comm,
843 			    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
844 			    0x700000+(0x2000*comm)+4)), comm,
845 			    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
846 			    0x700000+(0x2000*comm)+8)));
847 #endif
848 	} /* acebus_debug_flags */
849 #endif
850 	/* If TCR registers are not initialized, initialize them here */
851 	tcr_reg = ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
852 	    TCR1_OFF));
853 	if ((tcr_reg == 0) || (tcr_reg == -1))
854 		ddi_put32(csr_handle, (uint32_t *)((caddr_t)csr_io + TCR1_OFF),
855 		    TCR1_REGVAL);
856 	tcr_reg = ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
857 	    TCR2_OFF));
858 	if ((tcr_reg == 0) || (tcr_reg == -1))
859 		ddi_put32(csr_handle, (uint32_t *)((caddr_t)csr_io + TCR2_OFF),
860 		    TCR2_REGVAL);
861 	tcr_reg = ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
862 	    TCR3_OFF));
863 	if ((tcr_reg == 0) || (tcr_reg == -1))
864 		ddi_put32(csr_handle, (uint32_t *)((caddr_t)csr_io + TCR3_OFF),
865 		    TCR3_REGVAL);
866 #ifdef	DEBUG
867 	if (acebus_debug_flags) {
868 		DBG3(D_ATTACH, ebus_p, "wrote tcr[123] = %x,%x,%x\n",
869 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
870 		    TCR1_OFF)),
871 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
872 		    TCR2_OFF)),
873 		    ddi_get32(csr_handle, (uint32_t *)((caddr_t)csr_io +
874 		    TCR3_OFF)));
875 	}
876 #endif
877 
878 	ddi_regs_map_free(&csr_handle);
879 #endif	/* ACEBUS_HOTPLUG */
880 	return (1);	/* return success */
881 }
882 
883 #ifdef DEBUG
884 extern void prom_printf(const char *, ...);
885 
886 static void
887 acebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt,
888 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
889 {
890 	char *s;
891 
892 	if (acebus_debug_flags & flag) {
893 		switch (flag) {
894 		case D_ATTACH:
895 			s = "attach"; break;
896 		case D_DETACH:
897 			s = "detach"; break;
898 		case D_MAP:
899 			s = "map"; break;
900 		case D_CTLOPS:
901 			s = "ctlops"; break;
902 		case D_INTR:
903 			s = "intr"; break;
904 		}
905 		if (ebus_p)
906 			cmn_err(CE_CONT, "%s%d: %s: ",
907 			    ddi_get_name(ebus_p->dip),
908 			    ddi_get_instance(ebus_p->dip), s);
909 		else
910 			cmn_err(CE_CONT, "ebus: ");
911 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
912 	}
913 }
914 #endif
915 
916 #ifdef	ACEBUS_HOTPLUG
917 #define	EBUS_CHILD_PHYS_LOW_RANGE	0x10
918 #define	EBUS_CHILD_PHYS_HI_RANGE	0x14
919 
920 static int
921 acebus_update_props(ebus_devstate_t *ebus_p)
922 {
923 	dev_info_t *dip = ebus_p->dip;
924 	struct ebus_pci_rangespec er[2], *erp;
925 	pci_regspec_t *pci_rp, *prp;
926 	int length, rnums, imask[3], i, found = 0;
927 
928 	/*
929 	 * If "ranges" property is found, then the device is initialized
930 	 * by OBP, hence simply return.
931 	 * Otherwise we create all the properties here.
932 	 */
933 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
934 	    "ranges", (int **)&erp, (uint_t *)&length) == DDI_PROP_SUCCESS) {
935 		ddi_prop_free(erp);
936 		return (DDI_SUCCESS);
937 	}
938 
939 	/*
940 	 * interrupt-map is the only property that comes from a .conf file.
941 	 * Since it doesn't have the nodeid field set, it must be done here.
942 	 * Other properties can come from OBP or created here.
943 	 */
944 	if (acebus_set_imap(dip) != DDI_SUCCESS) {
945 		return (DDI_FAILURE);
946 	}
947 
948 	/*
949 	 * Create the "ranges" property.
950 	 * Ebus has BAR0 and BAR1 allocated (both in memory space).
951 	 * Other BARs are 0.
952 	 * Hence there are 2 memory ranges it operates in. (one for each BAR).
953 	 * ie. there are 2 entries in its ranges property.
954 	 */
955 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
956 	    DDI_PROP_DONTPASS, "assigned-addresses",
957 	    (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
958 		cmn_err(CE_WARN, "%s%d: Could not get assigned-addresses",
959 		    ddi_driver_name(dip), ddi_get_instance(dip));
960 		return (DDI_FAILURE);
961 	}
962 	/*
963 	 * Create the 1st mem range in which it operates corresponding
964 	 * to BAR0
965 	 */
966 	er[0].ebus_phys_hi = EBUS_CHILD_PHYS_LOW_RANGE;
967 	rnums = (length * sizeof (int))/sizeof (pci_regspec_t);
968 	for (i = 0; i < rnums; i++) {
969 		prp = pci_rp + i;
970 		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[0].ebus_phys_hi) {
971 			found = 1;
972 			break;
973 		}
974 	}
975 	if (!found) {
976 		cmn_err(CE_WARN, "No assigned space for memory range 0.");
977 		ddi_prop_free(pci_rp);
978 		return (DDI_FAILURE);
979 	}
980 	found = 0;
981 	er[0].ebus_phys_low = 0;
982 	er[0].pci_phys_hi = prp->pci_phys_hi;
983 	er[0].pci_phys_mid = prp->pci_phys_mid;
984 	er[0].pci_phys_low = prp->pci_phys_low;
985 	er[0].rng_size = prp->pci_size_low;
986 
987 	/*
988 	 * Create the 2nd mem range in which it operates corresponding
989 	 * to BAR1
990 	 */
991 	er[1].ebus_phys_hi = EBUS_CHILD_PHYS_HI_RANGE;
992 	for (i = 0; i < rnums; i++) {
993 		prp = pci_rp + i;
994 		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[1].ebus_phys_hi) {
995 			found = 1;
996 			break;
997 		}
998 	}
999 	if (!found) {
1000 		cmn_err(CE_WARN, "No assigned space for memory range 1.");
1001 		ddi_prop_free(pci_rp);
1002 		return (DDI_FAILURE);
1003 	}
1004 	er[1].ebus_phys_low = 0;
1005 	er[1].pci_phys_hi = prp->pci_phys_hi;
1006 	er[1].pci_phys_mid = prp->pci_phys_mid;
1007 	er[1].pci_phys_low = prp->pci_phys_low;
1008 	er[1].rng_size = prp->pci_size_low;
1009 
1010 	ddi_prop_free(pci_rp);
1011 	length = sizeof (er) / sizeof (int);
1012 	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1013 	    "ranges", (int *)er, length) != DDI_PROP_SUCCESS) {
1014 		cmn_err(CE_WARN, "%s%d: Could not create ranges property",
1015 		    ddi_driver_name(dip), ddi_get_instance(dip));
1016 		return (DDI_FAILURE);
1017 	}
1018 	/* The following properties are as defined by PCI 1275 bindings. */
1019 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
1020 	    "#address-cells", 2) != DDI_PROP_SUCCESS)
1021 			return (DDI_FAILURE);
1022 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
1023 	    "#size-cells", 1) != DDI_PROP_SUCCESS)
1024 			return (DDI_FAILURE);
1025 	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
1026 	    "#interrupt-cells", 1) != DDI_PROP_SUCCESS)
1027 			return (DDI_FAILURE);
1028 
1029 	imask[0] = 0x1f;
1030 	imask[1] = 0x00ffffff;
1031 	imask[2] = 0x00000003;
1032 	length = sizeof (imask) / sizeof (int);
1033 	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1034 	    "interrupt-map-mask", (int *)imask, length) != DDI_PROP_SUCCESS) {
1035 		cmn_err(CE_WARN, "%s%d: Could not update imap mask property",
1036 		    ddi_driver_name(dip), ddi_get_instance(dip));
1037 		return (DDI_FAILURE);
1038 	}
1039 
1040 	return (DDI_SUCCESS);
1041 }
1042 
1043 /*
1044  * This function takes in the ac-interrupt-map property from the .conf file,
1045  * fills in the 'nodeid' information and then creates the 'interrupt-map'
1046  * property.
1047  */
1048 static int
1049 acebus_set_imap(dev_info_t *dip)
1050 {
1051 	int *imapp, *timapp, length, num, i, default_ival = 0;
1052 	dev_info_t *tdip = dip;
1053 	int *port_id, imap_ok = 1;
1054 	int ilength;
1055 	int acebus_default_se_imap[5];
1056 
1057 	/*
1058 	 * interrupt-map is specified via .conf file in hotplug mode,
1059 	 * since the child configuration is static.
1060 	 * It could even be hardcoded in the driver.
1061 	 */
1062 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1063 	    "ac-interrupt-map", (int **)&imapp, (uint_t *)&ilength) !=
1064 	    DDI_PROP_SUCCESS) {
1065 		/* assume default implementation */
1066 		acebus_default_se_imap[0] = 0x14;
1067 		acebus_default_se_imap[1] = 0x400000;
1068 		acebus_default_se_imap[2] = 1;
1069 		acebus_default_se_imap[3] = 0;
1070 		acebus_default_se_imap[4] = 2;
1071 		imapp = acebus_default_se_imap;
1072 		ilength = 5;
1073 		default_ival = 1;
1074 	}
1075 	num = ilength / 5;	/* there are 5 integer cells in our property */
1076 	timapp = imapp;
1077 	for (i = 0; i < num; i++) {
1078 		if (*(timapp+i*5+3) == 0)
1079 			imap_ok = 0;
1080 	}
1081 	if (imap_ok) {
1082 		if (!default_ival)
1083 			ddi_prop_free(imapp);
1084 		return (DDI_SUCCESS);
1085 	}
1086 
1087 	while (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, tdip,
1088 	    DDI_PROP_DONTPASS, "upa-portid", (int **)&port_id,
1089 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
1090 		tdip = ddi_get_parent(tdip);
1091 		if (tdip == NULL) {
1092 			cmn_err(CE_WARN, "%s%d: Could not get imap parent",
1093 			    ddi_driver_name(dip), ddi_get_instance(dip));
1094 			if (!default_ival)
1095 				ddi_prop_free(imapp);
1096 			return (DDI_FAILURE);
1097 		}
1098 	}
1099 	timapp = imapp;
1100 	for (i = 0; i < num; i++) {
1101 		*(timapp+i*5+3) = ddi_get_nodeid(tdip);
1102 	}
1103 
1104 	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1105 	    "interrupt-map", imapp, ilength) != DDI_PROP_SUCCESS) {
1106 		cmn_err(CE_WARN, "%s%d: Could not update AC imap property",
1107 		    ddi_driver_name(dip), ddi_get_instance(dip));
1108 		if (!default_ival)
1109 			ddi_prop_free(imapp);
1110 		return (DDI_FAILURE);
1111 	}
1112 	if (!default_ival)
1113 		ddi_prop_free(imapp);
1114 	return (DDI_SUCCESS);
1115 }
1116 #endif	/* ACEBUS_HOTPLUG */
1117