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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
30 #include <sys/types.h>
33 #include <sys/sunddi.h>
34 #include <sys/sunndi.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/ddi_implfuncs.h>
37 #include <sys/obpdefs.h>
38 #include <sys/cmn_err.h>
39 #include <sys/errno.h>
41 #include <sys/debug.h>
42 #include <sys/sysmacros.h>
43 #include <sys/autoconf.h>
45 #include <sys/iommu.h>
46 #include <sys/sysiosbus.h>
47 #include <sys/sysioerr.h>
48 #include <sys/iocache.h>
49 #include <sys/async.h>
50 #include <sys/machsystm.h>
51 #include <sys/intreg.h>
52 #include <sys/ddi_subrdefs.h>
54 #include <sys/starfire.h>
55 #endif /* _STARFIRE */
58 /* Useful debugging Stuff */
59 #include <sys/nexusdebug.h>
60 /* Bitfield debugging definitions for this file */
61 #define SBUS_ATTACH_DEBUG 0x1
62 #define SBUS_SBUSMEM_DEBUG 0x2
63 #define SBUS_INTERRUPT_DEBUG 0x4
64 #define SBUS_REGISTERS_DEBUG 0x8
67 * Interrupt registers table.
68 * This table is necessary due to inconsistencies in the sysio register
69 * layout. If this gets fixed in the chip, we can get rid of this stupid
72 static struct sbus_slot_entry ino_1
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
73 SBUS_SLOT0_L1_CLEAR
, NULL
};
74 static struct sbus_slot_entry ino_2
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
75 SBUS_SLOT0_L2_CLEAR
, NULL
};
76 static struct sbus_slot_entry ino_3
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
77 SBUS_SLOT0_L3_CLEAR
, NULL
};
78 static struct sbus_slot_entry ino_4
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
79 SBUS_SLOT0_L4_CLEAR
, NULL
};
80 static struct sbus_slot_entry ino_5
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
81 SBUS_SLOT0_L5_CLEAR
, NULL
};
82 static struct sbus_slot_entry ino_6
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
83 SBUS_SLOT0_L6_CLEAR
, NULL
};
84 static struct sbus_slot_entry ino_7
= {SBUS_SLOT0_CONFIG
, SBUS_SLOT0_MAPREG
,
85 SBUS_SLOT0_L7_CLEAR
, NULL
};
86 static struct sbus_slot_entry ino_9
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
87 SBUS_SLOT1_L1_CLEAR
, NULL
};
88 static struct sbus_slot_entry ino_10
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
89 SBUS_SLOT1_L2_CLEAR
, NULL
};
90 static struct sbus_slot_entry ino_11
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
91 SBUS_SLOT1_L3_CLEAR
, NULL
};
92 static struct sbus_slot_entry ino_12
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
93 SBUS_SLOT1_L4_CLEAR
, NULL
};
94 static struct sbus_slot_entry ino_13
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
95 SBUS_SLOT1_L5_CLEAR
, NULL
};
96 static struct sbus_slot_entry ino_14
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
97 SBUS_SLOT1_L6_CLEAR
, NULL
};
98 static struct sbus_slot_entry ino_15
= {SBUS_SLOT1_CONFIG
, SBUS_SLOT1_MAPREG
,
99 SBUS_SLOT1_L7_CLEAR
, NULL
};
100 static struct sbus_slot_entry ino_17
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
101 SBUS_SLOT2_L1_CLEAR
, NULL
};
102 static struct sbus_slot_entry ino_18
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
103 SBUS_SLOT2_L2_CLEAR
, NULL
};
104 static struct sbus_slot_entry ino_19
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
105 SBUS_SLOT2_L3_CLEAR
, NULL
};
106 static struct sbus_slot_entry ino_20
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
107 SBUS_SLOT2_L4_CLEAR
, NULL
};
108 static struct sbus_slot_entry ino_21
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
109 SBUS_SLOT2_L5_CLEAR
, NULL
};
110 static struct sbus_slot_entry ino_22
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
111 SBUS_SLOT2_L6_CLEAR
, NULL
};
112 static struct sbus_slot_entry ino_23
= {SBUS_SLOT2_CONFIG
, SBUS_SLOT2_MAPREG
,
113 SBUS_SLOT2_L7_CLEAR
, NULL
};
114 static struct sbus_slot_entry ino_25
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
115 SBUS_SLOT3_L1_CLEAR
, NULL
};
116 static struct sbus_slot_entry ino_26
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
117 SBUS_SLOT3_L2_CLEAR
, NULL
};
118 static struct sbus_slot_entry ino_27
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
119 SBUS_SLOT3_L3_CLEAR
, NULL
};
120 static struct sbus_slot_entry ino_28
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
121 SBUS_SLOT3_L4_CLEAR
, NULL
};
122 static struct sbus_slot_entry ino_29
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
123 SBUS_SLOT3_L5_CLEAR
, NULL
};
124 static struct sbus_slot_entry ino_30
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
125 SBUS_SLOT3_L6_CLEAR
, NULL
};
126 static struct sbus_slot_entry ino_31
= {SBUS_SLOT3_CONFIG
, SBUS_SLOT3_MAPREG
,
127 SBUS_SLOT3_L7_CLEAR
, NULL
};
128 static struct sbus_slot_entry ino_32
= {SBUS_SLOT5_CONFIG
, ESP_MAPREG
,
129 ESP_CLEAR
, ESP_INTR_STATE_SHIFT
};
130 static struct sbus_slot_entry ino_33
= {SBUS_SLOT5_CONFIG
, ETHER_MAPREG
,
131 ETHER_CLEAR
, ETHER_INTR_STATE_SHIFT
};
132 static struct sbus_slot_entry ino_34
= {SBUS_SLOT5_CONFIG
, PP_MAPREG
,
133 PP_CLEAR
, PP_INTR_STATE_SHIFT
};
134 static struct sbus_slot_entry ino_36
= {SBUS_SLOT4_CONFIG
, AUDIO_MAPREG
,
135 AUDIO_CLEAR
, AUDIO_INTR_STATE_SHIFT
};
136 static struct sbus_slot_entry ino_40
= {SBUS_SLOT6_CONFIG
, KBDMOUSE_MAPREG
,
138 KBDMOUSE_INTR_STATE_SHIFT
};
139 static struct sbus_slot_entry ino_41
= {SBUS_SLOT6_CONFIG
, FLOPPY_MAPREG
,
140 FLOPPY_CLEAR
, FLOPPY_INTR_STATE_SHIFT
};
141 static struct sbus_slot_entry ino_42
= {SBUS_SLOT6_CONFIG
, THERMAL_MAPREG
,
143 THERMAL_INTR_STATE_SHIFT
};
144 static struct sbus_slot_entry ino_48
= {SBUS_SLOT6_CONFIG
, TIMER0_MAPREG
,
145 TIMER0_CLEAR
, TIMER0_INTR_STATE_SHIFT
};
146 static struct sbus_slot_entry ino_49
= {SBUS_SLOT6_CONFIG
, TIMER1_MAPREG
,
147 TIMER1_CLEAR
, TIMER1_INTR_STATE_SHIFT
};
148 static struct sbus_slot_entry ino_52
= {SBUS_SLOT6_CONFIG
, UE_ECC_MAPREG
,
149 UE_ECC_CLEAR
, UE_INTR_STATE_SHIFT
};
150 static struct sbus_slot_entry ino_53
= {SBUS_SLOT6_CONFIG
, CE_ECC_MAPREG
,
151 CE_ECC_CLEAR
, CE_INTR_STATE_SHIFT
};
152 static struct sbus_slot_entry ino_54
= {SBUS_SLOT6_CONFIG
, SBUS_ERR_MAPREG
,
153 SBUS_ERR_CLEAR
, SERR_INTR_STATE_SHIFT
};
154 static struct sbus_slot_entry ino_55
= {SBUS_SLOT6_CONFIG
, PM_WAKEUP_MAPREG
,
155 PM_WAKEUP_CLEAR
, PM_INTR_STATE_SHIFT
};
156 static struct sbus_slot_entry ino_ffb
= {NULL
, FFB_MAPPING_REG
, NULL
, NULL
};
157 static struct sbus_slot_entry ino_exp
= {NULL
, EXP_MAPPING_REG
, NULL
, NULL
};
159 /* Construct the interrupt number array */
160 struct sbus_slot_entry
*ino_table
[] = {
161 NULL
, &ino_1
, &ino_2
, &ino_3
, &ino_4
, &ino_5
, &ino_6
, &ino_7
,
162 NULL
, &ino_9
, &ino_10
, &ino_11
, &ino_12
, &ino_13
, &ino_14
, &ino_15
,
163 NULL
, &ino_17
, &ino_18
, &ino_19
, &ino_20
, &ino_21
, &ino_22
, &ino_23
,
164 NULL
, &ino_25
, &ino_26
, &ino_27
, &ino_28
, &ino_29
, &ino_30
, &ino_31
,
165 &ino_32
, &ino_33
, &ino_34
, NULL
, &ino_36
, NULL
, NULL
, NULL
,
166 &ino_40
, &ino_41
, &ino_42
, NULL
, NULL
, NULL
, NULL
, NULL
, &ino_48
,
167 &ino_49
, NULL
, NULL
, &ino_52
, &ino_53
, &ino_54
, &ino_55
, &ino_ffb
,
172 * This table represents the Fusion interrupt priorities. They range
173 * from 1 - 15, so we'll pattern the priorities after the 4M. We map Fusion
174 * interrupt number to system priority. The mondo number is used as an
175 * index into this table.
177 int interrupt_priorities
[] = {
178 -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 0 sbus level 1 - 7 */
179 -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 1 sbus level 1 - 7 */
180 -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 2 sbus level 1 - 7 */
181 -1, 2, 3, 5, 7, 9, 11, 13, /* Slot 3 sbus level 1 - 7 */
182 4, /* Onboard SCSI */
183 6, /* Onboard Ethernet */
184 3, /* Onboard Parallel port */
186 9, /* Onboard Audio */
187 -1, -1, -1, /* Not in use */
188 12, /* Onboard keyboard/serial ports */
189 11, /* Onboard Floppy */
190 9, /* Thermal interrupt */
191 -1, -1, -1, /* Not is use */
192 10, /* Timer 0 (tick timer) */
193 14, /* Timer 1 (not used) */
194 15, /* Sysio UE ECC error */
195 10, /* Sysio CE ECC error */
196 10, /* Sysio Sbus error */
200 /* Interrupt counter flag. To enable/disable spurious interrupt counter. */
201 static int intr_cntr_on
;
204 * Function prototypes.
207 sbus_ctlops(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *, void *);
210 sbus_add_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
211 ddi_intr_handle_impl_t
*hdlp
);
214 sbus_remove_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
215 ddi_intr_handle_impl_t
*hdlp
);
218 sbus_intr_ops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
219 ddi_intr_handle_impl_t
*hdlp
, void *result
);
222 sbus_xlate_intrs(dev_info_t
*dip
, dev_info_t
*rdip
, uint32_t *intr
,
223 uint32_t *pil
, int32_t ign
);
226 sbus_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
);
229 sbus_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
);
232 sbus_do_detach(dev_info_t
*devi
);
235 sbus_add_picN_kstats(dev_info_t
*dip
);
238 sbus_add_kstats(struct sbus_soft_state
*);
241 sbus_counters_kstat_update(kstat_t
*, int);
244 sysio_err_uninit(struct sbus_soft_state
*softsp
);
247 iommu_uninit(struct sbus_soft_state
*softsp
);
250 stream_buf_uninit(struct sbus_soft_state
*softsp
);
253 find_sbus_slot(dev_info_t
*dip
, dev_info_t
*rdip
);
255 static void make_sbus_ppd(dev_info_t
*child
);
258 sbusmem_initchild(dev_info_t
*dip
, dev_info_t
*child
);
261 sbus_initchild(dev_info_t
*dip
, dev_info_t
*child
);
264 sbus_uninitchild(dev_info_t
*dip
);
267 sbus_ctlops_poke(struct sbus_soft_state
*softsp
, peekpoke_ctlops_t
*in_args
);
270 sbus_ctlops_peek(struct sbus_soft_state
*softsp
, peekpoke_ctlops_t
*in_args
,
274 sbus_init(struct sbus_soft_state
*softsp
, caddr_t address
);
277 sbus_resume_init(struct sbus_soft_state
*softsp
, int resume
);
280 sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp
, volatile uint64_t *baddr
,
283 static void sbus_intrdist(void *);
284 static uint_t
sbus_intr_reset(void *);
287 sbus_update_intr_state(dev_info_t
*dip
, dev_info_t
*rdip
,
288 ddi_intr_handle_impl_t
*hdlp
, uint_t new_intr_state
);
292 pc_ittrans_init(int, caddr_t
*);
295 pc_ittrans_uninit(caddr_t
);
298 pc_translate_tgtid(caddr_t
, int, volatile uint64_t *);
301 pc_ittrans_cleanup(caddr_t
, volatile uint64_t *);
302 #endif /* _STARFIRE */
305 * Configuration data structures
307 static struct bus_ops sbus_bus_ops
= {
324 0, /* (*bus_get_eventcookie)(); */
325 0, /* (*bus_add_eventcall)(); */
326 0, /* (*bus_remove_eventcall)(); */
327 0, /* (*bus_post_event)(); */
328 0, /* (*bus_intr_control)(); */
329 0, /* (*bus_config)(); */
330 0, /* (*bus_unconfig)(); */
331 0, /* (*bus_fm_init)(); */
332 0, /* (*bus_fm_fini)(); */
333 0, /* (*bus_fm_access_enter)(); */
334 0, /* (*bus_fm_access_exit)(); */
335 0, /* (*bus_power)(); */
336 sbus_intr_ops
/* (*bus_intr_op)(); */
339 static struct cb_ops sbus_cb_ops
= {
342 nodev
, /* strategy */
352 ddi_prop_op
, /* prop_op */
354 D_NEW
| D_MP
| D_HOTPLUG
,
356 nodev
, /* int (*cb_aread)() */
357 nodev
/* int (*cb_awrite)() */
360 static struct dev_ops sbus_ops
= {
361 DEVO_REV
, /* devo_rev, */
363 ddi_no_info
, /* info */
364 nulldev
, /* identify */
366 sbus_attach
, /* attach */
367 sbus_detach
, /* detach */
369 &sbus_cb_ops
, /* driver operations */
370 &sbus_bus_ops
, /* bus operations */
372 ddi_quiesce_not_supported
, /* devo_quiesce */
376 void *sbusp
; /* sbus soft state hook */
377 void *sbus_cprp
; /* subs suspend/resume soft state hook */
378 static kstat_t
*sbus_picN_ksp
[SBUS_NUM_PICS
]; /* performance picN kstats */
379 static int sbus_attachcnt
= 0; /* number of instances attached */
380 static kmutex_t sbus_attachcnt_mutex
; /* sbus_attachcnt lock - attach/detach */
382 #include <sys/modctl.h>
383 extern struct mod_ops mod_driverops
;
385 static struct modldrv modldrv
= {
386 &mod_driverops
, /* Type of module. This one is a driver */
387 "SBus (sysio) nexus driver", /* Name of module. */
388 &sbus_ops
, /* driver ops */
391 static struct modlinkage modlinkage
= {
392 MODREV_1
, (void *)&modldrv
, NULL
396 * These are the module initialization routines.
403 if ((error
= ddi_soft_state_init(&sbusp
,
404 sizeof (struct sbus_soft_state
), 1)) != 0)
408 * Initialize cpr soft state structure
410 if ((error
= ddi_soft_state_init(&sbus_cprp
,
411 sizeof (uint64_t) * MAX_INO_TABLE_SIZE
, 0)) != 0)
414 /* Initialize global mutex */
415 mutex_init(&sbus_attachcnt_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
417 return (mod_install(&modlinkage
));
425 if ((error
= mod_remove(&modlinkage
)) != 0)
428 mutex_destroy(&sbus_attachcnt_mutex
);
429 ddi_soft_state_fini(&sbusp
);
430 ddi_soft_state_fini(&sbus_cprp
);
435 _info(struct modinfo
*modinfop
)
437 return (mod_info(&modlinkage
, modinfop
));
442 sbus_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
444 struct sbus_soft_state
*softsp
;
446 uint64_t *cpr_softsp
;
447 ddi_device_acc_attr_t attr
;
452 debug_print_level
= 0;
455 instance
= ddi_get_instance(devi
);
462 softsp
= ddi_get_soft_state(sbusp
, instance
);
464 if ((error
= iommu_resume_init(softsp
)) != DDI_SUCCESS
)
467 if ((error
= sbus_resume_init(softsp
, 1)) != DDI_SUCCESS
)
470 if ((error
= stream_buf_resume_init(softsp
)) != DDI_SUCCESS
)
474 * Restore Interrupt Mapping registers
476 cpr_softsp
= ddi_get_soft_state(sbus_cprp
, instance
);
478 if (cpr_softsp
!= NULL
) {
479 sbus_cpr_handle_intr_map_reg(cpr_softsp
,
480 softsp
->intr_mapping_reg
, 0);
481 ddi_soft_state_free(sbus_cprp
, instance
);
484 return (DDI_SUCCESS
);
487 return (DDI_FAILURE
);
490 if (ddi_soft_state_zalloc(sbusp
, instance
) != DDI_SUCCESS
)
491 return (DDI_FAILURE
);
493 softsp
= ddi_get_soft_state(sbusp
, instance
);
495 /* Set the dip in the soft state */
498 if ((softsp
->upa_id
= (int)ddi_getprop(DDI_DEV_T_ANY
, softsp
->dip
,
499 DDI_PROP_DONTPASS
, "upa-portid", -1)) == -1) {
500 cmn_err(CE_WARN
, "Unable to retrieve sbus upa-portid"
507 * The firmware maps in all 3 pages of the sysio chips device
508 * device registers and exports the mapping in the int-sized
509 * property "address". Read in this address and pass it to
510 * the subsidiary *_init functions, so we don't create extra
511 * mappings to the same physical pages and we don't have to
512 * retrieve the more than once.
515 * Implement new policy to start ignoring the "address" property
516 * due to new requirements from DR. The problem is that the contents
517 * of the "address" property contain vm mappings from OBP which needs
518 * to be recaptured into kernel vm. Instead of relying on a blanket
519 * recapture during boot time, we map psycho registers each time during
520 * attach and unmap the during detach. In some future point of time
521 * OBP will drop creating "address" property but this driver will
522 * will already not rely on this property any more.
525 attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V0
;
526 attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
527 attr
.devacc_attr_endian_flags
= DDI_NEVERSWAP_ACC
;
528 if (ddi_regs_map_setup(softsp
->dip
, 0, &softsp
->address
, 0, 0,
529 &attr
, &softsp
->ac
) != DDI_SUCCESS
) {
530 cmn_err(CE_WARN
, "%s%d: unable to map reg set 0\n",
531 ddi_get_name(softsp
->dip
),
532 ddi_get_instance(softsp
->dip
));
535 if (softsp
->address
== (caddr_t
)-1) {
536 cmn_err(CE_CONT
, "?sbus%d: No sysio <address> property\n",
537 ddi_get_instance(softsp
->dip
));
538 return (DDI_FAILURE
);
541 DPRINTF(SBUS_ATTACH_DEBUG
, ("sbus: devi=0x%p, softsp=0x%p\n",
542 (void *)devi
, (void *)softsp
));
546 * This bit of code, plus the firmware, will tell us if
547 * the #size-cells infrastructure code works, to some degree.
548 * You should be able to use the firmware to determine if
549 * the address returned by ddi_map_regs maps the correct phys. pages.
556 cmn_err(CE_CONT
, "?sbus: address property = 0x%x\n", address
);
558 if ((rv
= ddi_map_regs(softsp
->dip
, 0, &addr
,
559 (off_t
)0, (off_t
)0)) != DDI_SUCCESS
) {
560 cmn_err(CE_CONT
, "?sbus: ddi_map_regs failed: %d\n",
563 cmn_err(CE_CONT
, "?sbus: ddi_map_regs returned "
564 " virtual address 0x%x\n", addr
);
569 if ((error
= iommu_init(softsp
, softsp
->address
)) != DDI_SUCCESS
)
572 if ((error
= sbus_init(softsp
, softsp
->address
)) != DDI_SUCCESS
)
575 if ((error
= sysio_err_init(softsp
, softsp
->address
)) != DDI_SUCCESS
)
578 if ((error
= stream_buf_init(softsp
, softsp
->address
)) != DDI_SUCCESS
)
581 /* Init the pokefault mutex for sbus devices */
582 mutex_init(&softsp
->pokefault_mutex
, NULL
, MUTEX_SPIN
,
583 (void *)ipltospl(SBUS_ERR_PIL
- 1));
585 sbus_add_kstats(softsp
);
587 bus_func_register(BF_TYPE_RESINTR
, sbus_intr_reset
, devi
);
589 intr_dist_add(sbus_intrdist
, devi
);
591 ddi_report_dev(devi
);
593 return (DDI_SUCCESS
);
596 ddi_soft_state_free(sbusp
, instance
);
602 sbus_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
605 struct sbus_soft_state
*softsp
;
606 uint64_t *cpr_softsp
;
611 * Allocate the cpr soft data structure to save the current
612 * state of the interrupt mapping registers.
613 * This structure will be deallocated after the system
616 instance
= ddi_get_instance(devi
);
618 if (ddi_soft_state_zalloc(sbus_cprp
, instance
)
620 return (DDI_FAILURE
);
622 cpr_softsp
= ddi_get_soft_state(sbus_cprp
, instance
);
624 softsp
= ddi_get_soft_state(sbusp
, instance
);
626 sbus_cpr_handle_intr_map_reg(cpr_softsp
,
627 softsp
->intr_mapping_reg
, 1);
628 return (DDI_SUCCESS
);
631 return (sbus_do_detach(devi
));
633 return (DDI_FAILURE
);
638 sbus_do_detach(dev_info_t
*devi
)
641 struct sbus_soft_state
*softsp
;
643 instance
= ddi_get_instance(devi
);
644 softsp
= ddi_get_soft_state(sbusp
, instance
);
645 ASSERT(softsp
!= NULL
);
647 bus_func_unregister(BF_TYPE_RESINTR
, sbus_intr_reset
, devi
);
649 intr_dist_rem(sbus_intrdist
, devi
);
651 /* disable the streamming cache */
652 if (stream_buf_uninit(softsp
) == DDI_FAILURE
) {
656 /* remove the interrupt handlers from the system */
657 if (sysio_err_uninit(softsp
) == DDI_FAILURE
) {
661 /* disable the IOMMU */
662 if (iommu_uninit(softsp
)) {
666 /* unmap register space if we have a handle */
668 ddi_regs_map_free(&softsp
->ac
);
669 softsp
->address
= NULL
;
673 * remove counter kstats for this device
675 if (softsp
->sbus_counters_ksp
!= (kstat_t
*)NULL
)
676 kstat_delete(softsp
->sbus_counters_ksp
);
679 * if we are the last instance to detach we need to
680 * remove the picN kstats. We use sbus_attachcnt as a
681 * count of how many instances are still attached. This
682 * is protected by a mutex.
684 mutex_enter(&sbus_attachcnt_mutex
);
686 if (sbus_attachcnt
== 0) {
687 for (pic
= 0; pic
< SBUS_NUM_PICS
; pic
++) {
688 if (sbus_picN_ksp
[pic
] != (kstat_t
*)NULL
) {
689 kstat_delete(sbus_picN_ksp
[pic
]);
690 sbus_picN_ksp
[pic
] = NULL
;
694 mutex_exit(&sbus_attachcnt_mutex
);
697 /* free starfire specific soft intr mapping structure */
698 pc_ittrans_uninit(softsp
->ittrans_cookie
);
699 #endif /* _STARFIRE */
701 /* free the soft state structure */
702 ddi_soft_state_free(sbusp
, instance
);
704 return (DDI_SUCCESS
);
706 return (DDI_FAILURE
);
710 sbus_init(struct sbus_soft_state
*softsp
, caddr_t address
)
713 extern void set_intr_mapping_reg(int, uint64_t *, int);
717 * Simply add each registers offset to the base address
718 * to calculate the already mapped virtual address of
719 * the device register...
721 * define a macro for the pointer arithmetic; all registers
722 * are 64 bits wide and are defined as uint64_t's.
725 #define REG_ADDR(b, o) (uint64_t *)((caddr_t)(b) + (o))
727 softsp
->sysio_ctrl_reg
= REG_ADDR(address
, OFF_SYSIO_CTRL_REG
);
728 softsp
->sbus_ctrl_reg
= REG_ADDR(address
, OFF_SBUS_CTRL_REG
);
729 softsp
->sbus_slot_config_reg
= REG_ADDR(address
, OFF_SBUS_SLOT_CONFIG
);
730 softsp
->intr_mapping_reg
= REG_ADDR(address
, OFF_INTR_MAPPING_REG
);
731 softsp
->clr_intr_reg
= REG_ADDR(address
, OFF_CLR_INTR_REG
);
732 softsp
->intr_retry_reg
= REG_ADDR(address
, OFF_INTR_RETRY_REG
);
733 softsp
->sbus_intr_state
= REG_ADDR(address
, OFF_SBUS_INTR_STATE_REG
);
734 softsp
->sbus_pcr
= REG_ADDR(address
, OFF_SBUS_PCR
);
735 softsp
->sbus_pic
= REG_ADDR(address
, OFF_SBUS_PIC
);
739 DPRINTF(SBUS_REGISTERS_DEBUG
, ("SYSIO Control reg: 0x%p\n"
740 "SBUS Control reg: 0x%p", (void *)softsp
->sysio_ctrl_reg
,
741 (void *)softsp
->sbus_ctrl_reg
));
744 /* Setup interrupt target translation for starfire */
745 pc_ittrans_init(softsp
->upa_id
, &softsp
->ittrans_cookie
);
746 #endif /* _STARFIRE */
748 softsp
->intr_mapping_ign
=
749 UPAID_TO_IGN(softsp
->upa_id
) << IMR_IGN_SHIFT
;
751 /* Diag reg 2 is the next 64 bit word after diag reg 1 */
752 softsp
->obio_intr_state
= softsp
->sbus_intr_state
+ 1;
754 (void) sbus_resume_init(softsp
, 0);
757 * Set the initial burstsizes for each slot to all 1's. This will
758 * get changed at initchild time.
760 for (i
= 0; i
< MAX_SBUS_SLOTS
; i
++)
761 softsp
->sbus_slave_burstsizes
[i
] = 0xffffffffu
;
764 * Since SYSIO is used as an interrupt mastering device for slave
765 * only UPA devices, we call a dedicated kernel function to register
766 * The address of the interrupt mapping register for the slave device.
768 * If RISC/sysio is wired to support 2 upa slave interrupt
769 * devices then register 2nd mapping register with system.
770 * The slave/proxy portid algorithm (decribed in Fusion Desktop Spec)
771 * allows for upto 3 slaves per proxy but Psycho/SYSIO only support 2.
773 * #upa-interrupt-proxies property defines how many UPA interrupt
774 * slaves a bridge is wired to support. Older systems that lack
775 * this property will default to 1.
777 numproxy
= ddi_prop_get_int(DDI_DEV_T_ANY
, softsp
->dip
,
778 DDI_PROP_DONTPASS
, "#upa-interrupt-proxies", 1);
781 set_intr_mapping_reg(softsp
->upa_id
,
782 (uint64_t *)(softsp
->intr_mapping_reg
+
783 FFB_MAPPING_REG
), 1);
786 set_intr_mapping_reg(softsp
->upa_id
,
787 (uint64_t *)(softsp
->intr_mapping_reg
+
788 EXP_MAPPING_REG
), 2);
790 /* support for a 3 interrupt proxy would go here */
792 /* Turn on spurious interrupt counter if we're not a DEBUG kernel. */
800 return (DDI_SUCCESS
);
804 * This procedure is part of sbus initialization. It is called by
805 * sbus_init() and is invoked when the system is being resumed.
808 sbus_resume_init(struct sbus_soft_state
*softsp
, int resume
)
811 uint_t sbus_burst_sizes
;
814 * This shouldn't be needed when we have a real OBP PROM.
815 * (RAZ) Get rid of this later!!!
820 * For Starfire, we need to program a
821 * constant odd value.
822 * Zero out the MID field before ORing
823 * We leave the LSB of the MID field intact since
824 * we cannot have a zero(even) MID value
826 uint64_t tmpconst
= 0x1DULL
;
827 *softsp
->sysio_ctrl_reg
&= 0xFF0FFFFFFFFFFFFFULL
;
828 *softsp
->sysio_ctrl_reg
|= tmpconst
<< 51;
831 * Program in the interrupt group number
832 * Here we have to convert the starfire
833 * 7 bit upaid into a 5bit value.
835 *softsp
->sysio_ctrl_reg
|=
836 (uint64_t)STARFIRE_UPAID2HWIGN(softsp
->upa_id
)
839 /* for the rest of sun4u's */
840 *softsp
->sysio_ctrl_reg
|=
841 (uint64_t)softsp
->upa_id
<< 51;
843 /* Program in the interrupt group number */
844 *softsp
->sysio_ctrl_reg
|=
845 (uint64_t)softsp
->upa_id
<< SYSIO_IGN
;
846 #endif /* _STARFIRE */
849 * Set appropriate fields of sbus control register.
850 * Set DVMA arbitration enable for all devices.
852 *softsp
->sbus_ctrl_reg
|= SBUS_ARBIT_ALL
;
854 /* Calculate our burstsizes now so we don't have to do it later */
855 sbus_burst_sizes
= (SYSIO64_BURST_RANGE
<< SYSIO64_BURST_SHIFT
)
858 sbus_burst_sizes
= ddi_getprop(DDI_DEV_T_ANY
, softsp
->dip
,
859 DDI_PROP_DONTPASS
, "up-burst-sizes", sbus_burst_sizes
);
861 softsp
->sbus_burst_sizes
= sbus_burst_sizes
& SYSIO_BURST_MASK
;
862 softsp
->sbus64_burst_sizes
= sbus_burst_sizes
& SYSIO64_BURST_MASK
;
865 /* Set burstsizes to smallest value */
866 for (i
= 0; i
< MAX_SBUS_SLOTS
; i
++) {
867 volatile uint64_t *config
;
870 config
= softsp
->sbus_slot_config_reg
+ i
;
872 /* Write out the burst size */
873 tmpreg
= (uint64_t)0;
876 /* Flush any write buffers */
877 tmpreg
= *softsp
->sbus_ctrl_reg
;
879 DPRINTF(SBUS_REGISTERS_DEBUG
, ("Sbus slot 0x%x slot "
880 "configuration reg: 0x%p", (i
> 3) ? i
+ 9 : i
,
884 /* Program the slot configuration registers */
885 for (i
= 0; i
< MAX_SBUS_SLOTS
; i
++) {
886 volatile uint64_t *config
;
890 uint_t slave_burstsizes
;
892 slave_burstsizes
= 0;
893 if (softsp
->sbus_slave_burstsizes
[i
] != 0xffffffffu
) {
894 config
= softsp
->sbus_slot_config_reg
+ i
;
896 if (softsp
->sbus_slave_burstsizes
[i
] &
897 SYSIO64_BURST_MASK
) {
898 /* get the 64 bit burstsizes */
900 softsp
->sbus_slave_burstsizes
[i
] >>
903 /* Turn on 64 bit PIO's on the sbus */
907 softsp
->sbus_slave_burstsizes
[i
] &
911 /* Get burstsizes into sysio register format */
912 slave_burstsizes
>>= SYSIO_SLAVEBURST_REGSHIFT
;
914 /* Program the burstsizes */
915 *config
|= (uint64_t)slave_burstsizes
;
917 /* Flush any write buffers */
919 tmpreg
= *softsp
->sbus_ctrl_reg
;
925 return (DDI_SUCCESS
);
928 #define get_prop(di, pname, flag, pval, plen) \
929 (ddi_prop_op(DDI_DEV_T_NONE, di, PROP_LEN_AND_VAL_ALLOC, \
930 flag | DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, \
931 pname, (caddr_t)pval, plen))
938 * Create a sysio_parent_private_data structure from the ddi properties of
941 * The "reg" and either an "intr" or "interrupts" properties are required
942 * if the driver wishes to create mappings or field interrupts on behalf
945 * The "reg" property is assumed to be a list of at least one triple
947 * <bustype, address, size>*1
949 * On pre-fusion machines, the "intr" property was the IPL for the system.
950 * Most new sbus devices post an "interrupts" property that corresponds to
951 * a particular bus level. All devices on fusion using an "intr" property
952 * will have it's contents translated into a bus level. Hence, "intr" and
953 * "interrupts on the fusion platform can be treated the same.
955 * The "interrupts" property is assumed to be a list of at least one
956 * n-tuples that describes the interrupt capabilities of the bus the device
957 * is connected to. For SBus, this looks like
961 * (This property obsoletes the 'intr' property).
963 * The OBP_RANGES property is optional.
966 make_sbus_ppd(dev_info_t
*child
)
968 struct sysio_parent_private_data
*pdptr
;
970 int *reg_prop
, *rgstr_prop
, *rng_prop
;
971 int reg_len
, rgstr_len
, rng_len
;
974 * Make the function idempotent, because name_child could
975 * be called multiple times on a node.
977 if (ddi_get_parent_data(child
) != NULL
)
980 pdptr
= kmem_zalloc(sizeof (*pdptr
), KM_SLEEP
);
981 ddi_set_parent_data(child
, pdptr
);
984 * Handle the 'reg'/'registers' properties.
985 * "registers" overrides "reg", but requires that "reg" be exported,
986 * so we can handle wildcard specifiers. "registers" implies an
987 * sbus style device. "registers" implies that we insert the
988 * correct value in the regspec_bustype field of each spec for a real
989 * (non-pseudo) device node. "registers" is a s/w only property, so
990 * we inhibit the prom search for this property.
992 if (get_prop(child
, OBP_REG
, 0, ®_prop
, ®_len
) != DDI_SUCCESS
)
996 * Save the underlying slot number and slot offset.
997 * Among other things, we use these to name the child node.
999 pdptr
->slot
= (uint_t
)-1;
1001 pdptr
->slot
= ((struct regspec
*)reg_prop
)->regspec_bustype
;
1002 pdptr
->offset
= ((struct regspec
*)reg_prop
)->regspec_addr
;
1006 (void) get_prop(child
, "registers", DDI_PROP_NOTPROM
,
1007 &rgstr_prop
, &rgstr_len
);
1009 if (rgstr_len
!= 0) {
1010 if (ndi_dev_is_persistent_node(child
) && (reg_len
!= 0)) {
1012 * Convert wildcard "registers" for a real node...
1013 * (Else, this is the wildcard prototype node)
1015 struct regspec
*rp
= (struct regspec
*)reg_prop
;
1016 uint_t slot
= rp
->regspec_bustype
;
1019 rp
= (struct regspec
*)rgstr_prop
;
1020 n
= rgstr_len
/ sizeof (struct regspec
);
1021 for (i
= 0; i
< n
; ++i
, ++rp
)
1022 rp
->regspec_bustype
= slot
;
1026 kmem_free(reg_prop
, reg_len
);
1028 reg_prop
= rgstr_prop
;
1029 reg_len
= rgstr_len
;
1032 pdptr
->par_nreg
= reg_len
/ (int)sizeof (struct regspec
);
1033 pdptr
->par_reg
= (struct regspec
*)reg_prop
;
1037 * See if I have ranges.
1039 if (get_prop(child
, OBP_RANGES
, 0, &rng_prop
, &rng_len
) ==
1041 pdptr
->par_nrng
= rng_len
/ (int)(sizeof (struct rangespec
));
1042 pdptr
->par_rng
= (struct rangespec
*)rng_prop
;
1047 * Special handling for "sbusmem" pseudo device nodes.
1048 * The special handling automatically creates the "reg"
1049 * property in the sbusmem nodes, based on the parent's
1050 * property so that each slot will automtically have a
1051 * correctly sized "reg" property, once created,
1052 * sbus_initchild does the rest of the work to init
1056 sbusmem_initchild(dev_info_t
*dip
, dev_info_t
*child
)
1062 slot
= ddi_getprop(DDI_DEV_T_NONE
, child
,
1063 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
, "slot", -1);
1065 DPRINTF(SBUS_SBUSMEM_DEBUG
, ("can't get slot property\n"));
1066 return (DDI_FAILURE
);
1070 * Find the parent range corresponding to this "slot",
1071 * so we can set the size of the child's "reg" property.
1073 for (i
= 0, n
= sparc_pd_getnrng(dip
); i
< n
; i
++) {
1074 struct rangespec
*rp
= sparc_pd_getrng(dip
, i
);
1076 if (rp
->rng_cbustype
== (uint_t
)slot
) {
1079 /* create reg property */
1081 r
.regspec_bustype
= (uint_t
)slot
;
1083 r
.regspec_size
= rp
->rng_size
;
1084 (void) ddi_prop_update_int_array(DDI_DEV_T_NONE
,
1085 child
, "reg", (int *)&r
,
1086 sizeof (struct regspec
) / sizeof (int));
1088 /* create size property for slot */
1090 size
= rp
->rng_size
;
1091 (void) ddi_prop_update_int(DDI_DEV_T_NONE
,
1092 child
, "size", size
);
1094 (void) sprintf(ident
, "slot%x", slot
);
1095 (void) ddi_prop_update_string(DDI_DEV_T_NONE
,
1096 child
, "ident", ident
);
1098 return (DDI_SUCCESS
);
1101 return (DDI_FAILURE
);
1105 * Nexus routine to name a child.
1106 * It takes a dev_info node and a buffer, returns the name
1110 sysio_name_child(dev_info_t
*child
, char *name
, int namelen
)
1113 * Fill in parent-private data
1115 make_sbus_ppd(child
);
1118 * Name the device node using the underlying (prom) values
1119 * of the first entry in the "reg" property. For SBus devices,
1120 * the textual form of the name is <name>@<slot#>,<offset>.
1121 * This must match the prom's pathname or mountroot, etc, won't
1124 if (sysio_pd_getslot(child
) != (uint_t
)-1) {
1125 (void) snprintf(name
, namelen
, "%x,%x",
1126 sysio_pd_getslot(child
), sysio_pd_getoffset(child
));
1128 return (DDI_SUCCESS
);
1132 * Called from the bus_ctl op of sysio sbus nexus driver
1133 * to implement the DDI_CTLOPS_INITCHILD operation. That is, it names
1134 * the children of sysio sbusses based on the reg spec.
1136 * Handles the following properties:
1142 * registers wildcard s/w sbus register spec (.conf file property)
1143 * intr old-form interrupt spec
1144 * interrupts new (bus-oriented) interrupt spec
1148 sbus_initchild(dev_info_t
*dip
, dev_info_t
*child
)
1150 char name
[MAXNAMELEN
];
1151 ulong_t slave_burstsizes
;
1153 volatile uint64_t *slot_reg
;
1157 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
1158 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
1160 if (strcmp(ddi_get_name(child
), "sbusmem") == 0) {
1161 if (sbusmem_initchild(dip
, child
) != DDI_SUCCESS
)
1162 return (DDI_FAILURE
);
1166 * If this is a s/w node defined with the "registers" property,
1167 * this means that this is a wildcard specifier, whose properties
1168 * get applied to all previously defined h/w nodes with the same
1169 * name and same parent.
1171 if (ndi_dev_is_persistent_node(child
) == 0) {
1173 if ((ddi_getproplen(DDI_DEV_T_ANY
, child
, DDI_PROP_NOTPROM
,
1174 "registers", &len
) == DDI_SUCCESS
) && (len
!= 0)) {
1175 ndi_merge_wildcard_node(child
);
1176 return (DDI_FAILURE
);
1180 /* name the child */
1181 (void) sysio_name_child(child
, name
, MAXNAMELEN
);
1182 ddi_set_name_addr(child
, name
);
1185 * If a pseudo node, attempt to merge it into a hw node.
1186 * If merge is successful, we uinitialize the node and
1187 * return failure, to allow caller to remove the node.
1188 * The merge fails, this is a real pseudo node. Allow
1189 * initchild to continue.
1191 if ((ndi_dev_is_persistent_node(child
) == 0) &&
1192 (ndi_merge_node(child
, sysio_name_child
) == DDI_SUCCESS
)) {
1193 (void) sbus_uninitchild(child
);
1194 return (DDI_FAILURE
);
1197 /* Figure out the child devices slot number */
1198 slot
= sysio_pd_getslot(child
);
1200 /* If we don't have a reg property, bypass slot specific programming */
1201 if (slot
< 0 || slot
>= MAX_SBUS_SLOT_ADDR
) {
1203 cmn_err(CE_WARN
, "?Invalid sbus slot address 0x%x for %s "
1204 "device\n", slot
, ddi_get_name(child
));
1209 /* Modify the onboard slot numbers if applicable. */
1210 slot
= (slot
> 3) ? slot
- 9 : slot
;
1212 /* Get the slot configuration register for the child device. */
1213 slot_reg
= softsp
->sbus_slot_config_reg
+ slot
;
1216 * Program the devices slot configuration register for the
1217 * appropriate slave burstsizes.
1218 * The upper 16 bits of the slave-burst-sizes are for 64 bit sbus
1219 * and the lower 16 bits are the burst sizes for 32 bit sbus. If
1220 * we see that a device supports both 64 bit and 32 bit slave accesses,
1221 * we default to 64 bit and turn it on in the slot config reg.
1223 * For older devices, make sure we check the "burst-sizes" property
1226 if ((slave_burstsizes
= (ulong_t
)ddi_getprop(DDI_DEV_T_ANY
, child
,
1227 DDI_PROP_DONTPASS
, "slave-burst-sizes", 0)) != 0 ||
1228 (slave_burstsizes
= (ulong_t
)ddi_getprop(DDI_DEV_T_ANY
, child
,
1229 DDI_PROP_DONTPASS
, "burst-sizes", 0)) != 0) {
1230 uint_t burstsizes
= 0;
1233 * If we only have 32 bit burst sizes from a previous device,
1234 * mask out any burstsizes for 64 bit mode.
1236 if (((softsp
->sbus_slave_burstsizes
[slot
] &
1237 0xffff0000u
) == 0) &&
1238 ((softsp
->sbus_slave_burstsizes
[slot
] & 0xffff) != 0)) {
1239 slave_burstsizes
&= 0xffff;
1243 * If "slave-burst-sizes was defined but we have 0 at this
1244 * point, we must have had 64 bit burstsizes, however a prior
1245 * device can only burst in 32 bit mode. Therefore, we leave
1246 * the burstsizes in the 32 bit mode and disregard the 64 bit.
1248 if (slave_burstsizes
== 0)
1252 * We and in the new burst sizes with that of prior devices.
1253 * This ensures that we always take the least common
1254 * denominator of the burst sizes.
1256 softsp
->sbus_slave_burstsizes
[slot
] &=
1258 ((SYSIO64_SLAVEBURST_RANGE
<<
1259 SYSIO64_BURST_SHIFT
) |
1260 SYSIO_SLAVEBURST_RANGE
));
1262 /* Get the 64 bit burstsizes. */
1263 if (softsp
->sbus_slave_burstsizes
[slot
] &
1264 SYSIO64_BURST_MASK
) {
1265 /* get the 64 bit burstsizes */
1266 burstsizes
= softsp
->sbus_slave_burstsizes
[slot
] >>
1267 SYSIO64_BURST_SHIFT
;
1269 /* Turn on 64 bit PIO's on the sbus */
1270 *slot_reg
|= SBUS_ETM
;
1272 /* Turn off 64 bit PIO's on the sbus */
1273 *slot_reg
&= ~SBUS_ETM
;
1275 /* Get the 32 bit burstsizes if we don't have 64 bit. */
1276 if (softsp
->sbus_slave_burstsizes
[slot
] &
1279 softsp
->sbus_slave_burstsizes
[slot
] &
1284 /* Get the burstsizes into sysio register format */
1285 burstsizes
>>= SYSIO_SLAVEBURST_REGSHIFT
;
1287 /* Reset reg in case we're scaling back */
1288 *slot_reg
&= (uint64_t)~SYSIO_SLAVEBURST_MASK
;
1290 /* Program the burstsizes */
1291 *slot_reg
|= (uint64_t)burstsizes
;
1293 /* Flush system load/store buffers */
1300 return (DDI_SUCCESS
);
1304 sbus_uninitchild(dev_info_t
*dip
)
1306 struct sysio_parent_private_data
*pdptr
;
1309 if ((pdptr
= ddi_get_parent_data(dip
)) != NULL
) {
1310 if ((n
= (size_t)pdptr
->par_nrng
) != 0)
1311 kmem_free(pdptr
->par_rng
, n
*
1312 sizeof (struct rangespec
));
1314 if ((n
= pdptr
->par_nreg
) != 0)
1315 kmem_free(pdptr
->par_reg
, n
* sizeof (struct regspec
));
1317 kmem_free(pdptr
, sizeof (*pdptr
));
1318 ddi_set_parent_data(dip
, NULL
);
1320 ddi_set_name_addr(dip
, NULL
);
1322 * Strip the node to properly convert it back to prototype form
1324 ddi_remove_minor_node(dip
, NULL
);
1325 impl_rem_dev_props(dip
);
1326 return (DDI_SUCCESS
);
1330 int sbus_peekfault_cnt
= 0;
1331 int sbus_pokefault_cnt
= 0;
1335 sbus_ctlops_poke(struct sbus_soft_state
*softsp
, peekpoke_ctlops_t
*in_args
)
1337 int err
= DDI_SUCCESS
;
1339 volatile uint64_t tmpreg
;
1341 /* Cautious access not supported. */
1342 if (in_args
->handle
!= NULL
)
1343 return (DDI_FAILURE
);
1345 mutex_enter(&softsp
->pokefault_mutex
);
1346 softsp
->ontrap_data
= &otd
;
1348 /* Set up protected environment. */
1349 if (!on_trap(&otd
, OT_DATA_ACCESS
)) {
1350 uintptr_t tramp
= otd
.ot_trampoline
;
1352 otd
.ot_trampoline
= (uintptr_t)&poke_fault
;
1353 err
= do_poke(in_args
->size
, (void *)in_args
->dev_addr
,
1354 (void *)in_args
->host_addr
);
1355 otd
.ot_trampoline
= tramp
;
1359 /* Flush any sbus store buffers. */
1360 tmpreg
= *softsp
->sbus_ctrl_reg
;
1363 * Read the sbus error reg and see if a fault occured. If
1364 * one has, give the SYSIO time to packetize the interrupt
1365 * for the fault and send it out. The sbus error handler will
1366 * 0 these fields when it's called to service the fault.
1368 tmpreg
= *softsp
->sbus_err_reg
;
1369 while (tmpreg
& SB_AFSR_P_TO
|| tmpreg
& SB_AFSR_P_BERR
)
1370 tmpreg
= *softsp
->sbus_err_reg
;
1372 /* Take down protected environment. */
1375 softsp
->ontrap_data
= NULL
;
1376 mutex_exit(&softsp
->pokefault_mutex
);
1379 if (err
== DDI_FAILURE
)
1380 sbus_pokefault_cnt
++;
1387 sbus_ctlops_peek(struct sbus_soft_state
*softsp
, peekpoke_ctlops_t
*in_args
,
1390 int err
= DDI_SUCCESS
;
1393 /* No safe access except for peek is supported. */
1394 if (in_args
->handle
!= NULL
)
1395 return (DDI_FAILURE
);
1397 if (!on_trap(&otd
, OT_DATA_ACCESS
)) {
1398 uintptr_t tramp
= otd
.ot_trampoline
;
1400 otd
.ot_trampoline
= (uintptr_t)&peek_fault
;
1401 err
= do_peek(in_args
->size
, (void *)in_args
->dev_addr
,
1402 (void *)in_args
->host_addr
);
1403 otd
.ot_trampoline
= tramp
;
1404 result
= (void *)in_args
->host_addr
;
1409 if (err
== DDI_FAILURE
)
1410 sbus_peekfault_cnt
++;
1417 sbus_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
,
1418 ddi_ctl_enum_t op
, void *arg
, void *result
)
1420 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
1421 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
1425 case DDI_CTLOPS_INITCHILD
:
1426 return (sbus_initchild(dip
, (dev_info_t
*)arg
));
1428 case DDI_CTLOPS_UNINITCHILD
:
1429 return (sbus_uninitchild(arg
));
1431 case DDI_CTLOPS_IOMIN
: {
1432 int val
= *((int *)result
);
1435 * The 'arg' value of nonzero indicates 'streaming' mode.
1436 * If in streaming mode, pick the largest of our burstsizes
1437 * available and say that that is our minimum value (modulo
1438 * what mincycle is).
1440 if ((int)(uintptr_t)arg
)
1442 (1 << (ddi_fls(softsp
->sbus_burst_sizes
) - 1)));
1445 (1 << (ddi_ffs(softsp
->sbus_burst_sizes
) - 1)));
1447 *((int *)result
) = val
;
1448 return (ddi_ctlops(dip
, rdip
, op
, arg
, result
));
1451 case DDI_CTLOPS_REPORTDEV
: {
1453 int i
, n
, len
, f_len
;
1457 * So we can do one atomic cmn_err call, we allocate a 4k
1458 * buffer, and format the reportdev message into that buffer,
1459 * send it to cmn_err, and then free the allocated buffer.
1460 * If message is longer than 1k, the message is truncated and
1461 * an error message is emitted (debug kernel only).
1463 #define REPORTDEV_BUFSIZE 1024
1465 int sbusid
= ddi_get_instance(dip
);
1467 if (ddi_get_parent_data(rdip
) == NULL
)
1468 return (DDI_FAILURE
);
1470 msgbuf
= kmem_zalloc(REPORTDEV_BUFSIZE
, KM_SLEEP
);
1472 pdev
= ddi_get_parent(rdip
);
1473 f_len
= snprintf(msgbuf
, REPORTDEV_BUFSIZE
,
1474 "%s%d at %s%d: SBus%d ",
1475 ddi_driver_name(rdip
), ddi_get_instance(rdip
),
1476 ddi_driver_name(pdev
), ddi_get_instance(pdev
), sbusid
);
1477 len
= strlen(msgbuf
);
1479 for (i
= 0, n
= sysio_pd_getnreg(rdip
); i
< n
; i
++) {
1482 rp
= sysio_pd_getreg(rdip
, i
);
1484 f_len
+= snprintf(msgbuf
+ len
,
1485 REPORTDEV_BUFSIZE
- len
, " and ");
1486 len
= strlen(msgbuf
);
1489 f_len
+= snprintf(msgbuf
+ len
, REPORTDEV_BUFSIZE
- len
,
1490 "slot 0x%x offset 0x%x",
1491 rp
->regspec_bustype
, rp
->regspec_addr
);
1492 len
= strlen(msgbuf
);
1495 for (i
= 0, n
= i_ddi_get_intx_nintrs(rdip
); i
< n
; i
++) {
1496 uint32_t sbuslevel
, inum
, pri
;
1499 f_len
+= snprintf(msgbuf
+ len
,
1500 REPORTDEV_BUFSIZE
- len
, ",");
1501 len
= strlen(msgbuf
);
1504 sbuslevel
= inum
= i_ddi_get_inum(rdip
, i
);
1505 pri
= i_ddi_get_intr_pri(rdip
, i
);
1507 (void) sbus_xlate_intrs(dip
, rdip
, &inum
,
1508 &pri
, softsp
->intr_mapping_ign
);
1510 if (sbuslevel
> MAX_SBUS_LEVEL
)
1511 f_len
+= snprintf(msgbuf
+ len
,
1512 REPORTDEV_BUFSIZE
- len
,
1513 " Onboard device ");
1515 f_len
+= snprintf(msgbuf
+ len
,
1516 REPORTDEV_BUFSIZE
- len
, " SBus level %d ",
1518 len
= strlen(msgbuf
);
1520 f_len
+= snprintf(msgbuf
+ len
, REPORTDEV_BUFSIZE
- len
,
1521 "sparc9 ipl %d", pri
);
1522 len
= strlen(msgbuf
);
1525 if (f_len
+ 1 >= REPORTDEV_BUFSIZE
) {
1526 cmn_err(CE_NOTE
, "next message is truncated: "
1527 "printed length 1024, real length %d", f_len
);
1531 cmn_err(CE_CONT
, "?%s\n", msgbuf
);
1532 kmem_free(msgbuf
, REPORTDEV_BUFSIZE
);
1533 return (DDI_SUCCESS
);
1535 #undef REPORTDEV_BUFSIZE
1538 case DDI_CTLOPS_SLAVEONLY
:
1539 return (DDI_FAILURE
);
1541 case DDI_CTLOPS_AFFINITY
: {
1542 dev_info_t
*dipb
= (dev_info_t
*)arg
;
1545 if ((b_slot
= find_sbus_slot(dip
, dipb
)) < 0)
1546 return (DDI_FAILURE
);
1548 if ((r_slot
= find_sbus_slot(dip
, rdip
)) < 0)
1549 return (DDI_FAILURE
);
1551 return ((b_slot
== r_slot
)? DDI_SUCCESS
: DDI_FAILURE
);
1554 case DDI_CTLOPS_DMAPMAPC
:
1555 cmn_err(CE_CONT
, "?DDI_DMAPMAPC called!!\n");
1556 return (DDI_FAILURE
);
1558 case DDI_CTLOPS_POKE
:
1559 return (sbus_ctlops_poke(softsp
, (peekpoke_ctlops_t
*)arg
));
1561 case DDI_CTLOPS_PEEK
:
1562 return (sbus_ctlops_peek(softsp
, (peekpoke_ctlops_t
*)arg
,
1565 case DDI_CTLOPS_DVMAPAGESIZE
:
1566 *(ulong_t
*)result
= IOMMU_PAGESIZE
;
1567 return (DDI_SUCCESS
);
1570 return (ddi_ctlops(dip
, rdip
, op
, arg
, result
));
1575 find_sbus_slot(dev_info_t
*dip
, dev_info_t
*rdip
)
1581 * look for the node that's a direct child of this Sbus node.
1583 while (rdip
&& (child
= ddi_get_parent(rdip
)) != dip
) {
1588 * If there is one, get the slot number of *my* child
1591 slot
= sysio_pd_getslot(rdip
);
1597 * This is the sbus interrupt routine wrapper function. This function
1598 * installs itself as a child devices interrupt handler. It's function is
1599 * to dispatch a child devices interrupt handler, and then
1600 * reset the interrupt clear register for the child device.
1602 * Warning: This routine may need to be implemented as an assembly level
1603 * routine to improve performance.
1606 #define MAX_INTR_CNT 10
1609 sbus_intr_wrapper(caddr_t arg
)
1611 uint_t intr_return
= DDI_INTR_UNCLAIMED
;
1612 volatile uint64_t tmpreg
;
1613 struct sbus_wrapper_arg
*intr_info
;
1614 struct sbus_intr_handler
*intr_handler
;
1615 uchar_t
*spurious_cntr
;
1617 intr_info
= (struct sbus_wrapper_arg
*)arg
;
1618 spurious_cntr
= &intr_info
->softsp
->spurious_cntrs
[intr_info
->pil
];
1619 intr_handler
= intr_info
->handler_list
;
1621 while (intr_handler
) {
1622 caddr_t arg1
= intr_handler
->arg1
;
1623 caddr_t arg2
= intr_handler
->arg2
;
1624 uint_t (*funcp
)() = intr_handler
->funcp
;
1625 dev_info_t
*dip
= intr_handler
->dip
;
1628 if (intr_handler
->intr_state
== SBUS_INTR_STATE_DISABLE
) {
1629 intr_handler
= intr_handler
->next
;
1633 DTRACE_PROBE4(interrupt__start
, dev_info_t
, dip
,
1634 void *, funcp
, caddr_t
, arg1
, caddr_t
, arg2
);
1636 r
= (*funcp
)(arg1
, arg2
);
1638 DTRACE_PROBE4(interrupt__complete
, dev_info_t
, dip
,
1639 void *, funcp
, caddr_t
, arg1
, int, r
);
1642 intr_handler
= intr_handler
->next
;
1645 /* Set the interrupt state machine to idle */
1646 tmpreg
= *intr_info
->softsp
->sbus_ctrl_reg
;
1647 tmpreg
= SBUS_INTR_IDLE
;
1648 *intr_info
->clear_reg
= tmpreg
;
1649 tmpreg
= *intr_info
->softsp
->sbus_ctrl_reg
;
1651 if (intr_return
== DDI_INTR_UNCLAIMED
) {
1654 if (*spurious_cntr
< MAX_INTR_CNT
) {
1656 return (DDI_INTR_CLAIMED
);
1659 else if (intr_info
->pil
>= LOCK_LEVEL
) {
1660 cmn_err(CE_PANIC
, "%d unclaimed interrupts at "
1661 "interrupt level %d", MAX_INTR_CNT
,
1667 * Reset spurious counter once we acknowledge
1668 * it to the system level.
1670 *spurious_cntr
= (uchar_t
)0;
1672 *spurious_cntr
= (uchar_t
)0;
1675 return (intr_return
);
1679 * add_intrspec - Add an interrupt specification.
1682 sbus_add_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
1683 ddi_intr_handle_impl_t
*hdlp
)
1685 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
1686 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
1687 volatile uint64_t *mondo_vec_reg
;
1688 volatile uint64_t tmp_mondo_vec
;
1689 volatile uint64_t *intr_state_reg
;
1690 volatile uint64_t tmpreg
; /* HW flush reg */
1694 struct sbus_wrapper_arg
*sbus_arg
;
1695 struct sbus_intr_handler
*intr_handler
;
1697 /* Interrupt state machine reset flag */
1698 int reset_ism_register
= 1;
1699 int ret
= DDI_SUCCESS
;
1701 /* Check if we have a valid sbus slot address */
1702 if (((slot
= (uint_t
)find_sbus_slot(dip
, rdip
)) >=
1703 MAX_SBUS_SLOT_ADDR
) || (slot
< (uint_t
)0)) {
1704 cmn_err(CE_WARN
, "Invalid sbus slot 0x%x during add intr\n",
1706 return (DDI_FAILURE
);
1709 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr: sbus interrupt %d "
1710 "for device %s%d\n", hdlp
->ih_vector
, ddi_driver_name(rdip
),
1711 ddi_get_instance(rdip
)));
1713 /* Xlate the interrupt */
1714 if (sbus_xlate_intrs(dip
, rdip
, (uint32_t *)&hdlp
->ih_vector
,
1715 &hdlp
->ih_pri
, softsp
->intr_mapping_ign
) == DDI_FAILURE
) {
1716 cmn_err(CE_WARN
, "Can't xlate SBUS devices %s interrupt.\n",
1717 ddi_driver_name(rdip
));
1718 return (DDI_FAILURE
);
1721 /* get the ino number */
1722 ino
= hdlp
->ih_vector
& SBUS_MAX_INO
;
1723 mondo_vec_reg
= (softsp
->intr_mapping_reg
+
1724 ino_table
[ino
]->mapping_reg
);
1727 * This is an intermediate step in identifying
1728 * the exact bits which represent the device in the interrupt
1729 * state diagnostic register.
1731 if (ino
> MAX_MONDO_EXTERNAL
) {
1732 start_bit
= ino_table
[ino
]->diagreg_shift
;
1733 intr_state_reg
= softsp
->obio_intr_state
;
1735 start_bit
= 16 * (ino
>> 3) + 2 * (ino
& 0x7);
1736 intr_state_reg
= softsp
->sbus_intr_state
;
1740 /* Allocate a nexus interrupt data structure */
1741 intr_handler
= kmem_zalloc(sizeof (struct sbus_intr_handler
), KM_SLEEP
);
1742 intr_handler
->dip
= rdip
;
1743 intr_handler
->funcp
= hdlp
->ih_cb_func
;
1744 intr_handler
->arg1
= hdlp
->ih_cb_arg1
;
1745 intr_handler
->arg2
= hdlp
->ih_cb_arg2
;
1746 intr_handler
->inum
= hdlp
->ih_inum
;
1748 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr: xlated interrupt 0x%x "
1749 "intr_handler 0x%p\n", hdlp
->ih_vector
, (void *)intr_handler
));
1752 * Grab this lock here. So it will protect the poll list.
1754 mutex_enter(&softsp
->intr_poll_list_lock
);
1756 sbus_arg
= softsp
->intr_list
[ino
];
1757 /* Check if we have a poll list to deal with */
1759 tmp_mondo_vec
= *mondo_vec_reg
;
1760 tmp_mondo_vec
&= ~INTERRUPT_VALID
;
1761 *mondo_vec_reg
= tmp_mondo_vec
;
1763 tmpreg
= *softsp
->sbus_ctrl_reg
;
1768 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr:sbus_arg exists "
1769 "0x%p\n", (void *)sbus_arg
));
1771 * Two bits per ino in the diagnostic register
1772 * indicate the status of its interrupt.
1773 * 0 - idle, 1 - transmit, 3 - pending.
1775 while (((*intr_state_reg
>>
1776 start_bit
) & 0x3) == INT_PENDING
&& !panicstr
)
1779 intr_handler
->next
= sbus_arg
->handler_list
;
1780 sbus_arg
->handler_list
= intr_handler
;
1782 reset_ism_register
= 0;
1784 sbus_arg
= kmem_zalloc(sizeof (struct sbus_wrapper_arg
),
1787 softsp
->intr_list
[ino
] = sbus_arg
;
1788 sbus_arg
->clear_reg
= (softsp
->clr_intr_reg
+
1789 ino_table
[ino
]->clear_reg
);
1790 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr:Ino 0x%x Interrupt "
1791 "clear reg: 0x%p\n", ino
, (void *)sbus_arg
->clear_reg
));
1792 sbus_arg
->softsp
= softsp
;
1793 sbus_arg
->handler_list
= intr_handler
;
1796 * No handler added yet in the interrupt vector
1797 * table for this ino.
1798 * Install the nexus interrupt wrapper in the
1799 * system. The wrapper will call the device
1800 * interrupt handler.
1802 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp
,
1803 (ddi_intr_handler_t
*)sbus_intr_wrapper
,
1804 (caddr_t
)sbus_arg
, NULL
);
1806 ret
= i_ddi_add_ivintr(hdlp
);
1809 * Restore original interrupt handler
1810 * and arguments in interrupt handle.
1812 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp
, intr_handler
->funcp
,
1813 intr_handler
->arg1
, intr_handler
->arg2
);
1815 if (ret
!= DDI_SUCCESS
) {
1816 mutex_exit(&softsp
->intr_poll_list_lock
);
1820 if ((slot
>= EXT_SBUS_SLOTS
) ||
1821 (softsp
->intr_hndlr_cnt
[slot
] == 0)) {
1823 cpu_id
= intr_dist_cpuid();
1825 tmp_mondo_vec
= pc_translate_tgtid(
1826 softsp
->ittrans_cookie
, cpu_id
,
1827 mondo_vec_reg
) << IMR_TID_SHIFT
;
1830 cpu_id
<< IMR_TID_SHIFT
;
1831 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr: initial "
1832 "mapping reg 0x%lx\n", tmp_mondo_vec
));
1833 #endif /* _STARFIRE */
1836 * There is already a different
1837 * ino programmed at this IMR.
1838 * Just read the IMR out to get the
1839 * correct MID target.
1841 tmp_mondo_vec
= *mondo_vec_reg
;
1842 tmp_mondo_vec
&= ~INTERRUPT_VALID
;
1843 *mondo_vec_reg
= tmp_mondo_vec
;
1844 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr: existing "
1845 "mapping reg 0x%lx\n", tmp_mondo_vec
));
1848 sbus_arg
->pil
= hdlp
->ih_pri
;
1850 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr:Alloc sbus_arg "
1851 "0x%p\n", (void *)sbus_arg
));
1854 softsp
->intr_hndlr_cnt
[slot
]++;
1856 mutex_exit(&softsp
->intr_poll_list_lock
);
1859 * Program the ino vector accordingly. This MUST be the
1860 * last thing we do. Once we program the ino, the device
1861 * may begin to interrupt. Add this hardware interrupt to
1862 * the interrupt lists, and get the CPU to target it at.
1865 tmp_mondo_vec
|= INTERRUPT_VALID
;
1867 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Add intr: Ino 0x%x mapping reg: 0x%p "
1868 "Intr cntr %d\n", ino
, (void *)mondo_vec_reg
,
1869 softsp
->intr_hndlr_cnt
[slot
]));
1871 /* Force the interrupt state machine to idle. */
1872 if (reset_ism_register
) {
1873 tmpreg
= SBUS_INTR_IDLE
;
1874 *sbus_arg
->clear_reg
= tmpreg
;
1877 /* Store it in the hardware reg. */
1878 *mondo_vec_reg
= tmp_mondo_vec
;
1880 /* Flush store buffers */
1881 tmpreg
= *softsp
->sbus_ctrl_reg
;
1888 sbus_free_handler(dev_info_t
*dip
, uint32_t inum
,
1889 struct sbus_wrapper_arg
*sbus_arg
)
1891 struct sbus_intr_handler
*listp
, *prevp
;
1895 listp
= sbus_arg
->handler_list
;
1898 if (listp
->dip
== dip
&& listp
->inum
== inum
) {
1900 prevp
->next
= listp
->next
;
1902 prevp
= listp
->next
;
1903 sbus_arg
->handler_list
= prevp
;
1907 sizeof (struct sbus_intr_handler
));
1911 listp
= listp
->next
;
1917 * remove_intrspec - Remove an interrupt specification.
1921 sbus_remove_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
1922 ddi_intr_handle_impl_t
*hdlp
)
1924 volatile uint64_t *mondo_vec_reg
;
1925 volatile uint64_t *intr_state_reg
;
1927 volatile uint64_t tmpreg
;
1929 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
1930 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
1931 int start_bit
, ino
, slot
;
1932 struct sbus_wrapper_arg
*sbus_arg
;
1934 /* Grab the mutex protecting the poll list */
1935 mutex_enter(&softsp
->intr_poll_list_lock
);
1937 /* Xlate the interrupt */
1938 if (sbus_xlate_intrs(dip
, rdip
, (uint32_t *)&hdlp
->ih_vector
,
1939 &hdlp
->ih_pri
, softsp
->intr_mapping_ign
) == DDI_FAILURE
) {
1940 cmn_err(CE_WARN
, "Can't xlate SBUS devices %s interrupt.\n",
1941 ddi_driver_name(rdip
));
1945 ino
= ((int32_t)hdlp
->ih_vector
) & SBUS_MAX_INO
;
1947 mondo_vec_reg
= (softsp
->intr_mapping_reg
+
1948 ino_table
[ino
]->mapping_reg
);
1950 /* Turn off the valid bit in the mapping register. */
1951 *mondo_vec_reg
&= ~INTERRUPT_VALID
;
1953 tmpreg
= *softsp
->sbus_ctrl_reg
;
1956 /* Get our bit position for checking intr pending */
1957 if (ino
> MAX_MONDO_EXTERNAL
) {
1958 start_bit
= ino_table
[ino
]->diagreg_shift
;
1959 intr_state_reg
= softsp
->obio_intr_state
;
1961 start_bit
= 16 * (ino
>> 3) + 2 * (ino
& 0x7);
1962 intr_state_reg
= softsp
->sbus_intr_state
;
1965 while (((*intr_state_reg
>> start_bit
) & 0x3) == INT_PENDING
&&
1969 slot
= find_sbus_slot(dip
, rdip
);
1971 /* Return if the slot is invalid */
1972 if (slot
>= MAX_SBUS_SLOT_ADDR
|| slot
< 0) {
1976 sbus_arg
= softsp
->intr_list
[ino
];
1978 /* Decrement the intr handler count on this slot */
1979 softsp
->intr_hndlr_cnt
[slot
]--;
1981 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Rem intr: Softsp 0x%p, Mondo 0x%x, "
1982 "ino 0x%x, sbus_arg 0x%p intr cntr %d\n", (void *)softsp
,
1983 hdlp
->ih_vector
, ino
, (void *)sbus_arg
,
1984 softsp
->intr_hndlr_cnt
[slot
]));
1986 ASSERT(sbus_arg
!= NULL
);
1987 ASSERT(sbus_arg
->handler_list
!= NULL
);
1988 sbus_free_handler(rdip
, hdlp
->ih_inum
, sbus_arg
);
1990 /* If we still have a list, we're done. */
1991 if (sbus_arg
->handler_list
== NULL
)
1992 i_ddi_rem_ivintr(hdlp
);
1995 * If other devices are still installed for this slot, we need to
1996 * turn the valid bit back on.
1998 if (softsp
->intr_hndlr_cnt
[slot
] > 0) {
1999 *mondo_vec_reg
|= INTERRUPT_VALID
;
2001 tmpreg
= *softsp
->sbus_ctrl_reg
;
2005 if ((softsp
->intr_hndlr_cnt
[slot
] == 0) || (slot
>= EXT_SBUS_SLOTS
)) {
2006 ASSERT(sbus_arg
->handler_list
== NULL
);
2008 /* Do cleanup for interrupt target translation */
2009 pc_ittrans_cleanup(softsp
->ittrans_cookie
, mondo_vec_reg
);
2010 #endif /* _STARFIRE */
2014 /* Free up the memory used for the sbus interrupt handler */
2015 if (sbus_arg
->handler_list
== NULL
) {
2016 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Rem intr: Freeing sbus arg "
2017 "0x%p\n", (void *)sbus_arg
));
2018 kmem_free(sbus_arg
, sizeof (struct sbus_wrapper_arg
));
2019 softsp
->intr_list
[ino
] = NULL
;
2023 mutex_exit(&softsp
->intr_poll_list_lock
);
2027 * We're prepared to claim that the interrupt string is in
2028 * the form of a list of <SBusintr> specifications, or we're dealing
2029 * with on-board devices and we have an interrupt_number property which
2030 * gives us our mondo number.
2031 * Translate the sbus levels or mondos into sysiointrspecs.
2034 sbus_xlate_intrs(dev_info_t
*dip
, dev_info_t
*rdip
, uint32_t *intr
,
2035 uint32_t *pil
, int32_t ign
)
2037 uint32_t ino
, slot
, level
= *intr
;
2038 int ret
= DDI_SUCCESS
;
2041 * Create the sysio ino number. onboard devices will have
2042 * an "interrupts" property, that is equal to the ino number.
2043 * If the devices are from the
2044 * expansion slots, we construct the ino number by putting
2045 * the slot number in the upper three bits, and the sbus
2046 * interrupt level in the lower three bits.
2048 if (level
> MAX_SBUS_LEVEL
) {
2051 /* Construct ino from slot and interrupts */
2052 if ((slot
= find_sbus_slot(dip
, rdip
)) == -1) {
2053 cmn_err(CE_WARN
, "Can't determine sbus slot "
2054 "of %s device\n", ddi_driver_name(rdip
));
2059 if (slot
>= MAX_SBUS_SLOT_ADDR
) {
2060 cmn_err(CE_WARN
, "Invalid sbus slot 0x%x"
2061 "in %s device\n", slot
, ddi_driver_name(rdip
));
2070 /* Sanity check the inos range */
2071 if (ino
>= MAX_INO_TABLE_SIZE
) {
2072 cmn_err(CE_WARN
, "Ino vector 0x%x out of range", ino
);
2076 /* Sanity check the inos value */
2077 if (!ino_table
[ino
]) {
2078 cmn_err(CE_WARN
, "Ino vector 0x%x is invalid", ino
);
2084 #define SOC_PRIORITY 5
2085 /* The sunfire i/o board has a soc in the printer slot */
2086 if ((ino_table
[ino
]->clear_reg
== PP_CLEAR
) &&
2087 ((strcmp(ddi_get_name(rdip
), "soc") == 0) ||
2088 (strcmp(ddi_get_name(rdip
), "SUNW,soc") == 0))) {
2089 *pil
= SOC_PRIORITY
;
2091 /* Figure out the pil associated with this interrupt */
2092 *pil
= interrupt_priorities
[ino
];
2096 /* Or in the upa_id into the interrupt group number field */
2097 *intr
= (uint32_t)(ino
| ign
);
2099 DPRINTF(SBUS_INTERRUPT_DEBUG
, ("Xlate intr: Interrupt info for "
2100 "device %s Mondo: 0x%x, ino: 0x%x, Pil: 0x%x, sbus level: 0x%x\n",
2101 ddi_driver_name(rdip
), *intr
, ino
, *pil
, level
));
2107 /* new intr_ops structure */
2109 sbus_intr_ops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
2110 ddi_intr_handle_impl_t
*hdlp
, void *result
)
2112 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
2113 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
2114 int ret
= DDI_SUCCESS
;
2118 case DDI_INTROP_GETCAP
:
2119 *(int *)result
= DDI_INTR_FLAG_LEVEL
;
2121 case DDI_INTROP_ALLOC
:
2122 *(int *)result
= hdlp
->ih_scratch1
;
2124 case DDI_INTROP_FREE
:
2126 case DDI_INTROP_GETPRI
:
2127 if (hdlp
->ih_pri
== 0) {
2128 /* Xlate the interrupt */
2129 (void) sbus_xlate_intrs(dip
, rdip
,
2130 (uint32_t *)&hdlp
->ih_vector
, &hdlp
->ih_pri
,
2131 softsp
->intr_mapping_ign
);
2134 *(int *)result
= hdlp
->ih_pri
;
2136 case DDI_INTROP_SETPRI
:
2138 case DDI_INTROP_ADDISR
:
2139 ret
= sbus_add_intr_impl(dip
, rdip
, hdlp
);
2141 case DDI_INTROP_REMISR
:
2142 sbus_remove_intr_impl(dip
, rdip
, hdlp
);
2144 case DDI_INTROP_ENABLE
:
2145 ret
= sbus_update_intr_state(dip
, rdip
, hdlp
,
2146 SBUS_INTR_STATE_ENABLE
);
2148 case DDI_INTROP_DISABLE
:
2149 ret
= sbus_update_intr_state(dip
, rdip
, hdlp
,
2150 SBUS_INTR_STATE_DISABLE
);
2152 case DDI_INTROP_NINTRS
:
2153 case DDI_INTROP_NAVAIL
:
2154 *(int *)result
= i_ddi_get_intx_nintrs(rdip
);
2156 case DDI_INTROP_SETCAP
:
2157 case DDI_INTROP_SETMASK
:
2158 case DDI_INTROP_CLRMASK
:
2159 case DDI_INTROP_GETPENDING
:
2162 case DDI_INTROP_SUPPORTED_TYPES
:
2163 /* Sbus nexus driver supports only fixed interrupts */
2164 *(int *)result
= i_ddi_get_intx_nintrs(rdip
) ?
2165 DDI_INTR_TYPE_FIXED
: 0;
2168 ret
= i_ddi_intr_ops(dip
, rdip
, intr_op
, hdlp
, result
);
2177 * Called by suspend/resume to save/restore the interrupt status (valid bit)
2178 * of the interrupt mapping registers.
2181 sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp
, volatile uint64_t *baddr
,
2185 volatile uint64_t *mondo_vec_reg
;
2187 for (i
= 0; i
< MAX_INO_TABLE_SIZE
; i
++) {
2188 if (ino_table
[i
] != NULL
) {
2189 mondo_vec_reg
= baddr
+ ino_table
[i
]->mapping_reg
;
2191 if (*mondo_vec_reg
& INTERRUPT_VALID
) {
2192 cpr_softsp
[i
] = *mondo_vec_reg
;
2195 if (cpr_softsp
[i
]) {
2196 *mondo_vec_reg
= cpr_softsp
[i
];
2203 #define SZ_INO_TABLE (sizeof (ino_table) / sizeof (ino_table[0]))
2208 * This function retargets active interrupts by reprogramming the mondo
2209 * vec register. If the CPU ID of the target has not changed, then
2210 * the mondo is not reprogrammed. The routine must hold the mondo
2211 * lock for this instance of the sbus.
2214 sbus_intrdist(void *arg
)
2216 struct sbus_soft_state
*softsp
;
2217 dev_info_t
*dip
= (dev_info_t
*)arg
;
2218 volatile uint64_t *mondo_vec_reg
;
2219 uint64_t *last_mondo_vec_reg
;
2221 volatile uint64_t *intr_state_reg
;
2223 volatile uint64_t tmpreg
; /* HW flush reg */
2227 /* extract the soft state pointer */
2228 softsp
= ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
2230 last_mondo_vec_reg
= NULL
;
2231 for (mondo
= 0; mondo
< SZ_INO_TABLE
; mondo
++) {
2232 if (ino_table
[mondo
] == NULL
)
2235 mondo_vec_reg
= (softsp
->intr_mapping_reg
+
2236 ino_table
[mondo
]->mapping_reg
);
2238 /* Don't reprogram the same register twice */
2239 if (mondo_vec_reg
== last_mondo_vec_reg
)
2242 if ((*mondo_vec_reg
& INTERRUPT_VALID
) == 0)
2245 last_mondo_vec_reg
= (uint64_t *)mondo_vec_reg
;
2247 cpu_id
= intr_dist_cpuid();
2250 * For Starfire it is a pain to check the current target for
2251 * the mondo since we have to read the PC asics ITTR slot
2252 * assigned to this mondo. It will be much easier to assume
2253 * the current target is always different and do the target
2254 * reprogram all the time.
2257 if (((*mondo_vec_reg
& IMR_TID
) >> IMR_TID_SHIFT
) == cpu_id
) {
2258 /* It is the same, don't reprogram */
2261 #endif /* _STARFIRE */
2263 /* So it's OK to reprogram the CPU target */
2265 /* turn off valid bit and wait for the state machine to idle */
2266 *mondo_vec_reg
&= ~INTERRUPT_VALID
;
2268 tmpreg
= *softsp
->sbus_ctrl_reg
;
2274 if (mondo
> MAX_MONDO_EXTERNAL
) {
2275 start_bit
= ino_table
[mondo
]->diagreg_shift
;
2276 intr_state_reg
= softsp
->obio_intr_state
;
2279 * Loop waiting for state machine to idle. Do not keep
2280 * looping on a panic so that the system does not hang.
2282 while ((((*intr_state_reg
>> start_bit
) & 0x3) ==
2283 INT_PENDING
) && !panicstr
)
2286 int int_pending
= 0; /* interrupts pending */
2289 * Shift over to first bit for this Sbus slot, 16
2290 * bits per slot, bits 0-1 of each slot are reserved.
2292 start_bit
= 16 * (mondo
>> 3) + 2;
2293 intr_state_reg
= softsp
->sbus_intr_state
;
2296 * Make sure interrupts for levels 1-7 of this slot
2300 int level
; /* Sbus interrupt level */
2301 int shift
; /* # of bits to shift */
2302 uint64_t state_reg
= *intr_state_reg
;
2306 for (shift
= start_bit
, level
= 1; level
< 8;
2307 level
++, shift
+= 2) {
2308 if (((state_reg
>> shift
) &
2309 0x3) == INT_PENDING
) {
2314 } while (int_pending
&& !panicstr
);
2317 /* re-target the mondo and turn it on */
2319 mondo_vec
= (pc_translate_tgtid(softsp
->ittrans_cookie
,
2320 cpu_id
, mondo_vec_reg
) <<
2321 INTERRUPT_CPU_FIELD
) |
2324 mondo_vec
= (cpu_id
<< INTERRUPT_CPU_FIELD
) | INTERRUPT_VALID
;
2325 #endif /* _STARFIRE */
2327 /* write it back to the hardware. */
2328 *mondo_vec_reg
= mondo_vec
;
2330 /* flush the hardware buffers. */
2331 tmpreg
= *mondo_vec_reg
;
2340 * Reset interrupts to IDLE. This function is called during
2341 * panic handling after redistributing interrupts; it's needed to
2342 * support dumping to network devices after 'sync' from OBP.
2344 * N.B. This routine runs in a context where all other threads
2345 * are permanently suspended.
2348 sbus_intr_reset(void *arg
)
2350 dev_info_t
*dip
= (dev_info_t
*)arg
;
2351 struct sbus_soft_state
*softsp
;
2353 volatile uint64_t *mondo_clear_reg
;
2355 softsp
= ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
2357 for (mondo
= 0; mondo
< SZ_INO_TABLE
; mondo
++) {
2358 if (ino_table
[mondo
] == NULL
||
2359 ino_table
[mondo
]->clear_reg
== NULL
) {
2364 mondo_clear_reg
= (softsp
->clr_intr_reg
+
2365 ino_table
[mondo
]->clear_reg
);
2366 *mondo_clear_reg
= SBUS_INTR_IDLE
;
2373 * called from sbus_add_kstats() to create a kstat for each %pic
2374 * that the SBUS supports. These (read-only) kstats export the
2375 * event names that each %pic supports.
2377 * if we fail to create any of these kstats we must remove any
2378 * that we have already created and return;
2380 * NOTE: because all sbus devices use the same events we only
2381 * need to create the picN kstats once. All instances can
2382 * use the same picN kstats.
2384 * The flexibility exists to allow each device specify it's
2385 * own events by creating picN kstats with the instance number
2386 * set to ddi_get_instance(softsp->dip).
2388 * When searching for a picN kstat for a device you should
2389 * first search for a picN kstat using the instance number
2390 * of the device you are interested in. If that fails you
2391 * should use the first picN kstat found for that device.
2394 sbus_add_picN_kstats(dev_info_t
*dip
)
2397 * SBUS Performance Events.
2399 * We declare an array of event-names and event-masks.
2400 * The num of events in this array is AC_NUM_EVENTS.
2402 sbus_event_mask_t sbus_events_arr
[SBUS_NUM_EVENTS
] = {
2403 {"dvma_stream_rd", 0x0}, {"dvma_stream_wr", 0x1},
2404 {"dvma_const_rd", 0x2}, {"dvma_const_wr", 0x3},
2405 {"dvma_tlb_misses", 0x4}, {"dvma_stream_buf_mis", 0x5},
2406 {"dvma_cycles", 0x6}, {"dvma_bytes_xfr", 0x7},
2407 {"interrupts", 0x8}, {"upa_inter_nack", 0x9},
2408 {"pio_reads", 0xA}, {"pio_writes", 0xB},
2409 {"sbus_reruns", 0xC}, {"pio_cycles", 0xD}
2413 * We declare an array of clear masks for each pic.
2414 * These masks are used to clear the %pcr bits for
2417 sbus_event_mask_t sbus_clear_pic
[SBUS_NUM_PICS
] = {
2419 {"clear_pic", (uint64_t)~(0xf)},
2421 {"clear_pic", (uint64_t)~(0xf << 8)}
2424 struct kstat_named
*sbus_pic_named_data
;
2427 int instance
= ddi_get_instance(dip
);
2430 for (pic
= 0; pic
< SBUS_NUM_PICS
; pic
++) {
2432 * create the picN kstat. The size of this kstat is
2433 * SBUS_NUM_EVENTS + 1 for the clear_event_mask
2435 (void) sprintf(pic_name
, "pic%d", pic
); /* pic0, pic1 ... */
2436 if ((sbus_picN_ksp
[pic
] = kstat_create("sbus",
2437 instance
, pic_name
, "bus", KSTAT_TYPE_NAMED
,
2438 SBUS_NUM_EVENTS
+ 1, NULL
)) == NULL
) {
2439 cmn_err(CE_WARN
, "sbus %s: kstat_create failed",
2442 /* remove pic0 kstat if pic1 create fails */
2444 kstat_delete(sbus_picN_ksp
[0]);
2445 sbus_picN_ksp
[0] = NULL
;
2450 sbus_pic_named_data
=
2451 (struct kstat_named
*)(sbus_picN_ksp
[pic
]->ks_data
);
2454 * when we are writing pcr_masks to the kstat we need to
2455 * shift bits left by 8 for pic1 events.
2461 * for each picN event we need to write a kstat record
2462 * (name = EVENT, value.ui64 = PCR_MASK)
2464 for (event
= 0; event
< SBUS_NUM_EVENTS
; event
++) {
2467 sbus_pic_named_data
[event
].value
.ui64
=
2468 sbus_events_arr
[event
].pcr_mask
<< pic_shift
;
2471 kstat_named_init(&sbus_pic_named_data
[event
],
2472 sbus_events_arr
[event
].event_name
,
2477 * we add the clear_pic event and mask as the last
2478 * record in the kstat
2481 sbus_pic_named_data
[SBUS_NUM_EVENTS
].value
.ui64
=
2482 sbus_clear_pic
[pic
].pcr_mask
;
2485 kstat_named_init(&sbus_pic_named_data
[SBUS_NUM_EVENTS
],
2486 sbus_clear_pic
[pic
].event_name
,
2489 kstat_install(sbus_picN_ksp
[pic
]);
2494 sbus_add_kstats(struct sbus_soft_state
*softsp
)
2496 struct kstat
*sbus_counters_ksp
;
2497 struct kstat_named
*sbus_counters_named_data
;
2500 * Create the picN kstats if we are the first instance
2501 * to attach. We use sbus_attachcnt as a count of how
2502 * many instances have attached. This is protected by
2505 mutex_enter(&sbus_attachcnt_mutex
);
2506 if (sbus_attachcnt
== 0)
2507 sbus_add_picN_kstats(softsp
->dip
);
2510 mutex_exit(&sbus_attachcnt_mutex
);
2513 * A "counter" kstat is created for each sbus
2514 * instance that provides access to the %pcr and %pic
2515 * registers for that instance.
2517 * The size of this kstat is SBUS_NUM_PICS + 1 for %pcr
2519 if ((sbus_counters_ksp
= kstat_create("sbus",
2520 ddi_get_instance(softsp
->dip
), "counters",
2521 "bus", KSTAT_TYPE_NAMED
, SBUS_NUM_PICS
+ 1,
2522 KSTAT_FLAG_WRITABLE
)) == NULL
) {
2524 cmn_err(CE_WARN
, "sbus%d counters: kstat_create"
2525 " failed", ddi_get_instance(softsp
->dip
));
2529 sbus_counters_named_data
=
2530 (struct kstat_named
*)(sbus_counters_ksp
->ks_data
);
2532 /* initialize the named kstats */
2533 kstat_named_init(&sbus_counters_named_data
[0],
2534 "pcr", KSTAT_DATA_UINT64
);
2536 kstat_named_init(&sbus_counters_named_data
[1],
2537 "pic0", KSTAT_DATA_UINT64
);
2539 kstat_named_init(&sbus_counters_named_data
[2],
2540 "pic1", KSTAT_DATA_UINT64
);
2542 sbus_counters_ksp
->ks_update
= sbus_counters_kstat_update
;
2543 sbus_counters_ksp
->ks_private
= (void *)softsp
;
2545 kstat_install(sbus_counters_ksp
);
2547 /* update the sofstate */
2548 softsp
->sbus_counters_ksp
= sbus_counters_ksp
;
2552 sbus_counters_kstat_update(kstat_t
*ksp
, int rw
)
2554 struct kstat_named
*sbus_counters_data
;
2555 struct sbus_soft_state
*softsp
;
2556 uint64_t pic_register
;
2558 sbus_counters_data
= (struct kstat_named
*)ksp
->ks_data
;
2559 softsp
= (struct sbus_soft_state
*)ksp
->ks_private
;
2561 if (rw
== KSTAT_WRITE
) {
2564 * Write the pcr value to the softsp->sbus_pcr.
2565 * The pic register is read-only so we don't
2566 * attempt to write to it.
2570 (uint32_t)sbus_counters_data
[0].value
.ui64
;
2574 * Read %pcr and %pic register values and write them
2575 * into counters kstat.
2577 * Due to a hardware bug we need to right shift the %pcr
2578 * by 4 bits. This is only done when reading the %pcr.
2582 sbus_counters_data
[0].value
.ui64
= *softsp
->sbus_pcr
>> 4;
2584 pic_register
= *softsp
->sbus_pic
;
2586 * sbus pic register:
2592 sbus_counters_data
[1].value
.ui64
= pic_register
>> 32;
2594 sbus_counters_data
[2].value
.ui64
=
2595 pic_register
& SBUS_PIC0_MASK
;
2602 sbus_update_intr_state(dev_info_t
*dip
, dev_info_t
*rdip
,
2603 ddi_intr_handle_impl_t
*hdlp
, uint_t new_intr_state
)
2605 struct sbus_soft_state
*softsp
= (struct sbus_soft_state
*)
2606 ddi_get_soft_state(sbusp
, ddi_get_instance(dip
));
2608 struct sbus_wrapper_arg
*sbus_arg
;
2609 struct sbus_intr_handler
*intr_handler
;
2611 /* Xlate the interrupt */
2612 if (sbus_xlate_intrs(dip
, rdip
, (uint32_t *)&hdlp
->ih_vector
,
2613 &hdlp
->ih_pri
, softsp
->intr_mapping_ign
) == DDI_FAILURE
) {
2614 cmn_err(CE_WARN
, "sbus_update_intr_state() can't xlate SBUS "
2615 "devices %s interrupt.", ddi_driver_name(rdip
));
2616 return (DDI_FAILURE
);
2619 ino
= ((int32_t)hdlp
->ih_vector
) & SBUS_MAX_INO
;
2620 sbus_arg
= softsp
->intr_list
[ino
];
2622 ASSERT(sbus_arg
!= NULL
);
2623 ASSERT(sbus_arg
->handler_list
!= NULL
);
2624 intr_handler
= sbus_arg
->handler_list
;
2626 while (intr_handler
) {
2627 if ((intr_handler
->inum
== hdlp
->ih_inum
) &&
2628 (intr_handler
->dip
== rdip
)) {
2629 intr_handler
->intr_state
= new_intr_state
;
2630 return (DDI_SUCCESS
);
2633 intr_handler
= intr_handler
->next
;
2636 return (DDI_FAILURE
);