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