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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27#include <sys/types.h>
28#include <sys/conf.h>
29#include <sys/ddi.h>
30#include <sys/sunddi.h>
31#include <sys/sunndi.h>
32#include <sys/ddi_impldefs.h>
33#include <sys/ddi_implfuncs.h>
34#include <sys/obpdefs.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/autoconf.h>
41#include <sys/spl.h>
42#include <sys/iommu.h>
43#include <sys/sysiosbus.h>
44#include <sys/sysioerr.h>
45#include <sys/iocache.h>
46#include <sys/async.h>
47#include <sys/machsystm.h>
48#include <sys/intreg.h>
49#include <sys/ddi_subrdefs.h>
50#ifdef _STARFIRE
51#include <sys/starfire.h>
52#endif /* _STARFIRE */
53#include <sys/sdt.h>
54
55/* Useful debugging Stuff */
56#include <sys/nexusdebug.h>
57/* Bitfield debugging definitions for this file */
58#define	SBUS_ATTACH_DEBUG	0x1
59#define	SBUS_SBUSMEM_DEBUG	0x2
60#define	SBUS_INTERRUPT_DEBUG	0x4
61#define	SBUS_REGISTERS_DEBUG	0x8
62
63/*
64 * Interrupt registers table.
65 * This table is necessary due to inconsistencies in the sysio register
66 * layout.  If this gets fixed in the chip, we can get rid of this stupid
67 * table.
68 */
69static struct sbus_slot_entry ino_1 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
70					SBUS_SLOT0_L1_CLEAR, NULL};
71static struct sbus_slot_entry ino_2 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
72					SBUS_SLOT0_L2_CLEAR, NULL};
73static struct sbus_slot_entry ino_3 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
74					SBUS_SLOT0_L3_CLEAR, NULL};
75static struct sbus_slot_entry ino_4 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
76					SBUS_SLOT0_L4_CLEAR, NULL};
77static struct sbus_slot_entry ino_5 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
78					SBUS_SLOT0_L5_CLEAR, NULL};
79static struct sbus_slot_entry ino_6 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
80					SBUS_SLOT0_L6_CLEAR, NULL};
81static struct sbus_slot_entry ino_7 = {SBUS_SLOT0_CONFIG, SBUS_SLOT0_MAPREG,
82					SBUS_SLOT0_L7_CLEAR, NULL};
83static struct sbus_slot_entry ino_9 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
84					SBUS_SLOT1_L1_CLEAR, NULL};
85static struct sbus_slot_entry ino_10 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
86					SBUS_SLOT1_L2_CLEAR, NULL};
87static struct sbus_slot_entry ino_11 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
88					SBUS_SLOT1_L3_CLEAR, NULL};
89static struct sbus_slot_entry ino_12 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
90					SBUS_SLOT1_L4_CLEAR, NULL};
91static struct sbus_slot_entry ino_13 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
92					SBUS_SLOT1_L5_CLEAR, NULL};
93static struct sbus_slot_entry ino_14 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
94					SBUS_SLOT1_L6_CLEAR, NULL};
95static struct sbus_slot_entry ino_15 = {SBUS_SLOT1_CONFIG, SBUS_SLOT1_MAPREG,
96					SBUS_SLOT1_L7_CLEAR, NULL};
97static struct sbus_slot_entry ino_17 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
98					SBUS_SLOT2_L1_CLEAR, NULL};
99static struct sbus_slot_entry ino_18 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
100					SBUS_SLOT2_L2_CLEAR, NULL};
101static struct sbus_slot_entry ino_19 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
102					SBUS_SLOT2_L3_CLEAR, NULL};
103static struct sbus_slot_entry ino_20 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
104					SBUS_SLOT2_L4_CLEAR, NULL};
105static struct sbus_slot_entry ino_21 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
106					SBUS_SLOT2_L5_CLEAR, NULL};
107static struct sbus_slot_entry ino_22 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
108					SBUS_SLOT2_L6_CLEAR, NULL};
109static struct sbus_slot_entry ino_23 = {SBUS_SLOT2_CONFIG, SBUS_SLOT2_MAPREG,
110					SBUS_SLOT2_L7_CLEAR, NULL};
111static struct sbus_slot_entry ino_25 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
112					SBUS_SLOT3_L1_CLEAR, NULL};
113static struct sbus_slot_entry ino_26 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
114					SBUS_SLOT3_L2_CLEAR, NULL};
115static struct sbus_slot_entry ino_27 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
116					SBUS_SLOT3_L3_CLEAR, NULL};
117static struct sbus_slot_entry ino_28 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
118					SBUS_SLOT3_L4_CLEAR, NULL};
119static struct sbus_slot_entry ino_29 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
120					SBUS_SLOT3_L5_CLEAR, NULL};
121static struct sbus_slot_entry ino_30 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
122					SBUS_SLOT3_L6_CLEAR, NULL};
123static struct sbus_slot_entry ino_31 = {SBUS_SLOT3_CONFIG, SBUS_SLOT3_MAPREG,
124					SBUS_SLOT3_L7_CLEAR, NULL};
125static struct sbus_slot_entry ino_32 = {SBUS_SLOT5_CONFIG, ESP_MAPREG,
126					ESP_CLEAR, ESP_INTR_STATE_SHIFT};
127static struct sbus_slot_entry ino_33 = {SBUS_SLOT5_CONFIG, ETHER_MAPREG,
128					ETHER_CLEAR, ETHER_INTR_STATE_SHIFT};
129static struct sbus_slot_entry ino_34 = {SBUS_SLOT5_CONFIG, PP_MAPREG,
130					PP_CLEAR, PP_INTR_STATE_SHIFT};
131static struct sbus_slot_entry ino_36 = {SBUS_SLOT4_CONFIG, AUDIO_MAPREG,
132					AUDIO_CLEAR, AUDIO_INTR_STATE_SHIFT};
133static struct sbus_slot_entry ino_40 = {SBUS_SLOT6_CONFIG, KBDMOUSE_MAPREG,
134					KBDMOUSE_CLEAR,
135					KBDMOUSE_INTR_STATE_SHIFT};
136static struct sbus_slot_entry ino_41 = {SBUS_SLOT6_CONFIG, FLOPPY_MAPREG,
137					FLOPPY_CLEAR, FLOPPY_INTR_STATE_SHIFT};
138static struct sbus_slot_entry ino_42 = {SBUS_SLOT6_CONFIG, THERMAL_MAPREG,
139					THERMAL_CLEAR,
140					THERMAL_INTR_STATE_SHIFT};
141static struct sbus_slot_entry ino_48 = {SBUS_SLOT6_CONFIG, TIMER0_MAPREG,
142					TIMER0_CLEAR, TIMER0_INTR_STATE_SHIFT};
143static struct sbus_slot_entry ino_49 = {SBUS_SLOT6_CONFIG, TIMER1_MAPREG,
144					TIMER1_CLEAR, TIMER1_INTR_STATE_SHIFT};
145static struct sbus_slot_entry ino_52 = {SBUS_SLOT6_CONFIG, UE_ECC_MAPREG,
146					UE_ECC_CLEAR, UE_INTR_STATE_SHIFT};
147static struct sbus_slot_entry ino_53 = {SBUS_SLOT6_CONFIG, CE_ECC_MAPREG,
148					CE_ECC_CLEAR, CE_INTR_STATE_SHIFT};
149static struct sbus_slot_entry ino_54 = {SBUS_SLOT6_CONFIG, SBUS_ERR_MAPREG,
150					SBUS_ERR_CLEAR, SERR_INTR_STATE_SHIFT};
151static struct sbus_slot_entry ino_55 = {SBUS_SLOT6_CONFIG, PM_WAKEUP_MAPREG,
152					PM_WAKEUP_CLEAR, PM_INTR_STATE_SHIFT};
153static struct sbus_slot_entry ino_ffb = {NULL, FFB_MAPPING_REG, NULL, NULL};
154static struct sbus_slot_entry ino_exp = {NULL, EXP_MAPPING_REG, NULL, NULL};
155
156/* Construct the interrupt number array */
157struct sbus_slot_entry *ino_table[] = {
158	NULL, &ino_1, &ino_2, &ino_3, &ino_4, &ino_5, &ino_6, &ino_7,
159	NULL, &ino_9, &ino_10, &ino_11, &ino_12, &ino_13, &ino_14, &ino_15,
160	NULL, &ino_17, &ino_18, &ino_19, &ino_20, &ino_21, &ino_22, &ino_23,
161	NULL, &ino_25, &ino_26, &ino_27, &ino_28, &ino_29, &ino_30, &ino_31,
162	&ino_32, &ino_33, &ino_34, NULL, &ino_36, NULL, NULL, NULL,
163	&ino_40, &ino_41, &ino_42, NULL, NULL, NULL, NULL, NULL, &ino_48,
164	&ino_49, NULL, NULL, &ino_52, &ino_53, &ino_54, &ino_55, &ino_ffb,
165	&ino_exp
166};
167
168/*
169 * This table represents the Fusion interrupt priorities.  They range
170 * from 1 - 15, so we'll pattern the priorities after the 4M.  We map Fusion
171 * interrupt number to system priority.  The mondo number is used as an
172 * index into this table.
173 */
174int interrupt_priorities[] = {
175	-1, 2, 3, 5, 7, 9, 11, 13,	/* Slot 0 sbus level 1 - 7 */
176	-1, 2, 3, 5, 7, 9, 11, 13,	/* Slot 1 sbus level 1 - 7 */
177	-1, 2, 3, 5, 7, 9, 11, 13,	/* Slot 2 sbus level 1 - 7 */
178	-1, 2, 3, 5, 7, 9, 11, 13,	/* Slot 3 sbus level 1 - 7 */
179	4,				/* Onboard SCSI */
180	6,				/* Onboard Ethernet */
181	3,				/* Onboard Parallel port */
182	-1,				/* Not in use */
183	9,				/* Onboard Audio */
184	-1, -1, -1,			/* Not in use */
185	12,				/* Onboard keyboard/serial ports */
186	11,				/* Onboard Floppy */
187	9,				/* Thermal interrupt */
188	-1, -1, -1,			/* Not is use */
189	10,				/* Timer 0 (tick timer) */
190	14,				/* Timer 1 (not used) */
191	15,				/* Sysio UE ECC error */
192	10,				/* Sysio CE ECC error */
193	10,				/* Sysio Sbus error */
194	10,				/* PM Wakeup */
195};
196
197/* Interrupt counter flag.  To enable/disable spurious interrupt counter. */
198static int intr_cntr_on;
199
200/*
201 * Function prototypes.
202 */
203static int
204sbus_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
205
206static int
207sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
208    ddi_intr_handle_impl_t *hdlp);
209
210static void
211sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
212    ddi_intr_handle_impl_t *hdlp);
213
214static int
215sbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
216    ddi_intr_handle_impl_t *hdlp, void *result);
217
218static int
219sbus_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, uint32_t *intr,
220    uint32_t *pil, int32_t ign);
221
222static int
223sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
224
225static int
226sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
227
228static int
229sbus_do_detach(dev_info_t *devi);
230
231static	void
232sbus_add_picN_kstats(dev_info_t *dip);
233
234static	void
235sbus_add_kstats(struct sbus_soft_state *);
236
237static	int
238sbus_counters_kstat_update(kstat_t *, int);
239
240extern int
241sysio_err_uninit(struct sbus_soft_state *softsp);
242
243extern int
244iommu_uninit(struct sbus_soft_state *softsp);
245
246extern int
247stream_buf_uninit(struct sbus_soft_state *softsp);
248
249static int
250find_sbus_slot(dev_info_t *dip, dev_info_t *rdip);
251
252static void make_sbus_ppd(dev_info_t *child);
253
254static int
255sbusmem_initchild(dev_info_t *dip, dev_info_t *child);
256
257static int
258sbus_initchild(dev_info_t *dip, dev_info_t *child);
259
260static int
261sbus_uninitchild(dev_info_t *dip);
262
263static int
264sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args);
265
266static int
267sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args,
268    void *result);
269
270static int
271sbus_init(struct sbus_soft_state *softsp, caddr_t address);
272
273static int
274sbus_resume_init(struct sbus_soft_state *softsp, int resume);
275
276static void
277sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr,
278    int flag);
279
280static void sbus_intrdist(void *);
281static uint_t sbus_intr_reset(void *);
282
283static int
284sbus_update_intr_state(dev_info_t *dip, dev_info_t *rdip,
285    ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state);
286
287#ifdef	_STARFIRE
288void
289pc_ittrans_init(int, caddr_t *);
290
291void
292pc_ittrans_uninit(caddr_t);
293
294int
295pc_translate_tgtid(caddr_t, int, volatile uint64_t *);
296
297void
298pc_ittrans_cleanup(caddr_t, volatile uint64_t *);
299#endif	/* _STARFIRE */
300
301/*
302 * Configuration data structures
303 */
304static struct bus_ops sbus_bus_ops = {
305	BUSO_REV,
306	i_ddi_bus_map,
307	0,
308	0,
309	0,
310	i_ddi_map_fault,
311	iommu_dma_map,
312	iommu_dma_allochdl,
313	iommu_dma_freehdl,
314	iommu_dma_bindhdl,
315	iommu_dma_unbindhdl,
316	iommu_dma_flush,
317	iommu_dma_win,
318	iommu_dma_mctl,
319	sbus_ctlops,
320	ddi_bus_prop_op,
321	0,			/* (*bus_get_eventcookie)();	*/
322	0,			/* (*bus_add_eventcall)();	*/
323	0,			/* (*bus_remove_eventcall)();	*/
324	0,			/* (*bus_post_event)();		*/
325	0,			/* (*bus_intr_control)();	*/
326	0,			/* (*bus_config)();		*/
327	0,			/* (*bus_unconfig)();		*/
328	0,			/* (*bus_fm_init)();		*/
329	0,			/* (*bus_fm_fini)();		*/
330	0,			/* (*bus_fm_access_enter)();	*/
331	0,			/* (*bus_fm_access_exit)();	*/
332	0,			/* (*bus_power)();		*/
333	sbus_intr_ops		/* (*bus_intr_op)();		*/
334};
335
336static struct cb_ops sbus_cb_ops = {
337	nodev,			/* open */
338	nodev,			/* close */
339	nodev,			/* strategy */
340	nodev,			/* print */
341	nodev,			/* dump */
342	nodev,			/* read */
343	nodev,			/* write */
344	nodev,			/* ioctl */
345	nodev,			/* devmap */
346	nodev,			/* mmap */
347	nodev,			/* segmap */
348	nochpoll,		/* poll */
349	ddi_prop_op,		/* prop_op */
350	NULL,
351	D_NEW | D_MP | D_HOTPLUG,
352	CB_REV,				/* rev */
353	nodev,				/* int (*cb_aread)() */
354	nodev				/* int (*cb_awrite)() */
355};
356
357static struct dev_ops sbus_ops = {
358	DEVO_REV,		/* devo_rev, */
359	0,			/* refcnt  */
360	ddi_no_info,		/* info */
361	nulldev,		/* identify */
362	nulldev,		/* probe */
363	sbus_attach,		/* attach */
364	sbus_detach,		/* detach */
365	nodev,			/* reset */
366	&sbus_cb_ops,		/* driver operations */
367	&sbus_bus_ops,		/* bus operations */
368	nulldev,		/* power */
369	ddi_quiesce_not_supported,	/* devo_quiesce */
370};
371
372/* global data */
373void *sbusp;		/* sbus soft state hook */
374void *sbus_cprp;	/* subs suspend/resume soft state hook */
375static kstat_t *sbus_picN_ksp[SBUS_NUM_PICS]; /* performance picN kstats */
376static int	sbus_attachcnt = 0;   /* number of instances attached */
377static kmutex_t	sbus_attachcnt_mutex; /* sbus_attachcnt lock - attach/detach */
378
379#include <sys/modctl.h>
380extern struct mod_ops mod_driverops;
381
382static struct modldrv modldrv = {
383	&mod_driverops, 	/* Type of module.  This one is a driver */
384	"SBus (sysio) nexus driver",	/* Name of module. */
385	&sbus_ops,		/* driver ops */
386};
387
388static struct modlinkage modlinkage = {
389	MODREV_1, (void *)&modldrv, NULL
390};
391
392/*
393 * These are the module initialization routines.
394 */
395int
396_init(void)
397{
398	int error;
399
400	if ((error = ddi_soft_state_init(&sbusp,
401	    sizeof (struct sbus_soft_state), 1)) != 0)
402		return (error);
403
404	/*
405	 * Initialize cpr soft state structure
406	 */
407	if ((error = ddi_soft_state_init(&sbus_cprp,
408	    sizeof (uint64_t) * MAX_INO_TABLE_SIZE, 0)) != 0)
409		return (error);
410
411	/* Initialize global mutex */
412	mutex_init(&sbus_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
413
414	return (mod_install(&modlinkage));
415}
416
417int
418_fini(void)
419{
420	int error;
421
422	if ((error = mod_remove(&modlinkage)) != 0)
423		return (error);
424
425	mutex_destroy(&sbus_attachcnt_mutex);
426	ddi_soft_state_fini(&sbusp);
427	ddi_soft_state_fini(&sbus_cprp);
428	return (0);
429}
430
431int
432_info(struct modinfo *modinfop)
433{
434	return (mod_info(&modlinkage, modinfop));
435}
436
437/*ARGSUSED*/
438static int
439sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
440{
441	struct sbus_soft_state *softsp;
442	int instance, error;
443	uint64_t *cpr_softsp;
444	ddi_device_acc_attr_t attr;
445
446
447#ifdef	DEBUG
448	debug_info = 1;
449	debug_print_level = 0;
450#endif
451
452	instance = ddi_get_instance(devi);
453
454	switch (cmd) {
455	case DDI_ATTACH:
456		break;
457
458	case DDI_RESUME:
459		softsp = ddi_get_soft_state(sbusp, instance);
460
461		if ((error = iommu_resume_init(softsp)) != DDI_SUCCESS)
462			return (error);
463
464		if ((error = sbus_resume_init(softsp, 1)) != DDI_SUCCESS)
465			return (error);
466
467		if ((error = stream_buf_resume_init(softsp)) != DDI_SUCCESS)
468			return (error);
469
470		/*
471		 * Restore Interrupt Mapping registers
472		 */
473		cpr_softsp = ddi_get_soft_state(sbus_cprp, instance);
474
475		if (cpr_softsp != NULL) {
476			sbus_cpr_handle_intr_map_reg(cpr_softsp,
477			    softsp->intr_mapping_reg, 0);
478			ddi_soft_state_free(sbus_cprp, instance);
479		}
480
481		return (DDI_SUCCESS);
482
483	default:
484		return (DDI_FAILURE);
485	}
486
487	if (ddi_soft_state_zalloc(sbusp, instance) != DDI_SUCCESS)
488		return (DDI_FAILURE);
489
490	softsp = ddi_get_soft_state(sbusp, instance);
491
492	/* Set the dip in the soft state */
493	softsp->dip = devi;
494
495	if ((softsp->upa_id = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
496	    DDI_PROP_DONTPASS, "upa-portid", -1)) == -1) {
497		cmn_err(CE_WARN, "Unable to retrieve sbus upa-portid"
498		    "property.");
499		error = DDI_FAILURE;
500		goto bad;
501	}
502
503	/*
504	 * The firmware maps in all 3 pages of the sysio chips device
505	 * device registers and exports the mapping in the int-sized
506	 * property "address".  Read in this address and pass it to
507	 * the subsidiary *_init functions, so we don't create extra
508	 * mappings to the same physical pages and we don't have to
509	 * retrieve the more than once.
510	 */
511	/*
512	 * Implement new policy to start ignoring the "address" property
513	 * due to new requirements from DR.  The problem is that the contents
514	 * of the "address" property contain vm mappings from OBP which needs
515	 * to be recaptured into kernel vm.  Instead of relying on a blanket
516	 * recapture during boot time, we map psycho registers each time during
517	 * attach and unmap the during detach.  In some future point of time
518	 * OBP will drop creating "address" property but this driver will
519	 * will already not rely on this property any more.
520	 */
521
522	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
523	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
524	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
525	if (ddi_regs_map_setup(softsp->dip, 0, &softsp->address, 0, 0,
526	    &attr, &softsp->ac) != DDI_SUCCESS) {
527		cmn_err(CE_WARN, "%s%d: unable to map reg set 0\n",
528		    ddi_get_name(softsp->dip),
529		    ddi_get_instance(softsp->dip));
530		return (0);
531	}
532	if (softsp->address == (caddr_t)-1) {
533		cmn_err(CE_CONT, "?sbus%d: No sysio <address> property\n",
534		    ddi_get_instance(softsp->dip));
535		return (DDI_FAILURE);
536	}
537
538	DPRINTF(SBUS_ATTACH_DEBUG, ("sbus: devi=0x%p, softsp=0x%p\n",
539	    (void *)devi, (void *)softsp));
540
541#ifdef	notdef
542	/*
543	 * This bit of code, plus the firmware, will tell us if
544	 * the #size-cells infrastructure code works, to some degree.
545	 * You should be able to use the firmware to determine if
546	 * the address returned by ddi_map_regs maps the correct phys. pages.
547	 */
548
549	{
550		caddr_t addr;
551		int rv;
552
553		cmn_err(CE_CONT, "?sbus: address property = 0x%x\n", address);
554
555		if ((rv = ddi_map_regs(softsp->dip, 0, &addr,
556		    (off_t)0, (off_t)0)) != DDI_SUCCESS)  {
557			cmn_err(CE_CONT, "?sbus: ddi_map_regs failed: %d\n",
558			    rv);
559		} else {
560			cmn_err(CE_CONT, "?sbus: ddi_map_regs returned "
561			    " virtual address 0x%x\n", addr);
562		}
563	}
564#endif	/* notdef */
565
566	if ((error = iommu_init(softsp, softsp->address)) != DDI_SUCCESS)
567		goto bad;
568
569	if ((error = sbus_init(softsp, softsp->address)) != DDI_SUCCESS)
570		goto bad;
571
572	if ((error = sysio_err_init(softsp, softsp->address)) != DDI_SUCCESS)
573		goto bad;
574
575	if ((error = stream_buf_init(softsp, softsp->address)) != DDI_SUCCESS)
576		goto bad;
577
578	/* Init the pokefault mutex for sbus devices */
579	mutex_init(&softsp->pokefault_mutex, NULL, MUTEX_SPIN,
580	    (void *)ipltospl(SBUS_ERR_PIL - 1));
581
582	sbus_add_kstats(softsp);
583
584	bus_func_register(BF_TYPE_RESINTR, sbus_intr_reset, devi);
585
586	intr_dist_add(sbus_intrdist, devi);
587
588	ddi_report_dev(devi);
589
590	return (DDI_SUCCESS);
591
592bad:
593	ddi_soft_state_free(sbusp, instance);
594	return (error);
595}
596
597/* ARGSUSED */
598static int
599sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
600{
601	int instance;
602	struct sbus_soft_state *softsp;
603	uint64_t *cpr_softsp;
604
605	switch (cmd) {
606	case DDI_SUSPEND:
607		/*
608		 * Allocate the cpr  soft data structure to save the current
609		 * state of the interrupt mapping registers.
610		 * This structure will be deallocated after the system
611		 * is resumed.
612		 */
613		instance = ddi_get_instance(devi);
614
615		if (ddi_soft_state_zalloc(sbus_cprp, instance)
616		    != DDI_SUCCESS)
617			return (DDI_FAILURE);
618
619		cpr_softsp = ddi_get_soft_state(sbus_cprp, instance);
620
621		softsp = ddi_get_soft_state(sbusp, instance);
622
623		sbus_cpr_handle_intr_map_reg(cpr_softsp,
624		    softsp->intr_mapping_reg, 1);
625		return (DDI_SUCCESS);
626
627	case DDI_DETACH:
628		return (sbus_do_detach(devi));
629	default:
630		return (DDI_FAILURE);
631	}
632}
633
634static int
635sbus_do_detach(dev_info_t *devi)
636{
637	int instance, pic;
638	struct sbus_soft_state *softsp;
639
640	instance = ddi_get_instance(devi);
641	softsp = ddi_get_soft_state(sbusp, instance);
642	ASSERT(softsp != NULL);
643
644	bus_func_unregister(BF_TYPE_RESINTR, sbus_intr_reset, devi);
645
646	intr_dist_rem(sbus_intrdist, devi);
647
648	/* disable the streamming cache */
649	if (stream_buf_uninit(softsp) == DDI_FAILURE) {
650		goto err;
651	}
652
653	/* remove the interrupt handlers from the system */
654	if (sysio_err_uninit(softsp) == DDI_FAILURE) {
655		goto err;
656	}
657
658	/* disable the IOMMU */
659	if (iommu_uninit(softsp)) {
660		goto err;
661	}
662
663	/* unmap register space if we have a handle */
664	if (softsp->ac) {
665		ddi_regs_map_free(&softsp->ac);
666		softsp->address = NULL;
667	}
668
669	/*
670	 * remove counter kstats for this device
671	 */
672	if (softsp->sbus_counters_ksp != (kstat_t *)NULL)
673		kstat_delete(softsp->sbus_counters_ksp);
674
675	/*
676	 * if we are the last instance to detach we need to
677	 * remove the picN kstats. We use sbus_attachcnt as a
678	 * count of how many instances are still attached. This
679	 * is protected by a mutex.
680	 */
681	mutex_enter(&sbus_attachcnt_mutex);
682	sbus_attachcnt --;
683	if (sbus_attachcnt == 0) {
684		for (pic = 0; pic < SBUS_NUM_PICS; pic++) {
685			if (sbus_picN_ksp[pic] != (kstat_t *)NULL) {
686				kstat_delete(sbus_picN_ksp[pic]);
687				sbus_picN_ksp[pic] = NULL;
688			}
689		}
690	}
691	mutex_exit(&sbus_attachcnt_mutex);
692
693#ifdef _STARFIRE
694	/* free starfire specific soft intr mapping structure */
695	pc_ittrans_uninit(softsp->ittrans_cookie);
696#endif /* _STARFIRE */
697
698	/* free the soft state structure */
699	ddi_soft_state_free(sbusp, instance);
700
701	return (DDI_SUCCESS);
702err:
703	return (DDI_FAILURE);
704}
705
706static int
707sbus_init(struct sbus_soft_state *softsp, caddr_t address)
708{
709	int i;
710	extern void set_intr_mapping_reg(int, uint64_t *, int);
711	int numproxy;
712
713	/*
714	 * Simply add each registers offset to the base address
715	 * to calculate the already mapped virtual address of
716	 * the device register...
717	 *
718	 * define a macro for the pointer arithmetic; all registers
719	 * are 64 bits wide and are defined as uint64_t's.
720	 */
721
722#define	REG_ADDR(b, o)	(uint64_t *)((caddr_t)(b) + (o))
723
724	softsp->sysio_ctrl_reg = REG_ADDR(address, OFF_SYSIO_CTRL_REG);
725	softsp->sbus_ctrl_reg = REG_ADDR(address, OFF_SBUS_CTRL_REG);
726	softsp->sbus_slot_config_reg = REG_ADDR(address, OFF_SBUS_SLOT_CONFIG);
727	softsp->intr_mapping_reg = REG_ADDR(address, OFF_INTR_MAPPING_REG);
728	softsp->clr_intr_reg = REG_ADDR(address, OFF_CLR_INTR_REG);
729	softsp->intr_retry_reg = REG_ADDR(address, OFF_INTR_RETRY_REG);
730	softsp->sbus_intr_state = REG_ADDR(address, OFF_SBUS_INTR_STATE_REG);
731	softsp->sbus_pcr = REG_ADDR(address, OFF_SBUS_PCR);
732	softsp->sbus_pic = REG_ADDR(address, OFF_SBUS_PIC);
733
734#undef	REG_ADDR
735
736	DPRINTF(SBUS_REGISTERS_DEBUG, ("SYSIO Control reg: 0x%p\n"
737	    "SBUS Control reg: 0x%p", (void *)softsp->sysio_ctrl_reg,
738	    (void *)softsp->sbus_ctrl_reg));
739
740#ifdef _STARFIRE
741	/* Setup interrupt target translation for starfire */
742	pc_ittrans_init(softsp->upa_id, &softsp->ittrans_cookie);
743#endif /* _STARFIRE */
744
745	softsp->intr_mapping_ign =
746	    UPAID_TO_IGN(softsp->upa_id) << IMR_IGN_SHIFT;
747
748	/* Diag reg 2 is the next 64 bit word after diag reg 1 */
749	softsp->obio_intr_state = softsp->sbus_intr_state + 1;
750
751	(void) sbus_resume_init(softsp, 0);
752
753	/*
754	 * Set the initial burstsizes for each slot to all 1's.  This will
755	 * get changed at initchild time.
756	 */
757	for (i = 0; i < MAX_SBUS_SLOTS; i++)
758		softsp->sbus_slave_burstsizes[i] = 0xffffffffu;
759
760	/*
761	 * Since SYSIO is used as an interrupt mastering device for slave
762	 * only UPA devices, we call a dedicated kernel function to register
763	 * The address of the interrupt mapping register for the slave device.
764	 *
765	 * If RISC/sysio is wired to support 2 upa slave interrupt
766	 * devices then register 2nd mapping register with system.
767	 * The slave/proxy portid algorithm (decribed in Fusion Desktop Spec)
768	 * allows for upto 3 slaves per proxy but Psycho/SYSIO only support 2.
769	 *
770	 * #upa-interrupt-proxies property defines how many UPA interrupt
771	 * slaves a bridge is wired to support. Older systems that lack
772	 * this property will default to 1.
773	 */
774	numproxy = ddi_prop_get_int(DDI_DEV_T_ANY, softsp->dip,
775	    DDI_PROP_DONTPASS, "#upa-interrupt-proxies", 1);
776
777	if (numproxy > 0)
778		set_intr_mapping_reg(softsp->upa_id,
779		    (uint64_t *)(softsp->intr_mapping_reg +
780		    FFB_MAPPING_REG), 1);
781
782	if (numproxy > 1)
783		set_intr_mapping_reg(softsp->upa_id,
784		    (uint64_t *)(softsp->intr_mapping_reg +
785		    EXP_MAPPING_REG), 2);
786
787	/* support for a 3 interrupt proxy would go here */
788
789	/* Turn on spurious interrupt counter if we're not a DEBUG kernel. */
790#ifndef DEBUG
791	intr_cntr_on = 1;
792#else
793	intr_cntr_on = 0;
794#endif
795
796
797	return (DDI_SUCCESS);
798}
799
800/*
801 * This procedure is part of sbus initialization. It is called by
802 * sbus_init() and is invoked when the system is being resumed.
803 */
804static int
805sbus_resume_init(struct sbus_soft_state *softsp, int resume)
806{
807	int i;
808	uint_t sbus_burst_sizes;
809
810	/*
811	 * This shouldn't be needed when we have a real OBP PROM.
812	 * (RAZ) Get rid of this later!!!
813	 */
814
815#ifdef _STARFIRE
816	/*
817	 * For Starfire, we need to program a
818	 * constant odd value.
819	 * Zero out the MID field before ORing
820	 * We leave the LSB of the MID field intact since
821	 * we cannot have a zero(even) MID value
822	 */
823	uint64_t tmpconst = 0x1DULL;
824	*softsp->sysio_ctrl_reg &= 0xFF0FFFFFFFFFFFFFULL;
825	*softsp->sysio_ctrl_reg |= tmpconst << 51;
826
827	/*
828	 * Program in the interrupt group number
829	 * Here we have to convert the starfire
830	 * 7 bit upaid into a 5bit value.
831	 */
832	*softsp->sysio_ctrl_reg |=
833	    (uint64_t)STARFIRE_UPAID2HWIGN(softsp->upa_id)
834	    << SYSIO_IGN;
835#else
836	/* for the rest of sun4u's */
837	*softsp->sysio_ctrl_reg |=
838	    (uint64_t)softsp->upa_id << 51;
839
840	/* Program in the interrupt group number */
841	*softsp->sysio_ctrl_reg |=
842	    (uint64_t)softsp->upa_id << SYSIO_IGN;
843#endif /* _STARFIRE */
844
845	/*
846	 * Set appropriate fields of sbus control register.
847	 * Set DVMA arbitration enable for all devices.
848	 */
849	*softsp->sbus_ctrl_reg |= SBUS_ARBIT_ALL;
850
851	/* Calculate our burstsizes now so we don't have to do it later */
852	sbus_burst_sizes = (SYSIO64_BURST_RANGE << SYSIO64_BURST_SHIFT)
853	    | SYSIO_BURST_RANGE;
854
855	sbus_burst_sizes = ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
856	    DDI_PROP_DONTPASS, "up-burst-sizes", sbus_burst_sizes);
857
858	softsp->sbus_burst_sizes = sbus_burst_sizes & SYSIO_BURST_MASK;
859	softsp->sbus64_burst_sizes = sbus_burst_sizes & SYSIO64_BURST_MASK;
860
861	if (!resume) {
862		/* Set burstsizes to smallest value */
863		for (i = 0; i < MAX_SBUS_SLOTS; i++) {
864			volatile uint64_t *config;
865			uint64_t tmpreg;
866
867			config = softsp->sbus_slot_config_reg + i;
868
869			/* Write out the burst size */
870			tmpreg = (uint64_t)0;
871			*config = tmpreg;
872
873			/* Flush any write buffers */
874			tmpreg = *softsp->sbus_ctrl_reg;
875
876			DPRINTF(SBUS_REGISTERS_DEBUG, ("Sbus slot 0x%x slot "
877			    "configuration reg: 0x%p", (i > 3) ? i + 9 : i,
878			    (void *)config));
879		}
880	} else {
881		/* Program the slot configuration registers */
882		for (i = 0; i < MAX_SBUS_SLOTS; i++) {
883			volatile uint64_t *config;
884#ifndef lint
885			uint64_t tmpreg;
886#endif /* !lint */
887			uint_t slave_burstsizes;
888
889			slave_burstsizes = 0;
890			if (softsp->sbus_slave_burstsizes[i] != 0xffffffffu) {
891				config = softsp->sbus_slot_config_reg + i;
892
893				if (softsp->sbus_slave_burstsizes[i] &
894				    SYSIO64_BURST_MASK) {
895					/* get the 64 bit burstsizes */
896					slave_burstsizes =
897					    softsp->sbus_slave_burstsizes[i] >>
898					    SYSIO64_BURST_SHIFT;
899
900					/* Turn on 64 bit PIO's on the sbus */
901					*config |= SBUS_ETM;
902				} else {
903					slave_burstsizes =
904					    softsp->sbus_slave_burstsizes[i] &
905					    SYSIO_BURST_MASK;
906				}
907
908				/* Get burstsizes into sysio register format */
909				slave_burstsizes >>= SYSIO_SLAVEBURST_REGSHIFT;
910
911				/* Program the burstsizes */
912				*config |= (uint64_t)slave_burstsizes;
913
914				/* Flush any write buffers */
915#ifndef lint
916				tmpreg = *softsp->sbus_ctrl_reg;
917#endif /* !lint */
918			}
919		}
920	}
921
922	return (DDI_SUCCESS);
923}
924
925#define	get_prop(di, pname, flag, pval, plen)	\
926	(ddi_prop_op(DDI_DEV_T_NONE, di, PROP_LEN_AND_VAL_ALLOC, \
927	flag | DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, \
928	pname, (caddr_t)pval, plen))
929
930struct prop_ispec {
931	uint_t	pri, vec;
932};
933
934/*
935 * Create a sysio_parent_private_data structure from the ddi properties of
936 * the dev_info node.
937 *
938 * The "reg" and either an "intr" or "interrupts" properties are required
939 * if the driver wishes to create mappings or field interrupts on behalf
940 * of the device.
941 *
942 * The "reg" property is assumed to be a list of at least one triple
943 *
944 *	<bustype, address, size>*1
945 *
946 * On pre-fusion machines, the "intr" property was the IPL for the system.
947 * Most new sbus devices post an "interrupts" property that corresponds to
948 * a particular bus level.  All devices on fusion using an "intr" property
949 * will have it's contents translated into a bus level.  Hence, "intr" and
950 * "interrupts on the fusion platform can be treated the same.
951 *
952 * The "interrupts" property is assumed to be a list of at least one
953 * n-tuples that describes the interrupt capabilities of the bus the device
954 * is connected to.  For SBus, this looks like
955 *
956 *	<SBus-level>*1
957 *
958 * (This property obsoletes the 'intr' property).
959 *
960 * The OBP_RANGES property is optional.
961 */
962static void
963make_sbus_ppd(dev_info_t *child)
964{
965	struct sysio_parent_private_data *pdptr;
966	int n;
967	int *reg_prop, *rgstr_prop, *rng_prop;
968	int reg_len, rgstr_len, rng_len;
969
970	/*
971	 * Make the function idempotent, because name_child could
972	 * be called multiple times on a node.
973	 */
974	if (ddi_get_parent_data(child) != NULL)
975		return;
976
977	pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP);
978	ddi_set_parent_data(child, pdptr);
979
980	/*
981	 * Handle the 'reg'/'registers' properties.
982	 * "registers" overrides "reg", but requires that "reg" be exported,
983	 * so we can handle wildcard specifiers.  "registers" implies an
984	 * sbus style device.  "registers" implies that we insert the
985	 * correct value in the regspec_bustype field of each spec for a real
986	 * (non-pseudo) device node.  "registers" is a s/w only property, so
987	 * we inhibit the prom search for this property.
988	 */
989	if (get_prop(child, OBP_REG, 0, &reg_prop, &reg_len) != DDI_SUCCESS)
990		reg_len = 0;
991
992	/*
993	 * Save the underlying slot number and slot offset.
994	 * Among other things, we use these to name the child node.
995	 */
996	pdptr->slot = (uint_t)-1;
997	if (reg_len != 0) {
998		pdptr->slot = ((struct regspec *)reg_prop)->regspec_bustype;
999		pdptr->offset = ((struct regspec *)reg_prop)->regspec_addr;
1000	}
1001
1002	rgstr_len = 0;
1003	(void) get_prop(child, "registers", DDI_PROP_NOTPROM,
1004	    &rgstr_prop, &rgstr_len);
1005
1006	if (rgstr_len != 0)  {
1007		if (ndi_dev_is_persistent_node(child) && (reg_len != 0))  {
1008			/*
1009			 * Convert wildcard "registers" for a real node...
1010			 * (Else, this is the wildcard prototype node)
1011			 */
1012			struct regspec *rp = (struct regspec *)reg_prop;
1013			uint_t slot = rp->regspec_bustype;
1014			int i;
1015
1016			rp = (struct regspec *)rgstr_prop;
1017			n = rgstr_len / sizeof (struct regspec);
1018			for (i = 0; i < n; ++i, ++rp)
1019				rp->regspec_bustype = slot;
1020		}
1021
1022		if (reg_len != 0)
1023			kmem_free(reg_prop, reg_len);
1024
1025		reg_prop = rgstr_prop;
1026		reg_len = rgstr_len;
1027	}
1028	if (reg_len != 0)  {
1029		pdptr->par_nreg = reg_len / (int)sizeof (struct regspec);
1030		pdptr->par_reg = (struct regspec *)reg_prop;
1031	}
1032
1033	/*
1034	 * See if I have ranges.
1035	 */
1036	if (get_prop(child, OBP_RANGES, 0, &rng_prop, &rng_len) ==
1037	    DDI_SUCCESS) {
1038		pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec));
1039		pdptr->par_rng = (struct rangespec *)rng_prop;
1040	}
1041}
1042
1043/*
1044 * Special handling for "sbusmem" pseudo device nodes.
1045 * The special handling automatically creates the "reg"
1046 * property in the sbusmem nodes, based on the parent's
1047 * property so that each slot will automtically have a
1048 * correctly sized "reg" property, once created,
1049 * sbus_initchild does the rest of the work to init
1050 * the child node.
1051 */
1052static int
1053sbusmem_initchild(dev_info_t *dip, dev_info_t *child)
1054{
1055	int i, n;
1056	int slot, size;
1057	char ident[10];
1058
1059	slot = ddi_getprop(DDI_DEV_T_NONE, child,
1060	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "slot", -1);
1061	if (slot == -1) {
1062		DPRINTF(SBUS_SBUSMEM_DEBUG, ("can't get slot property\n"));
1063		return (DDI_FAILURE);
1064	}
1065
1066	/*
1067	 * Find the parent range corresponding to this "slot",
1068	 * so we can set the size of the child's "reg" property.
1069	 */
1070	for (i = 0, n = sparc_pd_getnrng(dip); i < n; i++) {
1071		struct rangespec *rp = sparc_pd_getrng(dip, i);
1072
1073		if (rp->rng_cbustype == (uint_t)slot) {
1074			struct regspec r;
1075
1076			/* create reg property */
1077
1078			r.regspec_bustype = (uint_t)slot;
1079			r.regspec_addr = 0;
1080			r.regspec_size = rp->rng_size;
1081			(void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
1082			    child, "reg", (int *)&r,
1083			    sizeof (struct regspec) / sizeof (int));
1084
1085			/* create size property for slot */
1086
1087			size = rp->rng_size;
1088			(void) ddi_prop_update_int(DDI_DEV_T_NONE,
1089			    child, "size", size);
1090
1091			(void) sprintf(ident, "slot%x", slot);
1092			(void) ddi_prop_update_string(DDI_DEV_T_NONE,
1093			    child, "ident", ident);
1094
1095			return (DDI_SUCCESS);
1096		}
1097	}
1098	return (DDI_FAILURE);
1099}
1100
1101/*
1102 * Nexus routine to name a child.
1103 * It takes a dev_info node and a buffer, returns the name
1104 * in the buffer.
1105 */
1106static int
1107sysio_name_child(dev_info_t *child, char *name, int namelen)
1108{
1109	/*
1110	 * Fill in parent-private data
1111	 */
1112	make_sbus_ppd(child);
1113
1114	/*
1115	 * Name the device node using the underlying (prom) values
1116	 * of the first entry in the "reg" property.  For SBus devices,
1117	 * the textual form of the name is <name>@<slot#>,<offset>.
1118	 * This must match the prom's pathname or mountroot, etc, won't
1119	 */
1120	name[0] = '\0';
1121	if (sysio_pd_getslot(child) != (uint_t)-1) {
1122		(void) snprintf(name, namelen, "%x,%x",
1123		    sysio_pd_getslot(child), sysio_pd_getoffset(child));
1124	}
1125	return (DDI_SUCCESS);
1126}
1127
1128/*
1129 * Called from the bus_ctl op of sysio sbus nexus driver
1130 * to implement the DDI_CTLOPS_INITCHILD operation.  That is, it names
1131 * the children of sysio sbusses based on the reg spec.
1132 *
1133 * Handles the following properties:
1134 *
1135 *	Property		value
1136 *	  Name			type
1137 *
1138 *	reg		register spec
1139 *	registers	wildcard s/w sbus register spec (.conf file property)
1140 *	intr		old-form interrupt spec
1141 *	interrupts	new (bus-oriented) interrupt spec
1142 *	ranges		range spec
1143 */
1144static int
1145sbus_initchild(dev_info_t *dip, dev_info_t *child)
1146{
1147	char name[MAXNAMELEN];
1148	ulong_t slave_burstsizes;
1149	int slot;
1150	volatile uint64_t *slot_reg;
1151#ifndef lint
1152	uint64_t tmp;
1153#endif /* !lint */
1154	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
1155	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
1156
1157	if (strcmp(ddi_get_name(child), "sbusmem") == 0) {
1158		if (sbusmem_initchild(dip, child) != DDI_SUCCESS)
1159			return (DDI_FAILURE);
1160	}
1161
1162	/*
1163	 * If this is a s/w node defined with the "registers" property,
1164	 * this means that this is a wildcard specifier, whose properties
1165	 * get applied to all previously defined h/w nodes with the same
1166	 * name and same parent.
1167	 */
1168	if (ndi_dev_is_persistent_node(child) == 0) {
1169		int len = 0;
1170		if ((ddi_getproplen(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM,
1171		    "registers", &len) == DDI_SUCCESS) && (len != 0)) {
1172			ndi_merge_wildcard_node(child);
1173			return (DDI_FAILURE);
1174		}
1175	}
1176
1177	/* name the child */
1178	(void) sysio_name_child(child, name, MAXNAMELEN);
1179	ddi_set_name_addr(child, name);
1180
1181	/*
1182	 * If a pseudo node, attempt to merge it into a hw node.
1183	 * If merge is successful, we uinitialize the node and
1184	 * return failure, to allow caller to remove the node.
1185	 * The merge fails, this is a real pseudo node. Allow
1186	 * initchild to continue.
1187	 */
1188	if ((ndi_dev_is_persistent_node(child) == 0) &&
1189	    (ndi_merge_node(child, sysio_name_child) == DDI_SUCCESS)) {
1190		(void) sbus_uninitchild(child);
1191		return (DDI_FAILURE);
1192	}
1193
1194	/* Figure out the child devices slot number */
1195	slot = sysio_pd_getslot(child);
1196
1197	/* If we don't have a reg property, bypass slot specific programming */
1198	if (slot < 0 || slot >= MAX_SBUS_SLOT_ADDR) {
1199#ifdef DEBUG
1200		cmn_err(CE_WARN, "?Invalid sbus slot address 0x%x for %s "
1201		    "device\n", slot, ddi_get_name(child));
1202#endif /* DEBUG */
1203		goto done;
1204	}
1205
1206	/* Modify the onboard slot numbers if applicable. */
1207	slot = (slot > 3) ? slot - 9 : slot;
1208
1209	/* Get the slot configuration register for the child device. */
1210	slot_reg = softsp->sbus_slot_config_reg + slot;
1211
1212	/*
1213	 * Program the devices slot configuration register for the
1214	 * appropriate slave burstsizes.
1215	 * The upper 16 bits of the slave-burst-sizes are for 64 bit sbus
1216	 * and the lower 16 bits are the burst sizes for 32 bit sbus. If
1217	 * we see that a device supports both 64 bit and 32 bit slave accesses,
1218	 * we default to 64 bit and turn it on in the slot config reg.
1219	 *
1220	 * For older devices, make sure we check the "burst-sizes" property
1221	 * too.
1222	 */
1223	if ((slave_burstsizes = (ulong_t)ddi_getprop(DDI_DEV_T_ANY, child,
1224	    DDI_PROP_DONTPASS, "slave-burst-sizes", 0)) != 0 ||
1225	    (slave_burstsizes = (ulong_t)ddi_getprop(DDI_DEV_T_ANY, child,
1226	    DDI_PROP_DONTPASS, "burst-sizes", 0)) != 0) {
1227		uint_t burstsizes = 0;
1228
1229		/*
1230		 * If we only have 32 bit burst sizes from a previous device,
1231		 * mask out any burstsizes for 64 bit mode.
1232		 */
1233		if (((softsp->sbus_slave_burstsizes[slot] &
1234		    0xffff0000u) == 0) &&
1235		    ((softsp->sbus_slave_burstsizes[slot] & 0xffff) != 0)) {
1236			slave_burstsizes &= 0xffff;
1237		}
1238
1239		/*
1240		 * If "slave-burst-sizes was defined but we have 0 at this
1241		 * point, we must have had 64 bit burstsizes, however a prior
1242		 * device can only burst in 32 bit mode.  Therefore, we leave
1243		 * the burstsizes in the 32 bit mode and disregard the 64 bit.
1244		 */
1245		if (slave_burstsizes == 0)
1246			goto done;
1247
1248		/*
1249		 * We and in the new burst sizes with that of prior devices.
1250		 * This ensures that we always take the least common
1251		 * denominator of the burst sizes.
1252		 */
1253		softsp->sbus_slave_burstsizes[slot] &=
1254		    (slave_burstsizes &
1255		    ((SYSIO64_SLAVEBURST_RANGE <<
1256		    SYSIO64_BURST_SHIFT) |
1257		    SYSIO_SLAVEBURST_RANGE));
1258
1259		/* Get the 64 bit burstsizes. */
1260		if (softsp->sbus_slave_burstsizes[slot] &
1261		    SYSIO64_BURST_MASK) {
1262			/* get the 64 bit burstsizes */
1263			burstsizes = softsp->sbus_slave_burstsizes[slot] >>
1264			    SYSIO64_BURST_SHIFT;
1265
1266			/* Turn on 64 bit PIO's on the sbus */
1267			*slot_reg |= SBUS_ETM;
1268		} else {
1269			/* Turn off 64 bit PIO's on the sbus */
1270			*slot_reg &= ~SBUS_ETM;
1271
1272			/* Get the 32 bit burstsizes if we don't have 64 bit. */
1273			if (softsp->sbus_slave_burstsizes[slot] &
1274			    SYSIO_BURST_MASK) {
1275				burstsizes =
1276				    softsp->sbus_slave_burstsizes[slot] &
1277				    SYSIO_BURST_MASK;
1278			}
1279		}
1280
1281		/* Get the burstsizes into sysio register format */
1282		burstsizes >>= SYSIO_SLAVEBURST_REGSHIFT;
1283
1284		/* Reset reg in case we're scaling back */
1285		*slot_reg &= (uint64_t)~SYSIO_SLAVEBURST_MASK;
1286
1287		/* Program the burstsizes */
1288		*slot_reg |= (uint64_t)burstsizes;
1289
1290		/* Flush system load/store buffers */
1291#ifndef lint
1292		tmp = *slot_reg;
1293#endif /* !lint */
1294	}
1295
1296done:
1297	return (DDI_SUCCESS);
1298}
1299
1300static int
1301sbus_uninitchild(dev_info_t *dip)
1302{
1303	struct sysio_parent_private_data *pdptr;
1304	size_t n;
1305
1306	if ((pdptr = ddi_get_parent_data(dip)) != NULL)  {
1307		if ((n = (size_t)pdptr->par_nrng) != 0)
1308			kmem_free(pdptr->par_rng, n *
1309			    sizeof (struct rangespec));
1310
1311		if ((n = pdptr->par_nreg) != 0)
1312			kmem_free(pdptr->par_reg, n * sizeof (struct regspec));
1313
1314		kmem_free(pdptr, sizeof (*pdptr));
1315		ddi_set_parent_data(dip, NULL);
1316	}
1317	ddi_set_name_addr(dip, NULL);
1318	/*
1319	 * Strip the node to properly convert it back to prototype form
1320	 */
1321	ddi_remove_minor_node(dip, NULL);
1322	impl_rem_dev_props(dip);
1323	return (DDI_SUCCESS);
1324}
1325
1326#ifdef  DEBUG
1327int	sbus_peekfault_cnt = 0;
1328int	sbus_pokefault_cnt = 0;
1329#endif  /* DEBUG */
1330
1331static int
1332sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args)
1333{
1334	int err = DDI_SUCCESS;
1335	on_trap_data_t otd;
1336	volatile uint64_t tmpreg;
1337
1338	/* Cautious access not supported. */
1339	if (in_args->handle != NULL)
1340		return (DDI_FAILURE);
1341
1342	mutex_enter(&softsp->pokefault_mutex);
1343	softsp->ontrap_data = &otd;
1344
1345	/* Set up protected environment. */
1346	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1347		uintptr_t tramp = otd.ot_trampoline;
1348
1349		otd.ot_trampoline = (uintptr_t)&poke_fault;
1350		err = do_poke(in_args->size, (void *)in_args->dev_addr,
1351		    (void *)in_args->host_addr);
1352		otd.ot_trampoline = tramp;
1353	} else
1354		err = DDI_FAILURE;
1355
1356	/* Flush any sbus store buffers. */
1357	tmpreg = *softsp->sbus_ctrl_reg;
1358
1359	/*
1360	 * Read the sbus error reg and see if a fault occured.  If
1361	 * one has, give the SYSIO time to packetize the interrupt
1362	 * for the fault and send it out.  The sbus error handler will
1363	 * 0 these fields when it's called to service the fault.
1364	 */
1365	tmpreg = *softsp->sbus_err_reg;
1366	while (tmpreg & SB_AFSR_P_TO || tmpreg & SB_AFSR_P_BERR)
1367		tmpreg = *softsp->sbus_err_reg;
1368
1369	/* Take down protected environment. */
1370	no_trap();
1371
1372	softsp->ontrap_data = NULL;
1373	mutex_exit(&softsp->pokefault_mutex);
1374
1375#ifdef  DEBUG
1376	if (err == DDI_FAILURE)
1377		sbus_pokefault_cnt++;
1378#endif
1379	return (err);
1380}
1381
1382/*ARGSUSED*/
1383static int
1384sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args,
1385    void *result)
1386{
1387	int err = DDI_SUCCESS;
1388	on_trap_data_t otd;
1389
1390	/* No safe access except for peek is supported. */
1391	if (in_args->handle != NULL)
1392		return (DDI_FAILURE);
1393
1394	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1395		uintptr_t tramp = otd.ot_trampoline;
1396
1397		otd.ot_trampoline = (uintptr_t)&peek_fault;
1398		err = do_peek(in_args->size, (void *)in_args->dev_addr,
1399		    (void *)in_args->host_addr);
1400		otd.ot_trampoline = tramp;
1401		result = (void *)in_args->host_addr;
1402	} else
1403		err = DDI_FAILURE;
1404
1405#ifdef  DEBUG
1406	if (err == DDI_FAILURE)
1407		sbus_peekfault_cnt++;
1408#endif
1409	no_trap();
1410	return (err);
1411}
1412
1413static int
1414sbus_ctlops(dev_info_t *dip, dev_info_t *rdip,
1415    ddi_ctl_enum_t op, void *arg, void *result)
1416{
1417	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
1418	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
1419
1420	switch (op) {
1421
1422	case DDI_CTLOPS_INITCHILD:
1423		return (sbus_initchild(dip, (dev_info_t *)arg));
1424
1425	case DDI_CTLOPS_UNINITCHILD:
1426		return (sbus_uninitchild(arg));
1427
1428	case DDI_CTLOPS_IOMIN: {
1429		int val = *((int *)result);
1430
1431		/*
1432		 * The 'arg' value of nonzero indicates 'streaming' mode.
1433		 * If in streaming mode, pick the largest of our burstsizes
1434		 * available and say that that is our minimum value (modulo
1435		 * what mincycle is).
1436		 */
1437		if ((int)(uintptr_t)arg)
1438			val = maxbit(val,
1439			    (1 << (ddi_fls(softsp->sbus_burst_sizes) - 1)));
1440		else
1441			val = maxbit(val,
1442			    (1 << (ddi_ffs(softsp->sbus_burst_sizes) - 1)));
1443
1444		*((int *)result) = val;
1445		return (ddi_ctlops(dip, rdip, op, arg, result));
1446	}
1447
1448	case DDI_CTLOPS_REPORTDEV: {
1449		dev_info_t *pdev;
1450		int i, n, len, f_len;
1451		char *msgbuf;
1452
1453	/*
1454	 * So we can do one atomic cmn_err call, we allocate a 4k
1455	 * buffer, and format the reportdev message into that buffer,
1456	 * send it to cmn_err, and then free the allocated buffer.
1457	 * If message is longer than 1k, the message is truncated and
1458	 * an error message is emitted (debug kernel only).
1459	 */
1460#define	REPORTDEV_BUFSIZE	1024
1461
1462		int sbusid = ddi_get_instance(dip);
1463
1464		if (ddi_get_parent_data(rdip) == NULL)
1465			return (DDI_FAILURE);
1466
1467		msgbuf = kmem_zalloc(REPORTDEV_BUFSIZE, KM_SLEEP);
1468
1469		pdev = ddi_get_parent(rdip);
1470		f_len = snprintf(msgbuf, REPORTDEV_BUFSIZE,
1471		    "%s%d at %s%d: SBus%d ",
1472		    ddi_driver_name(rdip), ddi_get_instance(rdip),
1473		    ddi_driver_name(pdev), ddi_get_instance(pdev), sbusid);
1474		len = strlen(msgbuf);
1475
1476		for (i = 0, n = sysio_pd_getnreg(rdip); i < n; i++) {
1477			struct regspec *rp;
1478
1479			rp = sysio_pd_getreg(rdip, i);
1480			if (i != 0) {
1481				f_len += snprintf(msgbuf + len,
1482				    REPORTDEV_BUFSIZE - len, " and ");
1483				len = strlen(msgbuf);
1484			}
1485
1486			f_len += snprintf(msgbuf + len, REPORTDEV_BUFSIZE - len,
1487			    "slot 0x%x offset 0x%x",
1488			    rp->regspec_bustype, rp->regspec_addr);
1489			len = strlen(msgbuf);
1490		}
1491
1492		for (i = 0, n = i_ddi_get_intx_nintrs(rdip); i < n; i++) {
1493			uint32_t sbuslevel, inum, pri;
1494
1495			if (i != 0) {
1496				f_len += snprintf(msgbuf + len,
1497				    REPORTDEV_BUFSIZE - len, ",");
1498				len = strlen(msgbuf);
1499			}
1500
1501			sbuslevel = inum = i_ddi_get_inum(rdip, i);
1502			pri = i_ddi_get_intr_pri(rdip, i);
1503
1504			(void) sbus_xlate_intrs(dip, rdip, &inum,
1505			    &pri, softsp->intr_mapping_ign);
1506
1507			if (sbuslevel > MAX_SBUS_LEVEL)
1508				f_len += snprintf(msgbuf + len,
1509				    REPORTDEV_BUFSIZE - len,
1510				    " Onboard device ");
1511			else
1512				f_len += snprintf(msgbuf + len,
1513				    REPORTDEV_BUFSIZE - len, " SBus level %d ",
1514				    sbuslevel);
1515			len = strlen(msgbuf);
1516
1517			f_len += snprintf(msgbuf + len, REPORTDEV_BUFSIZE - len,
1518			    "sparc9 ipl %d", pri);
1519			len = strlen(msgbuf);
1520		}
1521#ifdef DEBUG
1522	if (f_len + 1 >= REPORTDEV_BUFSIZE) {
1523		cmn_err(CE_NOTE, "next message is truncated: "
1524		    "printed length 1024, real length %d", f_len);
1525	}
1526#endif /* DEBUG */
1527
1528		cmn_err(CE_CONT, "?%s\n", msgbuf);
1529		kmem_free(msgbuf, REPORTDEV_BUFSIZE);
1530		return (DDI_SUCCESS);
1531
1532#undef	REPORTDEV_BUFSIZE
1533	}
1534
1535	case DDI_CTLOPS_SLAVEONLY:
1536		return (DDI_FAILURE);
1537
1538	case DDI_CTLOPS_AFFINITY: {
1539		dev_info_t *dipb = (dev_info_t *)arg;
1540		int r_slot, b_slot;
1541
1542		if ((b_slot = find_sbus_slot(dip, dipb)) < 0)
1543			return (DDI_FAILURE);
1544
1545		if ((r_slot = find_sbus_slot(dip, rdip)) < 0)
1546			return (DDI_FAILURE);
1547
1548		return ((b_slot == r_slot)? DDI_SUCCESS : DDI_FAILURE);
1549
1550	}
1551	case DDI_CTLOPS_DMAPMAPC:
1552		cmn_err(CE_CONT, "?DDI_DMAPMAPC called!!\n");
1553		return (DDI_FAILURE);
1554
1555	case DDI_CTLOPS_POKE:
1556		return (sbus_ctlops_poke(softsp, (peekpoke_ctlops_t *)arg));
1557
1558	case DDI_CTLOPS_PEEK:
1559		return (sbus_ctlops_peek(softsp, (peekpoke_ctlops_t *)arg,
1560		    result));
1561
1562	case DDI_CTLOPS_DVMAPAGESIZE:
1563		*(ulong_t *)result = IOMMU_PAGESIZE;
1564		return (DDI_SUCCESS);
1565
1566	default:
1567		return (ddi_ctlops(dip, rdip, op, arg, result));
1568	}
1569}
1570
1571static int
1572find_sbus_slot(dev_info_t *dip, dev_info_t *rdip)
1573{
1574	dev_info_t *child;
1575	int slot = -1;
1576
1577	/*
1578	 * look for the node that's a direct child of this Sbus node.
1579	 */
1580	while (rdip && (child = ddi_get_parent(rdip)) != dip) {
1581		rdip = child;
1582	}
1583
1584	/*
1585	 * If there is one, get the slot number of *my* child
1586	 */
1587	if (child == dip)
1588		slot = sysio_pd_getslot(rdip);
1589
1590	return (slot);
1591}
1592
1593/*
1594 * This is the sbus interrupt routine wrapper function.  This function
1595 * installs itself as a child devices interrupt handler.  It's function is
1596 * to dispatch a child devices interrupt handler, and then
1597 * reset the interrupt clear register for the child device.
1598 *
1599 * Warning: This routine may need to be implemented as an assembly level
1600 * routine to improve performance.
1601 */
1602
1603#define	MAX_INTR_CNT 10
1604
1605static uint_t
1606sbus_intr_wrapper(caddr_t arg)
1607{
1608	uint_t intr_return = DDI_INTR_UNCLAIMED;
1609	volatile uint64_t tmpreg;
1610	struct sbus_wrapper_arg *intr_info;
1611	struct sbus_intr_handler *intr_handler;
1612	uchar_t *spurious_cntr;
1613
1614	intr_info = (struct sbus_wrapper_arg *)arg;
1615	spurious_cntr = &intr_info->softsp->spurious_cntrs[intr_info->pil];
1616	intr_handler = intr_info->handler_list;
1617
1618	while (intr_handler) {
1619		caddr_t arg1 = intr_handler->arg1;
1620		caddr_t arg2 = intr_handler->arg2;
1621		uint_t (*funcp)() = intr_handler->funcp;
1622		dev_info_t *dip = intr_handler->dip;
1623		int r;
1624
1625		if (intr_handler->intr_state == SBUS_INTR_STATE_DISABLE) {
1626			intr_handler = intr_handler->next;
1627			continue;
1628		}
1629
1630		DTRACE_PROBE4(interrupt__start, dev_info_t, dip,
1631		    void *, funcp, caddr_t, arg1, caddr_t, arg2);
1632
1633		r = (*funcp)(arg1, arg2);
1634
1635		DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
1636		    void *, funcp, caddr_t, arg1, int, r);
1637
1638		intr_return |= r;
1639		intr_handler = intr_handler->next;
1640	}
1641
1642	/* Set the interrupt state machine to idle */
1643	tmpreg = *intr_info->softsp->sbus_ctrl_reg;
1644	tmpreg = SBUS_INTR_IDLE;
1645	*intr_info->clear_reg = tmpreg;
1646	tmpreg = *intr_info->softsp->sbus_ctrl_reg;
1647
1648	if (intr_return == DDI_INTR_UNCLAIMED) {
1649		(*spurious_cntr)++;
1650
1651		if (*spurious_cntr < MAX_INTR_CNT) {
1652			if (intr_cntr_on)
1653				return (DDI_INTR_CLAIMED);
1654		}
1655#ifdef DEBUG
1656		else if (intr_info->pil >= LOCK_LEVEL) {
1657			cmn_err(CE_PANIC, "%d unclaimed interrupts at "
1658			    "interrupt level %d", MAX_INTR_CNT,
1659			    intr_info->pil);
1660		}
1661#endif
1662
1663		/*
1664		 * Reset spurious counter once we acknowledge
1665		 * it to the system level.
1666		 */
1667		*spurious_cntr = (uchar_t)0;
1668	} else {
1669		*spurious_cntr = (uchar_t)0;
1670	}
1671
1672	return (intr_return);
1673}
1674
1675/*
1676 * add_intrspec - Add an interrupt specification.
1677 */
1678static int
1679sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1680    ddi_intr_handle_impl_t *hdlp)
1681{
1682	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
1683	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
1684	volatile uint64_t *mondo_vec_reg;
1685	volatile uint64_t tmp_mondo_vec;
1686	volatile uint64_t *intr_state_reg;
1687	volatile uint64_t tmpreg;	/* HW flush reg */
1688	uint_t start_bit;
1689	int ino;
1690	uint_t cpu_id;
1691	struct sbus_wrapper_arg *sbus_arg;
1692	struct sbus_intr_handler *intr_handler;
1693	uint32_t slot;
1694	/* Interrupt state machine reset flag */
1695	int reset_ism_register = 1;
1696	int ret = DDI_SUCCESS;
1697
1698	/* Check if we have a valid sbus slot address */
1699	if (((slot = (uint_t)find_sbus_slot(dip, rdip)) >=
1700	    MAX_SBUS_SLOT_ADDR) || (slot < (uint_t)0)) {
1701		cmn_err(CE_WARN, "Invalid sbus slot 0x%x during add intr\n",
1702		    slot);
1703		return (DDI_FAILURE);
1704	}
1705
1706	DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: sbus interrupt %d "
1707	    "for device %s%d\n", hdlp->ih_vector, ddi_driver_name(rdip),
1708	    ddi_get_instance(rdip)));
1709
1710	/* Xlate the interrupt */
1711	if (sbus_xlate_intrs(dip, rdip, (uint32_t *)&hdlp->ih_vector,
1712	    &hdlp->ih_pri, softsp->intr_mapping_ign) == DDI_FAILURE) {
1713		cmn_err(CE_WARN, "Can't xlate SBUS devices %s interrupt.\n",
1714		    ddi_driver_name(rdip));
1715		return (DDI_FAILURE);
1716	}
1717
1718	/* get the ino number */
1719	ino = hdlp->ih_vector & SBUS_MAX_INO;
1720	mondo_vec_reg = (softsp->intr_mapping_reg +
1721	    ino_table[ino]->mapping_reg);
1722
1723	/*
1724	 * This is an intermediate step in identifying
1725	 * the exact bits which represent the device in the interrupt
1726	 * state diagnostic register.
1727	 */
1728	if (ino > MAX_MONDO_EXTERNAL) {
1729		start_bit = ino_table[ino]->diagreg_shift;
1730		intr_state_reg = softsp->obio_intr_state;
1731	} else {
1732		start_bit = 16 * (ino >> 3) + 2 * (ino & 0x7);
1733		intr_state_reg = softsp->sbus_intr_state;
1734	}
1735
1736
1737	/* Allocate a nexus interrupt data structure */
1738	intr_handler = kmem_zalloc(sizeof (struct sbus_intr_handler), KM_SLEEP);
1739	intr_handler->dip = rdip;
1740	intr_handler->funcp = hdlp->ih_cb_func;
1741	intr_handler->arg1 = hdlp->ih_cb_arg1;
1742	intr_handler->arg2 = hdlp->ih_cb_arg2;
1743	intr_handler->inum = hdlp->ih_inum;
1744
1745	DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: xlated interrupt 0x%x "
1746	    "intr_handler 0x%p\n", hdlp->ih_vector, (void *)intr_handler));
1747
1748	/*
1749	 * Grab this lock here. So it will protect the poll list.
1750	 */
1751	mutex_enter(&softsp->intr_poll_list_lock);
1752
1753	sbus_arg = softsp->intr_list[ino];
1754	/* Check if we have a poll list to deal with */
1755	if (sbus_arg) {
1756		tmp_mondo_vec = *mondo_vec_reg;
1757		tmp_mondo_vec &= ~INTERRUPT_VALID;
1758		*mondo_vec_reg = tmp_mondo_vec;
1759
1760		tmpreg = *softsp->sbus_ctrl_reg;
1761#ifdef	lint
1762		tmpreg = tmpreg;
1763#endif
1764
1765		DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:sbus_arg exists "
1766		    "0x%p\n", (void *)sbus_arg));
1767		/*
1768		 * Two bits per ino in the diagnostic register
1769		 * indicate the status of its interrupt.
1770		 * 0 - idle, 1 - transmit, 3 - pending.
1771		 */
1772		while (((*intr_state_reg >>
1773		    start_bit) & 0x3) == INT_PENDING && !panicstr)
1774			/* empty */;
1775
1776		intr_handler->next = sbus_arg->handler_list;
1777		sbus_arg->handler_list = intr_handler;
1778
1779		reset_ism_register = 0;
1780	} else {
1781		sbus_arg = kmem_zalloc(sizeof (struct sbus_wrapper_arg),
1782		    KM_SLEEP);
1783
1784		softsp->intr_list[ino] = sbus_arg;
1785		sbus_arg->clear_reg = (softsp->clr_intr_reg +
1786		    ino_table[ino]->clear_reg);
1787		DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:Ino 0x%x Interrupt "
1788		    "clear reg: 0x%p\n", ino, (void *)sbus_arg->clear_reg));
1789		sbus_arg->softsp = softsp;
1790		sbus_arg->handler_list = intr_handler;
1791
1792		/*
1793		 * No handler added yet in the interrupt vector
1794		 * table for this ino.
1795		 * Install the nexus interrupt wrapper in the
1796		 * system. The wrapper will call the device
1797		 * interrupt handler.
1798		 */
1799		DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
1800		    (ddi_intr_handler_t *)sbus_intr_wrapper,
1801		    (caddr_t)sbus_arg, NULL);
1802
1803		ret = i_ddi_add_ivintr(hdlp);
1804
1805		/*
1806		 * Restore original interrupt handler
1807		 * and arguments in interrupt handle.
1808		 */
1809		DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, intr_handler->funcp,
1810		    intr_handler->arg1, intr_handler->arg2);
1811
1812		if (ret != DDI_SUCCESS) {
1813			mutex_exit(&softsp->intr_poll_list_lock);
1814			goto done;
1815		}
1816
1817		if ((slot >= EXT_SBUS_SLOTS) ||
1818		    (softsp->intr_hndlr_cnt[slot] == 0)) {
1819
1820			cpu_id = intr_dist_cpuid();
1821#ifdef	_STARFIRE
1822			tmp_mondo_vec = pc_translate_tgtid(
1823			    softsp->ittrans_cookie, cpu_id,
1824			    mondo_vec_reg) << IMR_TID_SHIFT;
1825#else
1826			tmp_mondo_vec =
1827			    cpu_id << IMR_TID_SHIFT;
1828			DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: initial "
1829			    "mapping reg 0x%lx\n", tmp_mondo_vec));
1830#endif	/* _STARFIRE */
1831		} else {
1832			/*
1833			 * There is already a different
1834			 * ino programmed at this IMR.
1835			 * Just read the IMR out to get the
1836			 * correct MID target.
1837			 */
1838			tmp_mondo_vec = *mondo_vec_reg;
1839			tmp_mondo_vec &= ~INTERRUPT_VALID;
1840			*mondo_vec_reg = tmp_mondo_vec;
1841			DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: existing "
1842			    "mapping reg 0x%lx\n", tmp_mondo_vec));
1843		}
1844
1845		sbus_arg->pil = hdlp->ih_pri;
1846
1847		DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr:Alloc sbus_arg "
1848		    "0x%p\n", (void *)sbus_arg));
1849	}
1850
1851	softsp->intr_hndlr_cnt[slot]++;
1852
1853	mutex_exit(&softsp->intr_poll_list_lock);
1854
1855	/*
1856	 * Program the ino vector accordingly.  This MUST be the
1857	 * last thing we do.  Once we program the ino, the device
1858	 * may begin to interrupt. Add this hardware interrupt to
1859	 * the interrupt lists, and get the CPU to target it at.
1860	 */
1861
1862	tmp_mondo_vec |= INTERRUPT_VALID;
1863
1864	DPRINTF(SBUS_INTERRUPT_DEBUG, ("Add intr: Ino 0x%x mapping reg: 0x%p "
1865	    "Intr cntr %d\n", ino, (void *)mondo_vec_reg,
1866	    softsp->intr_hndlr_cnt[slot]));
1867
1868	/* Force the interrupt state machine to idle. */
1869	if (reset_ism_register) {
1870		tmpreg = SBUS_INTR_IDLE;
1871		*sbus_arg->clear_reg = tmpreg;
1872	}
1873
1874	/* Store it in the hardware reg. */
1875	*mondo_vec_reg = tmp_mondo_vec;
1876
1877	/* Flush store buffers */
1878	tmpreg = *softsp->sbus_ctrl_reg;
1879
1880done:
1881	return (ret);
1882}
1883
1884static void
1885sbus_free_handler(dev_info_t *dip, uint32_t inum,
1886    struct sbus_wrapper_arg *sbus_arg)
1887{
1888	struct sbus_intr_handler *listp, *prevp;
1889
1890	if (sbus_arg) {
1891		prevp = NULL;
1892		listp = sbus_arg->handler_list;
1893
1894		while (listp) {
1895			if (listp->dip == dip && listp->inum == inum) {
1896				if (prevp)
1897					prevp->next = listp->next;
1898				else {
1899					prevp = listp->next;
1900					sbus_arg->handler_list = prevp;
1901				}
1902
1903				kmem_free(listp,
1904				    sizeof (struct sbus_intr_handler));
1905				break;
1906			}
1907			prevp = listp;
1908			listp = listp->next;
1909		}
1910	}
1911}
1912
1913/*
1914 * remove_intrspec - Remove an interrupt specification.
1915 */
1916/*ARGSUSED*/
1917static void
1918sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1919    ddi_intr_handle_impl_t *hdlp)
1920{
1921	volatile uint64_t *mondo_vec_reg;
1922	volatile uint64_t *intr_state_reg;
1923#ifndef lint
1924	volatile uint64_t tmpreg;
1925#endif /* !lint */
1926	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
1927	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
1928	int start_bit, ino, slot;
1929	struct sbus_wrapper_arg *sbus_arg;
1930
1931	/* Grab the mutex protecting the poll list */
1932	mutex_enter(&softsp->intr_poll_list_lock);
1933
1934	/* Xlate the interrupt */
1935	if (sbus_xlate_intrs(dip, rdip, (uint32_t *)&hdlp->ih_vector,
1936	    &hdlp->ih_pri, softsp->intr_mapping_ign) == DDI_FAILURE) {
1937		cmn_err(CE_WARN, "Can't xlate SBUS devices %s interrupt.\n",
1938		    ddi_driver_name(rdip));
1939		goto done;
1940	}
1941
1942	ino = ((int32_t)hdlp->ih_vector) & SBUS_MAX_INO;
1943
1944	mondo_vec_reg = (softsp->intr_mapping_reg +
1945	    ino_table[ino]->mapping_reg);
1946
1947	/* Turn off the valid bit in the mapping register. */
1948	*mondo_vec_reg &= ~INTERRUPT_VALID;
1949#ifndef lint
1950	tmpreg = *softsp->sbus_ctrl_reg;
1951#endif /* !lint */
1952
1953	/* Get our bit position for checking intr pending */
1954	if (ino > MAX_MONDO_EXTERNAL) {
1955		start_bit = ino_table[ino]->diagreg_shift;
1956		intr_state_reg = softsp->obio_intr_state;
1957	} else {
1958		start_bit = 16 * (ino >> 3) + 2 * (ino & 0x7);
1959		intr_state_reg = softsp->sbus_intr_state;
1960	}
1961
1962	while (((*intr_state_reg >> start_bit) & 0x3) == INT_PENDING &&
1963	    !panicstr)
1964		/* empty */;
1965
1966	slot = find_sbus_slot(dip, rdip);
1967
1968	/* Return if the slot is invalid */
1969	if (slot >= MAX_SBUS_SLOT_ADDR || slot < 0) {
1970		goto done;
1971	}
1972
1973	sbus_arg = softsp->intr_list[ino];
1974
1975	/* Decrement the intr handler count on this slot */
1976	softsp->intr_hndlr_cnt[slot]--;
1977
1978	DPRINTF(SBUS_INTERRUPT_DEBUG, ("Rem intr: Softsp 0x%p, Mondo 0x%x, "
1979	    "ino 0x%x, sbus_arg 0x%p intr cntr %d\n", (void *)softsp,
1980	    hdlp->ih_vector, ino, (void *)sbus_arg,
1981	    softsp->intr_hndlr_cnt[slot]));
1982
1983	ASSERT(sbus_arg != NULL);
1984	ASSERT(sbus_arg->handler_list != NULL);
1985	sbus_free_handler(rdip, hdlp->ih_inum, sbus_arg);
1986
1987	/* If we still have a list, we're done. */
1988	if (sbus_arg->handler_list == NULL)
1989		i_ddi_rem_ivintr(hdlp);
1990
1991	/*
1992	 * If other devices are still installed for this slot, we need to
1993	 * turn the valid bit back on.
1994	 */
1995	if (softsp->intr_hndlr_cnt[slot] > 0) {
1996		*mondo_vec_reg |= INTERRUPT_VALID;
1997#ifndef lint
1998		tmpreg = *softsp->sbus_ctrl_reg;
1999#endif /* !lint */
2000	}
2001
2002	if ((softsp->intr_hndlr_cnt[slot] == 0) || (slot >= EXT_SBUS_SLOTS)) {
2003		ASSERT(sbus_arg->handler_list == NULL);
2004#ifdef	_STARFIRE
2005		/* Do cleanup for interrupt target translation */
2006		pc_ittrans_cleanup(softsp->ittrans_cookie, mondo_vec_reg);
2007#endif	/* _STARFIRE */
2008	}
2009
2010
2011	/* Free up the memory used for the sbus interrupt handler */
2012	if (sbus_arg->handler_list == NULL) {
2013		DPRINTF(SBUS_INTERRUPT_DEBUG, ("Rem intr: Freeing sbus arg "
2014		    "0x%p\n", (void *)sbus_arg));
2015		kmem_free(sbus_arg, sizeof (struct sbus_wrapper_arg));
2016		softsp->intr_list[ino] = NULL;
2017	}
2018
2019done:
2020	mutex_exit(&softsp->intr_poll_list_lock);
2021}
2022
2023/*
2024 * We're prepared to claim that the interrupt string is in
2025 * the form of a list of <SBusintr> specifications, or we're dealing
2026 * with on-board devices and we have an interrupt_number property which
2027 * gives us our mondo number.
2028 * Translate the sbus levels or mondos into sysiointrspecs.
2029 */
2030static int
2031sbus_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, uint32_t *intr,
2032    uint32_t *pil, int32_t ign)
2033{
2034	uint32_t ino, slot, level = *intr;
2035	int ret = DDI_SUCCESS;
2036
2037	/*
2038	 * Create the sysio ino number.  onboard devices will have
2039	 * an "interrupts" property, that is equal to the ino number.
2040	 * If the devices are from the
2041	 * expansion slots, we construct the ino number by putting
2042	 * the slot number in the upper three bits, and the sbus
2043	 * interrupt level in the lower three bits.
2044	 */
2045	if (level > MAX_SBUS_LEVEL) {
2046		ino = level;
2047	} else {
2048		/* Construct ino from slot and interrupts */
2049		if ((slot = find_sbus_slot(dip, rdip)) == -1) {
2050			cmn_err(CE_WARN, "Can't determine sbus slot "
2051			    "of %s device\n", ddi_driver_name(rdip));
2052			ret = DDI_FAILURE;
2053			goto done;
2054		}
2055
2056		if (slot >= MAX_SBUS_SLOT_ADDR) {
2057			cmn_err(CE_WARN, "Invalid sbus slot 0x%x"
2058			    "in %s device\n", slot, ddi_driver_name(rdip));
2059			ret = DDI_FAILURE;
2060			goto done;
2061		}
2062
2063		ino = slot << 3;
2064		ino |= level;
2065	}
2066
2067	/* Sanity check the inos range */
2068	if (ino >= MAX_INO_TABLE_SIZE) {
2069		cmn_err(CE_WARN, "Ino vector 0x%x out of range", ino);
2070		ret = DDI_FAILURE;
2071		goto done;
2072	}
2073	/* Sanity check the inos value */
2074	if (!ino_table[ino]) {
2075		cmn_err(CE_WARN, "Ino vector 0x%x is invalid", ino);
2076		ret = DDI_FAILURE;
2077		goto done;
2078	}
2079
2080	if (*pil == 0) {
2081#define	SOC_PRIORITY 5
2082		/* The sunfire i/o board has a soc in the printer slot */
2083		if ((ino_table[ino]->clear_reg == PP_CLEAR) &&
2084		    ((strcmp(ddi_get_name(rdip), "soc") == 0) ||
2085		    (strcmp(ddi_get_name(rdip), "SUNW,soc") == 0))) {
2086			*pil = SOC_PRIORITY;
2087		} else {
2088			/* Figure out the pil associated with this interrupt */
2089			*pil = interrupt_priorities[ino];
2090		}
2091	}
2092
2093	/* Or in the upa_id into the interrupt group number field */
2094	*intr = (uint32_t)(ino | ign);
2095
2096	DPRINTF(SBUS_INTERRUPT_DEBUG, ("Xlate intr: Interrupt info for "
2097	    "device %s Mondo: 0x%x, ino: 0x%x, Pil: 0x%x, sbus level: 0x%x\n",
2098	    ddi_driver_name(rdip), *intr, ino, *pil, level));
2099
2100done:
2101	return (ret);
2102}
2103
2104/* new intr_ops structure */
2105int
2106sbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
2107    ddi_intr_handle_impl_t *hdlp, void *result)
2108{
2109	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
2110	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
2111	int			ret = DDI_SUCCESS;
2112
2113
2114	switch (intr_op) {
2115	case DDI_INTROP_GETCAP:
2116		*(int *)result = DDI_INTR_FLAG_LEVEL;
2117		break;
2118	case DDI_INTROP_ALLOC:
2119		*(int *)result = hdlp->ih_scratch1;
2120		break;
2121	case DDI_INTROP_FREE:
2122		break;
2123	case DDI_INTROP_GETPRI:
2124		if (hdlp->ih_pri == 0) {
2125			/* Xlate the interrupt */
2126			(void) sbus_xlate_intrs(dip, rdip,
2127			    (uint32_t *)&hdlp->ih_vector, &hdlp->ih_pri,
2128			    softsp->intr_mapping_ign);
2129		}
2130
2131		*(int *)result = hdlp->ih_pri;
2132		break;
2133	case DDI_INTROP_SETPRI:
2134		break;
2135	case DDI_INTROP_ADDISR:
2136		ret = sbus_add_intr_impl(dip, rdip, hdlp);
2137		break;
2138	case DDI_INTROP_REMISR:
2139		sbus_remove_intr_impl(dip, rdip, hdlp);
2140		break;
2141	case DDI_INTROP_ENABLE:
2142		ret = sbus_update_intr_state(dip, rdip, hdlp,
2143		    SBUS_INTR_STATE_ENABLE);
2144		break;
2145	case DDI_INTROP_DISABLE:
2146		ret = sbus_update_intr_state(dip, rdip, hdlp,
2147		    SBUS_INTR_STATE_DISABLE);
2148		break;
2149	case DDI_INTROP_NINTRS:
2150	case DDI_INTROP_NAVAIL:
2151		*(int *)result = i_ddi_get_intx_nintrs(rdip);
2152		break;
2153	case DDI_INTROP_SETCAP:
2154	case DDI_INTROP_SETMASK:
2155	case DDI_INTROP_CLRMASK:
2156	case DDI_INTROP_GETPENDING:
2157		ret = DDI_ENOTSUP;
2158		break;
2159	case DDI_INTROP_SUPPORTED_TYPES:
2160		/* Sbus nexus driver supports only fixed interrupts */
2161		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
2162		    DDI_INTR_TYPE_FIXED : 0;
2163		break;
2164	default:
2165		ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
2166		break;
2167	}
2168
2169	return (ret);
2170}
2171
2172
2173/*
2174 * Called by suspend/resume to save/restore the interrupt status (valid bit)
2175 * of the interrupt mapping registers.
2176 */
2177static void
2178sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr,
2179    int save)
2180{
2181	int i;
2182	volatile uint64_t *mondo_vec_reg;
2183
2184	for (i = 0; i < MAX_INO_TABLE_SIZE; i++) {
2185		if (ino_table[i] != NULL) {
2186			mondo_vec_reg = baddr + ino_table[i]->mapping_reg;
2187			if (save) {
2188				if (*mondo_vec_reg & INTERRUPT_VALID) {
2189					cpr_softsp[i] = *mondo_vec_reg;
2190				}
2191			} else {
2192				if (cpr_softsp[i]) {
2193					*mondo_vec_reg = cpr_softsp[i];
2194				}
2195			}
2196		}
2197	}
2198}
2199
2200#define	SZ_INO_TABLE (sizeof (ino_table) / sizeof (ino_table[0]))
2201
2202/*
2203 * sbus_intrdist
2204 *
2205 * This function retargets active interrupts by reprogramming the mondo
2206 * vec register. If the CPU ID of the target has not changed, then
2207 * the mondo is not reprogrammed. The routine must hold the mondo
2208 * lock for this instance of the sbus.
2209 */
2210static void
2211sbus_intrdist(void *arg)
2212{
2213	struct sbus_soft_state *softsp;
2214	dev_info_t *dip = (dev_info_t *)arg;
2215	volatile uint64_t *mondo_vec_reg;
2216	uint64_t *last_mondo_vec_reg;
2217	uint64_t mondo_vec;
2218	volatile uint64_t *intr_state_reg;
2219	uint_t start_bit;
2220	volatile uint64_t tmpreg; /* HW flush reg */
2221	uint_t mondo;
2222	uint_t cpu_id;
2223
2224	/* extract the soft state pointer */
2225	softsp = ddi_get_soft_state(sbusp, ddi_get_instance(dip));
2226
2227	last_mondo_vec_reg = NULL;
2228	for (mondo = 0; mondo < SZ_INO_TABLE; mondo++) {
2229		if (ino_table[mondo] == NULL)
2230			continue;
2231
2232		mondo_vec_reg = (softsp->intr_mapping_reg +
2233		    ino_table[mondo]->mapping_reg);
2234
2235		/* Don't reprogram the same register twice */
2236		if (mondo_vec_reg == last_mondo_vec_reg)
2237			continue;
2238
2239		if ((*mondo_vec_reg & INTERRUPT_VALID) == 0)
2240			continue;
2241
2242		last_mondo_vec_reg = (uint64_t *)mondo_vec_reg;
2243
2244		cpu_id = intr_dist_cpuid();
2245#ifdef _STARFIRE
2246		/*
2247		 * For Starfire it is a pain to check the current target for
2248		 * the mondo since we have to read the PC asics ITTR slot
2249		 * assigned to this mondo. It will be much easier to assume
2250		 * the current target is always different and do the target
2251		 * reprogram all the time.
2252		 */
2253#else
2254		if (((*mondo_vec_reg & IMR_TID) >> IMR_TID_SHIFT) == cpu_id) {
2255			/* It is the same, don't reprogram */
2256			return;
2257		}
2258#endif	/* _STARFIRE */
2259
2260		/* So it's OK to reprogram the CPU target */
2261
2262		/* turn off valid bit and wait for the state machine to idle */
2263		*mondo_vec_reg &= ~INTERRUPT_VALID;
2264
2265		tmpreg = *softsp->sbus_ctrl_reg;
2266
2267#ifdef	lint
2268		tmpreg = tmpreg;
2269#endif	/* lint */
2270
2271		if (mondo > MAX_MONDO_EXTERNAL) {
2272			start_bit = ino_table[mondo]->diagreg_shift;
2273			intr_state_reg = softsp->obio_intr_state;
2274
2275			/*
2276			 * Loop waiting for state machine to idle. Do not keep
2277			 * looping on a panic so that the system does not hang.
2278			 */
2279			while ((((*intr_state_reg >> start_bit) & 0x3) ==
2280			    INT_PENDING) && !panicstr)
2281				/* empty */;
2282		} else {
2283			int int_pending = 0;	/* interrupts pending */
2284
2285			/*
2286			 * Shift over to first bit for this Sbus slot, 16
2287			 * bits per slot, bits 0-1 of each slot are reserved.
2288			 */
2289			start_bit = 16 * (mondo >> 3) + 2;
2290			intr_state_reg = softsp->sbus_intr_state;
2291
2292			/*
2293			 * Make sure interrupts for levels 1-7 of this slot
2294			 * are not pending.
2295			 */
2296			do {
2297				int level;	/* Sbus interrupt level */
2298				int shift;		/* # of bits to shift */
2299				uint64_t state_reg = *intr_state_reg;
2300
2301				int_pending = 0;
2302
2303				for (shift = start_bit, level = 1; level < 8;
2304				    level++, shift += 2) {
2305					if (((state_reg >> shift) &
2306					    0x3) == INT_PENDING) {
2307						int_pending = 1;
2308						break;
2309					}
2310				}
2311			} while (int_pending && !panicstr);
2312		}
2313
2314		/* re-target the mondo and turn it on */
2315#ifdef _STARFIRE
2316		mondo_vec = (pc_translate_tgtid(softsp->ittrans_cookie,
2317		    cpu_id, mondo_vec_reg) <<
2318		    INTERRUPT_CPU_FIELD) |
2319		    INTERRUPT_VALID;
2320#else
2321		mondo_vec = (cpu_id << INTERRUPT_CPU_FIELD) | INTERRUPT_VALID;
2322#endif	/* _STARFIRE */
2323
2324		/* write it back to the hardware. */
2325		*mondo_vec_reg = mondo_vec;
2326
2327		/* flush the hardware buffers. */
2328		tmpreg = *mondo_vec_reg;
2329
2330#ifdef	lint
2331		tmpreg = tmpreg;
2332#endif	/* lint */
2333	}
2334}
2335
2336/*
2337 * Reset interrupts to IDLE.  This function is called during
2338 * panic handling after redistributing interrupts; it's needed to
2339 * support dumping to network devices after 'sync' from OBP.
2340 *
2341 * N.B.  This routine runs in a context where all other threads
2342 * are permanently suspended.
2343 */
2344static uint_t
2345sbus_intr_reset(void *arg)
2346{
2347	dev_info_t *dip = (dev_info_t *)arg;
2348	struct sbus_soft_state *softsp;
2349	uint_t mondo;
2350	volatile uint64_t *mondo_clear_reg;
2351
2352	softsp = ddi_get_soft_state(sbusp, ddi_get_instance(dip));
2353
2354	for (mondo = 0; mondo < SZ_INO_TABLE; mondo++) {
2355		if (ino_table[mondo] == NULL ||
2356		    ino_table[mondo]->clear_reg == NULL) {
2357
2358			continue;
2359		}
2360
2361		mondo_clear_reg = (softsp->clr_intr_reg +
2362		    ino_table[mondo]->clear_reg);
2363		*mondo_clear_reg = SBUS_INTR_IDLE;
2364	}
2365
2366	return (BF_NONE);
2367}
2368
2369/*
2370 * called from sbus_add_kstats() to create a kstat for each %pic
2371 * that the SBUS supports. These (read-only) kstats export the
2372 * event names that each %pic supports.
2373 *
2374 * if we fail to create any of these kstats we must remove any
2375 * that we have already created and return;
2376 *
2377 * NOTE: because all sbus devices use the same events we only
2378 *	 need to create the picN kstats once. All instances can
2379 *	 use the same picN kstats.
2380 *
2381 *       The flexibility exists to allow each device specify it's
2382 *       own events by creating picN kstats with the instance number
2383 *       set to ddi_get_instance(softsp->dip).
2384 *
2385 *       When searching for a picN kstat for a device you should
2386 *       first search for a picN kstat using the instance number
2387 *       of the device you are interested in. If that fails you
2388 *       should use the first picN kstat found for that device.
2389 */
2390static	void
2391sbus_add_picN_kstats(dev_info_t *dip)
2392{
2393	/*
2394	 * SBUS Performance Events.
2395	 *
2396	 * We declare an array of event-names and event-masks.
2397	 * The num of events in this array is AC_NUM_EVENTS.
2398	 */
2399	sbus_event_mask_t sbus_events_arr[SBUS_NUM_EVENTS] = {
2400		{"dvma_stream_rd", 0x0}, {"dvma_stream_wr", 0x1},
2401		{"dvma_const_rd", 0x2}, {"dvma_const_wr", 0x3},
2402		{"dvma_tlb_misses", 0x4}, {"dvma_stream_buf_mis", 0x5},
2403		{"dvma_cycles", 0x6}, {"dvma_bytes_xfr", 0x7},
2404		{"interrupts", 0x8}, {"upa_inter_nack", 0x9},
2405		{"pio_reads", 0xA}, {"pio_writes", 0xB},
2406		{"sbus_reruns", 0xC}, {"pio_cycles", 0xD}
2407	};
2408
2409	/*
2410	 * We declare an array of clear masks for each pic.
2411	 * These masks are used to clear the %pcr bits for
2412	 * each pic.
2413	 */
2414	sbus_event_mask_t sbus_clear_pic[SBUS_NUM_PICS] = {
2415		/* pic0 */
2416		{"clear_pic", (uint64_t)~(0xf)},
2417		/* pic1 */
2418		{"clear_pic", (uint64_t)~(0xf << 8)}
2419	};
2420
2421	struct kstat_named *sbus_pic_named_data;
2422	int  		event, pic;
2423	char 		pic_name[30];
2424	int		instance = ddi_get_instance(dip);
2425	int		pic_shift = 0;
2426
2427	for (pic = 0; pic < SBUS_NUM_PICS; pic++) {
2428		/*
2429		 * create the picN kstat. The size of this kstat is
2430		 * SBUS_NUM_EVENTS + 1 for the clear_event_mask
2431		 */
2432		(void) sprintf(pic_name, "pic%d", pic);	/* pic0, pic1 ... */
2433		if ((sbus_picN_ksp[pic] = kstat_create("sbus",
2434		    instance, pic_name, "bus", KSTAT_TYPE_NAMED,
2435		    SBUS_NUM_EVENTS + 1, NULL)) == NULL) {
2436				cmn_err(CE_WARN, "sbus %s: kstat_create failed",
2437				    pic_name);
2438
2439			/* remove pic0 kstat if pic1 create fails */
2440			if (pic == 1) {
2441				kstat_delete(sbus_picN_ksp[0]);
2442				sbus_picN_ksp[0] = NULL;
2443			}
2444			return;
2445		}
2446
2447		sbus_pic_named_data =
2448		    (struct kstat_named *)(sbus_picN_ksp[pic]->ks_data);
2449
2450		/*
2451		 * when we are writing pcr_masks to the kstat we need to
2452		 * shift bits left by 8 for pic1 events.
2453		 */
2454		if (pic == 1)
2455			pic_shift = 8;
2456
2457		/*
2458		 * for each picN event we need to write a kstat record
2459		 * (name = EVENT, value.ui64 = PCR_MASK)
2460		 */
2461		for (event = 0; event < SBUS_NUM_EVENTS; event ++) {
2462
2463			/* pcr_mask */
2464			sbus_pic_named_data[event].value.ui64 =
2465			    sbus_events_arr[event].pcr_mask << pic_shift;
2466
2467			/* event-name */
2468			kstat_named_init(&sbus_pic_named_data[event],
2469			    sbus_events_arr[event].event_name,
2470			    KSTAT_DATA_UINT64);
2471		}
2472
2473		/*
2474		 * we add the clear_pic event and mask as the last
2475		 * record in the kstat
2476		 */
2477		/* pcr mask */
2478		sbus_pic_named_data[SBUS_NUM_EVENTS].value.ui64 =
2479		    sbus_clear_pic[pic].pcr_mask;
2480
2481		/* event-name */
2482		kstat_named_init(&sbus_pic_named_data[SBUS_NUM_EVENTS],
2483		    sbus_clear_pic[pic].event_name,
2484		    KSTAT_DATA_UINT64);
2485
2486		kstat_install(sbus_picN_ksp[pic]);
2487	}
2488}
2489
2490static	void
2491sbus_add_kstats(struct sbus_soft_state *softsp)
2492{
2493	struct kstat *sbus_counters_ksp;
2494	struct kstat_named *sbus_counters_named_data;
2495
2496	/*
2497	 * Create the picN kstats if we are the first instance
2498	 * to attach. We use sbus_attachcnt as a count of how
2499	 * many instances have attached. This is protected by
2500	 * a mutex.
2501	 */
2502	mutex_enter(&sbus_attachcnt_mutex);
2503	if (sbus_attachcnt == 0)
2504		sbus_add_picN_kstats(softsp->dip);
2505
2506	sbus_attachcnt ++;
2507	mutex_exit(&sbus_attachcnt_mutex);
2508
2509	/*
2510	 * A "counter" kstat is created for each sbus
2511	 * instance that provides access to the %pcr and %pic
2512	 * registers for that instance.
2513	 *
2514	 * The size of this kstat is SBUS_NUM_PICS + 1 for %pcr
2515	 */
2516	if ((sbus_counters_ksp = kstat_create("sbus",
2517	    ddi_get_instance(softsp->dip), "counters",
2518	    "bus", KSTAT_TYPE_NAMED, SBUS_NUM_PICS + 1,
2519	    KSTAT_FLAG_WRITABLE)) == NULL) {
2520
2521			cmn_err(CE_WARN, "sbus%d counters: kstat_create"
2522			    " failed", ddi_get_instance(softsp->dip));
2523		return;
2524	}
2525
2526	sbus_counters_named_data =
2527	    (struct kstat_named *)(sbus_counters_ksp->ks_data);
2528
2529	/* initialize the named kstats */
2530	kstat_named_init(&sbus_counters_named_data[0],
2531	    "pcr", KSTAT_DATA_UINT64);
2532
2533	kstat_named_init(&sbus_counters_named_data[1],
2534	    "pic0", KSTAT_DATA_UINT64);
2535
2536	kstat_named_init(&sbus_counters_named_data[2],
2537	    "pic1", KSTAT_DATA_UINT64);
2538
2539	sbus_counters_ksp->ks_update = sbus_counters_kstat_update;
2540	sbus_counters_ksp->ks_private = (void *)softsp;
2541
2542	kstat_install(sbus_counters_ksp);
2543
2544	/* update the sofstate */
2545	softsp->sbus_counters_ksp = sbus_counters_ksp;
2546}
2547
2548static	int
2549sbus_counters_kstat_update(kstat_t *ksp, int rw)
2550{
2551	struct kstat_named *sbus_counters_data;
2552	struct sbus_soft_state *softsp;
2553	uint64_t pic_register;
2554
2555	sbus_counters_data = (struct kstat_named *)ksp->ks_data;
2556	softsp = (struct sbus_soft_state *)ksp->ks_private;
2557
2558	if (rw == KSTAT_WRITE) {
2559
2560		/*
2561		 * Write the pcr value to the softsp->sbus_pcr.
2562		 * The pic register is read-only so we don't
2563		 * attempt to write to it.
2564		 */
2565
2566		*softsp->sbus_pcr =
2567		    (uint32_t)sbus_counters_data[0].value.ui64;
2568
2569	} else {
2570		/*
2571		 * Read %pcr and %pic register values and write them
2572		 * into counters kstat.
2573		 *
2574		 * Due to a hardware bug we need to right shift the %pcr
2575		 * by 4 bits. This is only done when reading the %pcr.
2576		 *
2577		 */
2578		/* pcr */
2579		sbus_counters_data[0].value.ui64 = *softsp->sbus_pcr >> 4;
2580
2581		pic_register = *softsp->sbus_pic;
2582		/*
2583		 * sbus pic register:
2584		 *  (63:32) = pic0
2585		 *  (31:00) = pic1
2586		 */
2587
2588		/* pic0 */
2589		sbus_counters_data[1].value.ui64 = pic_register >> 32;
2590		/* pic1 */
2591		sbus_counters_data[2].value.ui64 =
2592		    pic_register & SBUS_PIC0_MASK;
2593
2594	}
2595	return (0);
2596}
2597
2598static int
2599sbus_update_intr_state(dev_info_t *dip, dev_info_t *rdip,
2600    ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state)
2601{
2602	struct sbus_soft_state *softsp = (struct sbus_soft_state *)
2603	    ddi_get_soft_state(sbusp, ddi_get_instance(dip));
2604	int ino;
2605	struct sbus_wrapper_arg *sbus_arg;
2606	struct sbus_intr_handler *intr_handler;
2607
2608	/* Xlate the interrupt */
2609	if (sbus_xlate_intrs(dip, rdip, (uint32_t *)&hdlp->ih_vector,
2610	    &hdlp->ih_pri, softsp->intr_mapping_ign) == DDI_FAILURE) {
2611		cmn_err(CE_WARN, "sbus_update_intr_state() can't xlate SBUS "
2612		    "devices %s interrupt.", ddi_driver_name(rdip));
2613		return (DDI_FAILURE);
2614	}
2615
2616	ino = ((int32_t)hdlp->ih_vector) & SBUS_MAX_INO;
2617	sbus_arg = softsp->intr_list[ino];
2618
2619	ASSERT(sbus_arg != NULL);
2620	ASSERT(sbus_arg->handler_list != NULL);
2621	intr_handler = sbus_arg->handler_list;
2622
2623	while (intr_handler) {
2624		if ((intr_handler->inum == hdlp->ih_inum) &&
2625		    (intr_handler->dip == rdip)) {
2626			intr_handler->intr_state = new_intr_state;
2627			return (DDI_SUCCESS);
2628		}
2629
2630		intr_handler = intr_handler->next;
2631	}
2632
2633	return (DDI_FAILURE);
2634}
2635