xref: /illumos-gate/usr/src/uts/sun4u/io/upa64s.c (revision e42d2a1c942c82ff0fa3de86624e48f22c4457c0)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/autoconf.h>
34 #include <sys/ddi_impldefs.h>
35 #include <sys/ddi_subrdefs.h>
36 #include <sys/cmn_err.h>
37 #include <sys/errno.h>
38 #include <sys/kmem.h>
39 #include <sys/debug.h>
40 #include <sys/sysmacros.h>
41 #include <sys/spl.h>
42 #include <sys/async.h>
43 #include <sys/dvma.h>
44 #include <sys/upa64s.h>
45 #include <sys/machsystm.h>
46 
47 /*
48  * driver global data:
49  */
50 static void *per_upa64s_state;		/* soft state pointer */
51 
52 /*
53  * function prototypes for bus ops routines:
54  */
55 static int
56 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
57     off_t offset, off_t len, caddr_t *addrp);
58 static int
59 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
60     ddi_ctl_enum_t op, void *arg, void *result);
61 static int
62 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
63     ddi_intr_handle_impl_t *hdlp, void *result);
64 static int
65 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
66     ddi_intr_handle_impl_t *hdlp);
67 static int
68 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
69     ddi_intr_handle_impl_t *hdlp);
70 
71 /*
72  * function prototypes for dev ops routines:
73  */
74 static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
75 static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
76 static int upa64s_power(dev_info_t *dip, int component, int level);
77 
78 /*
79  * bus ops and dev ops structures:
80  */
81 static struct bus_ops upa64s_bus_ops = {
82 	BUSO_REV,
83 	upa64s_map,
84 	0,
85 	0,
86 	0,
87 	i_ddi_map_fault,
88 	ddi_no_dma_map,
89 	ddi_no_dma_allochdl,
90 	ddi_no_dma_freehdl,
91 	ddi_no_dma_bindhdl,
92 	ddi_no_dma_unbindhdl,
93 	ddi_no_dma_flush,
94 	ddi_no_dma_win,
95 	ddi_no_dma_mctl,
96 	upa64s_ctlops,
97 	ddi_bus_prop_op,
98 	0,
99 	0,
100 	0,
101 	0,
102 	0,
103 	0,
104 	0,
105 	0,
106 	0,
107 	0,
108 	0,
109 	0,
110 	upa64_intr_ops
111 };
112 
113 static struct dev_ops upa64s_ops = {
114 	DEVO_REV,
115 	0,
116 	ddi_no_info,
117 	nulldev,
118 	0,
119 	upa64s_attach,
120 	upa64s_detach,
121 	nodev,
122 	(struct cb_ops *)0,
123 	&upa64s_bus_ops,
124 	upa64s_power
125 };
126 
127 /*
128  * module definitions:
129  */
130 #include <sys/modctl.h>
131 extern struct mod_ops mod_driverops;
132 
133 static struct modldrv modldrv = {
134 	&mod_driverops, 		/* type of module */
135 	"UPA64S nexus driver %I%",	/* name of module */
136 	&upa64s_ops,			/* driver ops */
137 };
138 
139 static struct modlinkage modlinkage = {
140 	MODREV_1, (void *)&modldrv, NULL
141 };
142 
143 int
144 _init(void)
145 {
146 	int e;
147 
148 	/*
149 	 * Initialize per instance bus soft state pointer.
150 	 */
151 	if (e = ddi_soft_state_init(&per_upa64s_state,
152 	    sizeof (upa64s_devstate_t), 2))
153 		return (e);
154 	/*
155 	 * Install the module.
156 	 */
157 	if (e = mod_install(&modlinkage))
158 		ddi_soft_state_fini(&per_upa64s_state);
159 	return (e);
160 }
161 
162 int
163 _fini(void)
164 {
165 	int e = mod_remove(&modlinkage);
166 	if (e)
167 		return (e);
168 	ddi_soft_state_fini(&per_upa64s_state);
169 	return (e);
170 }
171 
172 int
173 _info(struct modinfo *modinfop)
174 {
175 	return (mod_info(&modlinkage, modinfop));
176 }
177 
178 
179 /*
180  * forward declarations:
181  */
182 static void upa64s_intrdist(void *arg);
183 static int init_child(dev_info_t *child);
184 static int report_dev(dev_info_t *dip);
185 static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip);
186 static void save_state(upa64s_devstate_t *upa64s_p);
187 static void restore_state(upa64s_devstate_t *upa64s_p);
188 static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp,
189     off_t off, off_t len, struct regspec *rp);
190 static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
191     off_t off, off_t len, struct regspec *rp);
192 static off_t get_reg_set_size(dev_info_t *child, int rnumber);
193 static uint_t get_nreg_set(dev_info_t *child);
194 
195 
196 /* device driver entry points */
197 
198 /*
199  * attach entry point:
200  */
201 static int
202 upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
203 {
204 	upa64s_devstate_t *upa64s_p;	/* per upa64s state pointer */
205 	ddi_device_acc_attr_t attr;
206 	int instance;
207 	char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL };
208 
209 	switch (cmd) {
210 	case DDI_ATTACH:
211 		/*
212 		 * Allocate and get the per instance soft state structure.
213 		 */
214 		instance = ddi_get_instance(dip);
215 		if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) {
216 			cmn_err(CE_WARN, "%s%d: can't allocate upa64s state",
217 			    ddi_get_name(dip), instance);
218 			return (DDI_FAILURE);
219 		}
220 		upa64s_p = get_upa64s_soft_state(instance);
221 		upa64s_p->dip = dip;
222 
223 		/*
224 		 * Get key properties of the bridge node.
225 		 */
226 		if (get_properties(upa64s_p, dip) != DDI_SUCCESS)
227 			goto fail;
228 
229 		/*
230 		 * Create "pm-components" property for the purpose of
231 		 * doing Power Management.
232 		 */
233 		if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
234 		    "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1))
235 		    != DDI_PROP_SUCCESS) {
236 			cmn_err(CE_WARN, "%s%d: failed to create pm-components "
237 			    "property.", ddi_get_name(dip), instance);
238 			goto fail;
239 		}
240 
241 		/* Map in the UPA's registers */
242 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
243 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
244 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
245 		if (ddi_regs_map_setup(dip, 0,
246 		    (caddr_t *)&upa64s_p->config_base, 0, 0, &attr,
247 		    &upa64s_p->config_base_ah) != DDI_SUCCESS) {
248 			cmn_err(CE_WARN, "%s%d: failed to map reg1.",
249 			    ddi_get_name(dip), instance);
250 			goto fail;
251 		}
252 
253 		upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base +
254 		    UPA64S_UPA0_CONFIG_OFFSET);
255 		upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base +
256 		    UPA64S_UPA1_CONFIG_OFFSET);
257 		upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base +
258 		    UPA64S_IF_CONFIG_OFFSET);
259 		upa64s_p->estar = (uint64_t *)(upa64s_p->config_base +
260 		    UPA64S_ESTAR_OFFSET);
261 
262 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0],
263 		    0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) {
264 			cmn_err(CE_WARN, "%s%d: failed to map reg2.",
265 			    ddi_get_name(dip), instance);
266 			goto fail1;
267 		}
268 
269 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1],
270 		    0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) {
271 			cmn_err(CE_WARN, "%s%d: failed to map reg3.",
272 			    ddi_get_name(dip), instance);
273 			goto fail2;
274 		}
275 
276 		/*
277 		 * Power level of a component is unknown at attach time.
278 		 * Bring the power level to what is needed for normal operation.
279 		 */
280 		upa64s_p->power_level = UPA64S_PM_UNKNOWN;
281 		if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) !=
282 		    DDI_SUCCESS) {
283 			cmn_err(CE_WARN, "%s%d: failed to raise the power.",
284 			    ddi_get_name(dip), instance);
285 			goto fail3;
286 		}
287 
288 		intr_dist_add(upa64s_intrdist, dip);
289 
290 		ddi_report_dev(dip);
291 		return (DDI_SUCCESS);
292 
293 	case DDI_RESUME:
294 
295 		upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip));
296 		DBG(D_ATTACH, dip, "DDI_RESUME\n");
297 		restore_state(upa64s_p);
298 
299 		/*
300 		 * Power level of a component is unknown at resume time.
301 		 * Bring the power level to what it was before suspend.
302 		 */
303 		upa64s_p->power_level = UPA64S_PM_UNKNOWN;
304 		if (pm_raise_power(dip, UPA64S_PM_COMP,
305 		    upa64s_p->saved_power_level) != DDI_SUCCESS)
306 			cmn_err(CE_WARN, "%s%d: failed to change power level "
307 			    "during resume!", ddi_get_name(dip), instance);
308 
309 		return (DDI_SUCCESS);
310 
311 	default:
312 		return (DDI_FAILURE);
313 	}
314 
315 fail3:
316 	ddi_regs_map_free(&upa64s_p->imr_ah[1]);
317 fail2:
318 	ddi_regs_map_free(&upa64s_p->imr_ah[0]);
319 fail1:
320 	ddi_regs_map_free(&upa64s_p->config_base_ah);
321 fail:
322 	free_upa64s_soft_state(instance);
323 	return (DDI_FAILURE);
324 }
325 
326 
327 /*
328  * detach entry point:
329  */
330 static int
331 upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
332 {
333 	int instance = ddi_get_instance(dip);
334 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
335 
336 	switch (cmd) {
337 	case DDI_DETACH:
338 
339 		DBG(D_DETACH, dip, "DDI_DETACH\n");
340 
341 		/*
342 		 * Power down the device.
343 		 */
344 		if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) !=
345 		    DDI_SUCCESS)
346 			DBG(D_DETACH, dip, "failed to power off!\n");
347 
348 		intr_dist_rem(upa64s_intrdist, dip);
349 
350 		ddi_regs_map_free(&upa64s_p->config_base_ah);
351 		ddi_regs_map_free(&upa64s_p->imr_ah[0]);
352 		ddi_regs_map_free(&upa64s_p->imr_ah[1]);
353 		free_upa64s_soft_state(instance);
354 		return (DDI_SUCCESS);
355 
356 	case DDI_SUSPEND:
357 
358 		DBG(D_DETACH, dip, "DDI_SUSPEND\n");
359 		save_state(upa64s_p);
360 		upa64s_p->saved_power_level = upa64s_p->power_level;
361 		return (DDI_SUCCESS);
362 	}
363 
364 	return (DDI_FAILURE);
365 }
366 
367 /*
368  * power entry point:
369  *
370  * This entry point is called by Power Management framework to
371  * reset upa bus and slow down/speed up the upa interface of
372  * Schizo chip.
373  */
374 static int
375 upa64s_power(dev_info_t *dip, int component, int level)
376 {
377 	int instance = ddi_get_instance(dip);
378 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
379 	volatile uint64_t uint64_data;
380 
381 	DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level);
382 	if (component != UPA64S_PM_COMP ||
383 	    level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP)
384 		return (DDI_FAILURE);
385 
386 	/*
387 	 * We can't set the hardware to the state that it is
388 	 * already in.  So if the power state is not known, inquire the
389 	 * state of the hardware.  If it is already in that state,
390 	 * record and return, otherwise make the state change.
391 	 */
392 	if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) {
393 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
394 		    upa64s_p->if_config);
395 		if ((level == UPA64S_PM_RESET &&
396 		    uint64_data == UPA64S_NOT_POK_RST_L) ||
397 		    (level == UPA64S_PM_NORMOP &&
398 		    uint64_data == UPA64S_POK_NOT_RST_L)) {
399 			upa64s_p->power_level = level;
400 			return (DDI_SUCCESS);
401 		}
402 	}
403 
404 	if (level == upa64s_p->power_level) {
405 		DBG1(D_POWER, dip, "device is already at power level %d\n",
406 		    level);
407 		return (DDI_SUCCESS);
408 	}
409 
410 
411 	if (level == UPA64S_PM_RESET) {
412 		/*
413 		 * Assert UPA64S_RESET
414 		 */
415 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
416 		    UPA64S_POK_RST_L);
417 
418 		/*
419 		 * Deassert UPA64S_POK.  Flush the store buffer.
420 		 */
421 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
422 		    UPA64S_NOT_POK_RST_L);
423 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
424 		    upa64s_p->if_config);
425 
426 		/*
427 		 * Internal UPA clock to 1/2 speed
428 		 */
429 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
430 		    UPA64S_1_2_SPEED);
431 
432 		/*
433 		 * Internal UPA clock to 1/64 speed.  Flush the store buffer.
434 		 */
435 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
436 		    UPA64S_1_64_SPEED);
437 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
438 		    upa64s_p->estar);
439 	} else {
440 		/*
441 		 * Internal UPA clock to 1/2 speed
442 		 */
443 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
444 		    UPA64S_1_2_SPEED);
445 
446 		/*
447 		 * Internal UPA clock to full speed.  Flush the store buffer.
448 		 */
449 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
450 		    UPA64S_FULL_SPEED);
451 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
452 		    upa64s_p->estar);
453 
454 		/*
455 		 * Assert UPA64S_POK.  Flush the store buffer before
456 		 * the wait delay.
457 		 */
458 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
459 		    UPA64S_POK_RST_L);
460 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
461 		    upa64s_p->if_config);
462 
463 		/*
464 		 * Delay 20 milliseconds for the signals to settle down.
465 		 */
466 		delay(drv_usectohz(20*1000));
467 
468 		/*
469 		 * Deassert UPA64S_RESET.  Flush the store buffer.
470 		 */
471 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
472 		    UPA64S_POK_NOT_RST_L);
473 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
474 		    upa64s_p->if_config);
475 	}
476 	upa64s_p->power_level = level;
477 
478 	return (DDI_SUCCESS);
479 }
480 
481 /* bus driver entry points */
482 
483 /*
484  * bus map entry point:
485  *
486  * 	if map request is for an rnumber
487  *		get the corresponding regspec from device node
488  * 	build a new regspec in our parent's format
489  *	build a new map_req with the new regspec
490  *	call up the tree to complete the mapping
491  */
492 static int
493 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
494     off_t off, off_t len, caddr_t *addrp)
495 {
496 	struct regspec regspec;
497 	ddi_map_req_t p_map_request;
498 	int rnumber, rval;
499 
500 	DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n",
501 	    HI32(mp), LO32(mp), HI32(addrp), LO32(addrp));
502 
503 	/*
504 	 * User level mappings are not supported yet.
505 	 */
506 	if (mp->map_flags & DDI_MF_USER_MAPPING) {
507 		DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n",
508 		    ddi_get_name(rdip), ddi_get_instance(rdip));
509 		return (DDI_ME_UNIMPLEMENTED);
510 	}
511 
512 	/*
513 	 * Now handle the mapping according to its type.
514 	 */
515 	switch (mp->map_type) {
516 	case DDI_MT_REGSPEC:
517 
518 		/*
519 		 * We assume the register specification is in PCI format.
520 		 * We must convert it into a regspec of our parent's
521 		 * and pass the request to our parent.
522 		 */
523 		DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n",
524 		    ddi_get_name(rdip), ddi_get_instance(rdip),
525 		    mp->map_handlep);
526 		rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp,
527 		    off, len, &regspec);
528 		break;
529 
530 	case DDI_MT_RNUMBER:
531 
532 		/*
533 		 * Get the "reg" property from the device node and convert
534 		 * it to our parent's format.
535 		 */
536 		DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n",
537 		    ddi_get_name(rdip), ddi_get_instance(rdip),
538 		    mp->map_obj.rnumber, mp->map_handlep);
539 		rnumber = mp->map_obj.rnumber;
540 		if (rnumber < 0)
541 			return (DDI_ME_RNUMBER_RANGE);
542 		rval = get_reg_set(dip, rdip,  rnumber, off, len, &regspec);
543 		break;
544 
545 	default:
546 		return (DDI_ME_INVAL);
547 
548 	}
549 	if (rval != DDI_SUCCESS) {
550 		DBG(D_MAP, dip, "failed on regspec\n\n");
551 		return (rval);
552 	}
553 
554 	/*
555 	 * Now we have a copy of the upa64s regspec converted to our parent's
556 	 * format.  Build a new map request based on this regspec and pass
557 	 * it to our parent.
558 	 */
559 	p_map_request = *mp;
560 	p_map_request.map_type = DDI_MT_REGSPEC;
561 	p_map_request.map_obj.rp = &regspec;
562 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
563 	DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n",
564 	    rval, HI32(*addrp), LO32(*addrp));
565 	return (rval);
566 }
567 
568 /*
569  * Translate the UPA devices interrupt property.  This is the only case I
570  * know of where the interrupts property is meaningless.  As a result, we
571  * just use UPA_BASE_INO as our interrupt value and add to it the upa port id.
572  * UPA portid is returned too.
573  */
574 #define	UPA_BASE_INO	0x2a
575 
576 static int
577 upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, ddi_ispec_t *ispecp)
578 {
579 	uint32_t ino = UPA_BASE_INO;
580 	int32_t portid;
581 
582 	/* Clear the ffb's interrupts property, it's meaningless */
583 	*ispecp->is_intr = 0;
584 
585 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
586 	    "upa-portid", -1)) == -1)
587 		return (-1);
588 
589 	ino += portid;
590 
591 	*ispecp->is_intr = UPA64S_MAKE_MONDO(safariport, ino);
592 
593 	DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d "
594 	    "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip),
595 	    portid, ino, *ispecp->is_intr);
596 
597 	return (portid);
598 }
599 
600 /*
601  * bus add intrspec entry point:
602  */
603 static int
604 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
605     ddi_intr_handle_impl_t *hdlp)
606 {
607 	int upaport, instance = ddi_get_instance(dip);
608 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
609 #ifdef DEBUG
610 	uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func;
611 	caddr_t int_handler_arg1 = hdlp->ih_cb_arg1;
612 #endif /* DEBUG */
613 	ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private;
614 	uint_t cpu_id;
615 	volatile uint64_t imr_data;
616 
617 	upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, ip);
618 
619 	if (*ip->is_intr == 0)
620 		return (DDI_FAILURE);
621 
622 	DBG3(D_A_ISPEC, dip,
623 	    "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
624 	    ddi_get_name(rdip), ddi_get_instance(rdip), *ip->is_intr);
625 
626 	/*
627 	 * Make sure an interrupt handler isn't already installed.
628 	 */
629 	if (upa64s_p->ino_state[upaport] != INO_FREE) {
630 		return (DDI_FAILURE);
631 	}
632 
633 	/*
634 	 * Install the handler in the system table.
635 	 */
636 #ifdef	DEBUG
637 	DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n",
638 	    int_handler, int_handler_arg1);
639 #endif
640 	hdlp->ih_vector = *ip->is_intr;
641 	if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS)
642 		return (DDI_FAILURE);
643 
644 	cpu_id = intr_dist_cpuid();
645 
646 	/*
647 	 * Enable the interrupt through its interrupt mapping register.
648 	 */
649 	imr_data = UPA64S_CPUID_TO_IMR(cpu_id);
650 	imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data);
651 
652 	DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n",
653 	    upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data));
654 
655 	ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data);
656 	/* Read the data back to flush store buffers. */
657 	imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
658 	upa64s_p->ino_state[upaport] = INO_INUSE;
659 
660 	DBG(D_A_ISPEC, dip, "add_intrspec success!\n");
661 	return (DDI_SUCCESS);
662 }
663 
664 
665 /*
666  * bus remove intrspec entry point
667  */
668 static int
669 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
670     ddi_intr_handle_impl_t *hdlp)
671 {
672 	upa64s_devstate_t *upa64s_p =
673 	    get_upa64s_soft_state(ddi_get_instance(dip));
674 	ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private;
675 	int upaport;
676 #ifndef lint
677 	volatile uint64_t tmp;
678 #endif
679 
680 	/*
681 	 * Make sure the mondo is valid.
682 	 */
683 	upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, ip);
684 
685 	if (*ip->is_intr == 0)
686 		return (DDI_FAILURE);
687 
688 	DBG3(D_R_ISPEC, dip,
689 	    "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
690 	    ddi_get_name(rdip), ddi_get_instance(rdip), *ip->is_intr);
691 
692 	if (upa64s_p->ino_state[upaport] != INO_INUSE) {
693 		return (DDI_FAILURE);
694 	}
695 
696 	/* Call up to our parent to handle the removal */
697 	hdlp->ih_vector = *ip->is_intr;
698 	i_ddi_rem_ivintr(hdlp);
699 
700 	ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0);
701 #ifndef lint
702 	/* Flush store buffers */
703 	tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
704 #endif
705 
706 	upa64s_p->ino_state[upaport] = INO_FREE;
707 	return (DDI_SUCCESS);
708 }
709 
710 
711 /* new intr_ops structure */
712 static int
713 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
714     ddi_intr_handle_impl_t *hdlp, void *result)
715 {
716 	ddi_ispec_t	*ip = (ddi_ispec_t *)hdlp->ih_private;
717 	int		ret = DDI_SUCCESS;
718 
719 	switch (intr_op) {
720 	case DDI_INTROP_GETCAP:
721 		*(int *)result = 0;
722 		break;
723 	case DDI_INTROP_ALLOC:
724 		*(int *)result = hdlp->ih_scratch1;
725 		break;
726 	case DDI_INTROP_FREE:
727 		break;
728 	case DDI_INTROP_GETPRI:
729 		/*
730 		 * We only have slave UPA devices so force the PIL to 5.
731 		 * this is done since all slave UPA devices have historically
732 		 * had their PILs set to 5.  Only do it if the PIL is not
733 		 * being preset.
734 		 */
735 		*(int *)result = ip->is_pil ? ip->is_pil : 5;
736 		break;
737 	case DDI_INTROP_SETPRI:
738 		ip->is_pil = (*(int *)result);
739 		break;
740 	case DDI_INTROP_ADDISR:
741 		hdlp->ih_vector = *ip->is_intr;
742 
743 		ret = upa64s_add_intr_impl(dip, rdip, hdlp);
744 		break;
745 	case DDI_INTROP_REMISR:
746 		hdlp->ih_vector = *ip->is_intr;
747 
748 		ret = upa64s_remove_intr_impl(dip, rdip, hdlp);
749 		break;
750 	case DDI_INTROP_ENABLE:
751 	case DDI_INTROP_DISABLE:
752 		break;
753 	case DDI_INTROP_NINTRS:
754 	case DDI_INTROP_NAVAIL:
755 		*(int *)result = i_ddi_get_nintrs(rdip);
756 		break;
757 	case DDI_INTROP_SETCAP:
758 	case DDI_INTROP_SETMASK:
759 	case DDI_INTROP_CLRMASK:
760 	case DDI_INTROP_GETPENDING:
761 		ret = DDI_ENOTSUP;
762 		break;
763 	case DDI_INTROP_SUPPORTED_TYPES:
764 		/* only support fixed interrupts */
765 		*(int *)result = i_ddi_get_nintrs(rdip) ?
766 		    DDI_INTR_TYPE_FIXED : 0;
767 		break;
768 	default:
769 		ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
770 		break;
771 	}
772 
773 	return (ret);
774 }
775 
776 #ifdef DEBUG
777 uint_t upa64s_debug_flags = (uint_t)0;
778 
779 extern void prom_printf(const char *, ...);
780 #endif
781 
782 /*
783  * control ops entry point:
784  *
785  * Requests handled completely:
786  *	DDI_CTLOPS_INITCHILD	see init_child() for details
787  *	DDI_CTLOPS_UNINITCHILD
788  *	DDI_CTLOPS_REPORTDEV	see report_dev() for details
789  *	DDI_CTLOPS_XLATE_INTRS	nothing to do
790  *	DDI_CTLOPS_REGSIZE
791  *	DDI_CTLOPS_NREGS
792  *	DDI_CTLOPS_NINTRS
793  *
794  * All others passed to parent.
795  */
796 static int
797 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
798     ddi_ctl_enum_t op, void *arg, void *result)
799 {
800 	DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x",
801 	    HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op);
802 	DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n",
803 	    HI32(arg), LO32(arg), HI32(result), LO32(result));
804 
805 	switch (op) {
806 	case DDI_CTLOPS_INITCHILD:
807 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
808 		    ddi_get_name(rdip), ddi_get_instance(rdip));
809 		return (init_child((dev_info_t *)arg));
810 
811 	case DDI_CTLOPS_UNINITCHILD:
812 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
813 		    ddi_get_name(rdip), ddi_get_instance(rdip));
814 		ddi_set_name_addr((dev_info_t *)arg, NULL);
815 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
816 		impl_rem_dev_props((dev_info_t *)arg);
817 		return (DDI_SUCCESS);
818 
819 	case DDI_CTLOPS_REPORTDEV:
820 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
821 		    ddi_get_name(rdip), ddi_get_instance(rdip));
822 		return (report_dev(rdip));
823 
824 	case DDI_CTLOPS_XLATE_INTRS:
825 		return (DDI_FAILURE);
826 
827 	case DDI_CTLOPS_REGSIZE:
828 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
829 		    ddi_get_name(rdip), ddi_get_instance(rdip));
830 		*((off_t *)result) = get_reg_set_size(rdip, *((int *)arg));
831 		return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS);
832 
833 	case DDI_CTLOPS_NREGS:
834 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
835 		    ddi_get_name(rdip), ddi_get_instance(rdip));
836 		*((uint_t *)result) = get_nreg_set(rdip);
837 		return (DDI_SUCCESS);
838 
839 	case DDI_CTLOPS_NINTRS:
840 		return (DDI_FAILURE);
841 	}
842 
843 	/*
844 	 * Now pass the request up to our parent.
845 	 */
846 	DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n",
847 	    ddi_get_name(rdip), ddi_get_instance(rdip), op);
848 	return (ddi_ctlops(dip, rdip, op, arg, result));
849 }
850 
851 
852 /* support routines */
853 
854 /*
855  * get_properties
856  *
857  * This function is called from the attach routine to get the key
858  * properties of the upa64s node.
859  *
860  * used by: upa64s_attach()
861  *
862  * return value: none
863  */
864 static int
865 get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip)
866 {
867 	int safari_id;
868 
869 	/*
870 	 * Get the device's safari id.
871 	 */
872 	safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
873 	    "portid", -1);
874 	if (safari_id == -1) {
875 		int instance = ddi_get_instance(dip);
876 		panic("%s%d: no portid property", ddi_get_name(dip), instance);
877 	}
878 	upa64s_p->safari_id = safari_id;
879 
880 	return (DDI_SUCCESS);
881 }
882 
883 
884 /*
885  * save_state
886  *
887  * This routine saves a copy of the upa64s register state.
888  *
889  * used by: upa64s_detach() on a suspend operation
890  */
891 static void
892 save_state(upa64s_devstate_t *upa64s_p)
893 {
894 	upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0],
895 	    upa64s_p->imr[0]);
896 	upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1],
897 	    upa64s_p->imr[1]);
898 }
899 
900 
901 /*
902  * restore_state
903  *
904  * This routine restores a copy of the upa64s register state.
905  *
906  * used by: upa64s_attach() on a resume operation
907  */
908 static void
909 restore_state(upa64s_devstate_t *upa64s_p)
910 {
911 #ifndef lint
912 	volatile uint64_t tmp;
913 #endif
914 	ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0],
915 	    upa64s_p->imr_data[0]);
916 	ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1],
917 	    upa64s_p->imr_data[1]);
918 #ifndef lint
919 	/* Flush the store buffer */
920 	tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]);
921 	tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]);
922 #endif
923 }
924 
925 
926 /*
927  * get_reg_set
928  *
929  * This routine will get a upa64s format regspec for a given
930  * device node and register number.
931  *
932  * used by: upa64s_map()
933  *
934  * return value:
935  *
936  *	DDI_SUCCESS		- on success
937  *	DDI_ME_INVAL		- regspec is invalid
938  *	DDI_ME_RNUMBER_RANGE	- rnumber out of range
939  */
940 static int
941 get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
942     off_t off, off_t len, struct regspec *rp)
943 {
944 	upa64s_regspec_t *upa64s_rp;
945 	int i, n, rval;
946 
947 	/*
948 	 * Get child device "reg" property
949 	 */
950 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
951 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
952 		return (DDI_ME_RNUMBER_RANGE);
953 
954 	n = i / (int)sizeof (upa64s_regspec_t);
955 	if (rnumber >= n) {
956 		kmem_free(upa64s_rp, i);
957 		return (DDI_ME_RNUMBER_RANGE);
958 	}
959 
960 	/*
961 	 * Convert each the upa64s format register specification to
962 	 * out parent format.
963 	 */
964 	rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp);
965 	kmem_free(upa64s_rp, i);
966 	return (rval);
967 }
968 
969 
970 /*
971  * xlate_reg_prop
972  *
973  * This routine converts a upa64s format regspec to a standard
974  * regspec containing the corresponding system address.
975  *
976  * used by: upa64s_map()
977  *
978  * return value:
979  *
980  *	DDI_SUCCESS
981  *	DDI_FAILURE	- off + len is beyond device address range
982  *	DDI_ME_INVAL	- regspec is invalid
983  */
984 static int
985 xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off,
986     off_t len, struct regspec *rp)
987 {
988 	int n_ranges, ranges_len, i;
989 	uint64_t child_beg, child_end;
990 	upa64s_ranges_t *range_p, *rng_p;
991 
992 	DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n",
993 	    HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys),
994 	    HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size));
995 	DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len);
996 #if 0
997 	/*
998 	 * both FFB and AFB have broken "reg" properties, all mapping
999 	 * requests are done through reg-0 with very long offsets.
1000 	 * Hence this safety check is always violated.
1001 	 */
1002 	if (off + len > child_rp->upa64s_size) {
1003 		DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n");
1004 		return (DDI_FAILURE);
1005 	}
1006 #endif
1007 	/*
1008 	 * current "struct regspec" only supports 32-bit sizes.
1009 	 */
1010 	if (child_rp->upa64s_size >= (1ull << 32))
1011 		panic("upa64s: reg size must be less than 4 Gb");
1012 
1013 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1014 	    "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) {
1015 		ranges_len = 0;
1016 		cmn_err(CE_WARN, "%s%d: no ranges property",
1017 		    ddi_get_name(dip), ddi_get_instance(dip));
1018 	}
1019 
1020 	n_ranges = ranges_len / sizeof (upa64s_regspec_t);
1021 	child_beg = child_rp->upa64s_phys;
1022 #if 0
1023 	/*
1024 	 * again, this safety checking can not be performed.
1025 	 * Hack by adding a pratical max child reg bank length.
1026 	 */
1027 	child_end = child_beg + child_rp->upa64s_size;
1028 #else
1029 #define	UPA64S_MAX_CHILD_LEN	0xe000000
1030 	child_end = child_beg + UPA64S_MAX_CHILD_LEN;
1031 #endif
1032 	for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) {
1033 		uint64_t rng_beg = rng_p->upa64s_child;
1034 		uint64_t rng_end = rng_beg + rng_p->upa64s_size;
1035 		if ((rng_beg <= child_beg) && (rng_end >= child_end)) {
1036 			uint64_t addr = child_beg - rng_beg + off;
1037 			addr += rng_p->upa64s_parent;
1038 			rp->regspec_bustype = HI32(addr);
1039 			rp->regspec_addr = LO32(addr);
1040 			rp->regspec_size = len ? len : child_rp->upa64s_size;
1041 			break;
1042 		}
1043 	}
1044 	if (ranges_len)
1045 		kmem_free(range_p, ranges_len);
1046 	DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n",
1047 	    rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i);
1048 	return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL);
1049 }
1050 
1051 
1052 /*
1053  * report_dev
1054  *
1055  * This function is called from our control ops routine on a
1056  * DDI_CTLOPS_REPORTDEV request.
1057  */
1058 static int
1059 report_dev(dev_info_t *dip)
1060 {
1061 	if (dip == (dev_info_t *)0)
1062 		return (DDI_FAILURE);
1063 	cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n",
1064 	    ddi_node_name(dip), ddi_get_name_addr(dip),
1065 	    ddi_major_to_name(ddi_name_to_major(ddi_get_name(dip))),
1066 	    ddi_get_instance(dip));
1067 	return (DDI_SUCCESS);
1068 }
1069 
1070 
1071 /*
1072  * init_child
1073  *
1074  * This function is called from our control ops routine on a
1075  * DDI_CTLOPS_INITCHILD request.  It builds and sets the device's
1076  * parent private data area.
1077  *
1078  * used by: upa64s_ctlops()
1079  *
1080  * return value: none
1081  */
1082 static int
1083 init_child(dev_info_t *child)
1084 {
1085 	upa64s_regspec_t *child_rp;
1086 	int i;
1087 	char addr[256];
1088 	int32_t portid;
1089 
1090 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1091 	    "upa-portid", -1)) == -1)
1092 		return (DDI_FAILURE);
1093 
1094 	/*
1095 	 * Set the address portion of the node name based on
1096 	 * the function and device number.
1097 	 */
1098 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1099 	    (caddr_t)&child_rp, &i) != DDI_SUCCESS) {
1100 		return (DDI_FAILURE);
1101 	}
1102 
1103 	(void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys));
1104 	ddi_set_name_addr(child, addr);
1105 
1106 	ddi_set_parent_data(child, NULL);
1107 	kmem_free(child_rp, i);
1108 	return (DDI_SUCCESS);
1109 }
1110 
1111 
1112 /*
1113  * get_reg_set_size
1114  *
1115  * Given a dev info pointer to a child and a register number, this
1116  * routine returns the size element of that reg set property.
1117  *
1118  * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE
1119  *
1120  * return value: size of reg set on success, -1 on error
1121  */
1122 static off_t
1123 get_reg_set_size(dev_info_t *child, int rnumber)
1124 {
1125 	upa64s_regspec_t *upa64s_rp;
1126 	uint_t size;
1127 	int i;
1128 
1129 	if (rnumber < 0)
1130 		return (-1);
1131 
1132 	/*
1133 	 * Get the reg property for the device.
1134 	 */
1135 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1136 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1137 		return (-1);
1138 
1139 	if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) {
1140 		kmem_free(upa64s_rp, i);
1141 		return (-1);
1142 	}
1143 
1144 	/*  >4G reg size not supported */
1145 	size = (uint32_t)upa64s_rp[rnumber].upa64s_size;
1146 	kmem_free(upa64s_rp, i);
1147 	return (size);
1148 }
1149 
1150 
1151 /*
1152  * get_nreg_set
1153  *
1154  * Given a dev info pointer to a child, this routine returns the
1155  * number of sets in its "reg" property.
1156  *
1157  * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS
1158  *
1159  * return value: # of reg sets on success, zero on error
1160  */
1161 static uint_t
1162 get_nreg_set(dev_info_t *child)
1163 {
1164 	upa64s_regspec_t *upa64s_rp;
1165 	int i, n;
1166 
1167 	/*
1168 	 * Get the reg property for the device.
1169 	 */
1170 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1171 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1172 		return (0);
1173 
1174 	n =  i / (int)sizeof (upa64s_regspec_t);
1175 	kmem_free(upa64s_rp, i);
1176 	return (n);
1177 }
1178 
1179 
1180 /*
1181  * upa64s_intrdist
1182  *
1183  * The following routine is the callback function for this nexus driver
1184  * to support interrupt distribution on sun4u systems. When this
1185  * function is called by the interrupt distribution framework, it will
1186  * reprogram all the active the mondo registers.
1187  */
1188 static void
1189 upa64s_intrdist(void *arg)
1190 {
1191 	dev_info_t *dip = (dev_info_t *)arg;
1192 	int instance = ddi_get_instance(dip);
1193 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
1194 	uint_t upaport;
1195 
1196 	for (upaport = 0; upaport < UPA64S_PORTS; upaport++) {
1197 		volatile uint64_t *imr;
1198 		volatile uint64_t imr_dat;
1199 		uint_t mondo;
1200 		uint32_t cpuid;
1201 
1202 		if (upa64s_p->ino_state[upaport] != INO_INUSE)
1203 			continue;
1204 
1205 		imr = upa64s_p->imr[upaport];
1206 		mondo = UPA64S_IMR_TO_MONDO(*imr);
1207 		cpuid = intr_dist_cpuid();
1208 		imr_dat = UPA64S_CPUID_TO_IMR(cpuid);
1209 		imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat);
1210 
1211 		/* Check and re-program cpu target if necessary */
1212 		DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid);
1213 		if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) {
1214 			DBG(D_INTRDIST, dip, "same cpuid\n");
1215 			continue;
1216 		}
1217 		ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat);
1218 		imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr);
1219 	}
1220 }
1221 
1222 
1223 #ifdef DEBUG
1224 static void
1225 upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt,
1226     uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1227 {
1228 	char *s = NULL;
1229 	uint_t cont = 0;
1230 	if (flag & D_CONT) {
1231 		flag &= ~D_CONT;
1232 		cont = 1;
1233 	}
1234 	if (!(upa64s_debug_flags & flag))
1235 		return;
1236 
1237 	switch (flag) {
1238 	case D_ATTACH:		s = "attach";		break;
1239 	case D_DETACH:		s = "detach";		break;
1240 	case D_POWER:		s = "power";		break;
1241 	case D_MAP:		s = "map";		break;
1242 	case D_CTLOPS:		s = "ctlops";		break;
1243 	case D_G_ISPEC:		s = "get_intrspec";	break;
1244 	case D_A_ISPEC:		s = "add_intrspec";	break;
1245 	case D_R_ISPEC:		s = "remove_intrspec";	break;
1246 	case D_INIT_CLD:	s = "init_child";	break;
1247 	case D_INTRDIST:	s = "intrdist";		break;
1248 	}
1249 
1250 	if (s && cont == 0) {
1251 		prom_printf("%s(%d): %s: ", ddi_get_name(dip),
1252 		    ddi_get_instance(dip), s);
1253 	}
1254 	prom_printf(fmt, a1, a2, a3, a4, a5);
1255 }
1256 #endif
1257