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