998 obsolete DMA driver interfaces should be removed
[unleashed.git] / usr / src / uts / sun4u / io / sysiosbus.c
blob71ec224b19ca1583af5918ff797a455987f09ae3
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
31 #include <sys/conf.h>
32 #include <sys/ddi.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>
40 #include <sys/kmem.h>
41 #include <sys/debug.h>
42 #include <sys/sysmacros.h>
43 #include <sys/autoconf.h>
44 #include <sys/spl.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>
53 #ifdef _STARFIRE
54 #include <sys/starfire.h>
55 #endif /* _STARFIRE */
56 #include <sys/sdt.h>
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
70 * table.
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,
137 KBDMOUSE_CLEAR,
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,
142 THERMAL_CLEAR,
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,
168 &ino_exp
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 */
185 -1, /* Not in use */
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 */
197 10, /* PM Wakeup */
200 /* Interrupt counter flag. To enable/disable spurious interrupt counter. */
201 static int intr_cntr_on;
204 * Function prototypes.
206 static int
207 sbus_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
209 static int
210 sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
211 ddi_intr_handle_impl_t *hdlp);
213 static void
214 sbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
215 ddi_intr_handle_impl_t *hdlp);
217 static int
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);
221 static int
222 sbus_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, uint32_t *intr,
223 uint32_t *pil, int32_t ign);
225 static int
226 sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
228 static int
229 sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
231 static int
232 sbus_do_detach(dev_info_t *devi);
234 static void
235 sbus_add_picN_kstats(dev_info_t *dip);
237 static void
238 sbus_add_kstats(struct sbus_soft_state *);
240 static int
241 sbus_counters_kstat_update(kstat_t *, int);
243 extern int
244 sysio_err_uninit(struct sbus_soft_state *softsp);
246 extern int
247 iommu_uninit(struct sbus_soft_state *softsp);
249 extern int
250 stream_buf_uninit(struct sbus_soft_state *softsp);
252 static int
253 find_sbus_slot(dev_info_t *dip, dev_info_t *rdip);
255 static void make_sbus_ppd(dev_info_t *child);
257 static int
258 sbusmem_initchild(dev_info_t *dip, dev_info_t *child);
260 static int
261 sbus_initchild(dev_info_t *dip, dev_info_t *child);
263 static int
264 sbus_uninitchild(dev_info_t *dip);
266 static int
267 sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args);
269 static int
270 sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args,
271 void *result);
273 static int
274 sbus_init(struct sbus_soft_state *softsp, caddr_t address);
276 static int
277 sbus_resume_init(struct sbus_soft_state *softsp, int resume);
279 static void
280 sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr,
281 int flag);
283 static void sbus_intrdist(void *);
284 static uint_t sbus_intr_reset(void *);
286 static int
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);
290 #ifdef _STARFIRE
291 void
292 pc_ittrans_init(int, caddr_t *);
294 void
295 pc_ittrans_uninit(caddr_t);
298 pc_translate_tgtid(caddr_t, int, volatile uint64_t *);
300 void
301 pc_ittrans_cleanup(caddr_t, volatile uint64_t *);
302 #endif /* _STARFIRE */
305 * Configuration data structures
307 static struct bus_ops sbus_bus_ops = {
308 BUSO_REV,
309 i_ddi_bus_map,
313 i_ddi_map_fault,
315 iommu_dma_allochdl,
316 iommu_dma_freehdl,
317 iommu_dma_bindhdl,
318 iommu_dma_unbindhdl,
319 iommu_dma_flush,
320 iommu_dma_win,
321 iommu_dma_mctl,
322 sbus_ctlops,
323 ddi_bus_prop_op,
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 = {
340 nodev, /* open */
341 nodev, /* close */
342 nodev, /* strategy */
343 nodev, /* print */
344 nodev, /* dump */
345 nodev, /* read */
346 nodev, /* write */
347 nodev, /* ioctl */
348 nodev, /* devmap */
349 nodev, /* mmap */
350 nodev, /* segmap */
351 nochpoll, /* poll */
352 ddi_prop_op, /* prop_op */
353 NULL,
354 D_NEW | D_MP | D_HOTPLUG,
355 CB_REV, /* rev */
356 nodev, /* int (*cb_aread)() */
357 nodev /* int (*cb_awrite)() */
360 static struct dev_ops sbus_ops = {
361 DEVO_REV, /* devo_rev, */
362 0, /* refcnt */
363 ddi_no_info, /* info */
364 nulldev, /* identify */
365 nulldev, /* probe */
366 sbus_attach, /* attach */
367 sbus_detach, /* detach */
368 nodev, /* reset */
369 &sbus_cb_ops, /* driver operations */
370 &sbus_bus_ops, /* bus operations */
371 nulldev, /* power */
372 ddi_quiesce_not_supported, /* devo_quiesce */
375 /* global data */
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.
399 _init(void)
401 int error;
403 if ((error = ddi_soft_state_init(&sbusp,
404 sizeof (struct sbus_soft_state), 1)) != 0)
405 return (error);
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)
412 return (error);
414 /* Initialize global mutex */
415 mutex_init(&sbus_attachcnt_mutex, NULL, MUTEX_DRIVER, NULL);
417 return (mod_install(&modlinkage));
421 _fini(void)
423 int error;
425 if ((error = mod_remove(&modlinkage)) != 0)
426 return (error);
428 mutex_destroy(&sbus_attachcnt_mutex);
429 ddi_soft_state_fini(&sbusp);
430 ddi_soft_state_fini(&sbus_cprp);
431 return (0);
435 _info(struct modinfo *modinfop)
437 return (mod_info(&modlinkage, modinfop));
440 /*ARGSUSED*/
441 static int
442 sbus_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
444 struct sbus_soft_state *softsp;
445 int instance, error;
446 uint64_t *cpr_softsp;
447 ddi_device_acc_attr_t attr;
450 #ifdef DEBUG
451 debug_info = 1;
452 debug_print_level = 0;
453 #endif
455 instance = ddi_get_instance(devi);
457 switch (cmd) {
458 case DDI_ATTACH:
459 break;
461 case DDI_RESUME:
462 softsp = ddi_get_soft_state(sbusp, instance);
464 if ((error = iommu_resume_init(softsp)) != DDI_SUCCESS)
465 return (error);
467 if ((error = sbus_resume_init(softsp, 1)) != DDI_SUCCESS)
468 return (error);
470 if ((error = stream_buf_resume_init(softsp)) != DDI_SUCCESS)
471 return (error);
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);
486 default:
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 */
496 softsp->dip = devi;
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"
501 "property.");
502 error = DDI_FAILURE;
503 goto bad;
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));
533 return (0);
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));
544 #ifdef notdef
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.
553 caddr_t addr;
554 int rv;
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",
561 rv);
562 } else {
563 cmn_err(CE_CONT, "?sbus: ddi_map_regs returned "
564 " virtual address 0x%x\n", addr);
567 #endif /* notdef */
569 if ((error = iommu_init(softsp, softsp->address)) != DDI_SUCCESS)
570 goto bad;
572 if ((error = sbus_init(softsp, softsp->address)) != DDI_SUCCESS)
573 goto bad;
575 if ((error = sysio_err_init(softsp, softsp->address)) != DDI_SUCCESS)
576 goto bad;
578 if ((error = stream_buf_init(softsp, softsp->address)) != DDI_SUCCESS)
579 goto bad;
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);
595 bad:
596 ddi_soft_state_free(sbusp, instance);
597 return (error);
600 /* ARGSUSED */
601 static int
602 sbus_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
604 int instance;
605 struct sbus_soft_state *softsp;
606 uint64_t *cpr_softsp;
608 switch (cmd) {
609 case DDI_SUSPEND:
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
614 * is resumed.
616 instance = ddi_get_instance(devi);
618 if (ddi_soft_state_zalloc(sbus_cprp, instance)
619 != DDI_SUCCESS)
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);
630 case DDI_DETACH:
631 return (sbus_do_detach(devi));
632 default:
633 return (DDI_FAILURE);
637 static int
638 sbus_do_detach(dev_info_t *devi)
640 int instance, pic;
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) {
653 goto err;
656 /* remove the interrupt handlers from the system */
657 if (sysio_err_uninit(softsp) == DDI_FAILURE) {
658 goto err;
661 /* disable the IOMMU */
662 if (iommu_uninit(softsp)) {
663 goto err;
666 /* unmap register space if we have a handle */
667 if (softsp->ac) {
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);
685 sbus_attachcnt --;
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);
696 #ifdef _STARFIRE
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);
705 err:
706 return (DDI_FAILURE);
709 static int
710 sbus_init(struct sbus_soft_state *softsp, caddr_t address)
712 int i;
713 extern void set_intr_mapping_reg(int, uint64_t *, int);
714 int numproxy;
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);
737 #undef REG_ADDR
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));
743 #ifdef _STARFIRE
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);
780 if (numproxy > 0)
781 set_intr_mapping_reg(softsp->upa_id,
782 (uint64_t *)(softsp->intr_mapping_reg +
783 FFB_MAPPING_REG), 1);
785 if (numproxy > 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. */
793 #ifndef DEBUG
794 intr_cntr_on = 1;
795 #else
796 intr_cntr_on = 0;
797 #endif
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.
807 static int
808 sbus_resume_init(struct sbus_soft_state *softsp, int resume)
810 int i;
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!!!
818 #ifdef _STARFIRE
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)
837 << SYSIO_IGN;
838 #else
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)
856 | SYSIO_BURST_RANGE;
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;
864 if (!resume) {
865 /* Set burstsizes to smallest value */
866 for (i = 0; i < MAX_SBUS_SLOTS; i++) {
867 volatile uint64_t *config;
868 uint64_t tmpreg;
870 config = softsp->sbus_slot_config_reg + i;
872 /* Write out the burst size */
873 tmpreg = (uint64_t)0;
874 *config = tmpreg;
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,
881 (void *)config));
883 } else {
884 /* Program the slot configuration registers */
885 for (i = 0; i < MAX_SBUS_SLOTS; i++) {
886 volatile uint64_t *config;
887 #ifndef lint
888 uint64_t tmpreg;
889 #endif /* !lint */
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 */
899 slave_burstsizes =
900 softsp->sbus_slave_burstsizes[i] >>
901 SYSIO64_BURST_SHIFT;
903 /* Turn on 64 bit PIO's on the sbus */
904 *config |= SBUS_ETM;
905 } else {
906 slave_burstsizes =
907 softsp->sbus_slave_burstsizes[i] &
908 SYSIO_BURST_MASK;
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 */
918 #ifndef lint
919 tmpreg = *softsp->sbus_ctrl_reg;
920 #endif /* !lint */
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))
933 struct prop_ispec {
934 uint_t pri, vec;
938 * Create a sysio_parent_private_data structure from the ddi properties of
939 * the dev_info node.
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
943 * of the device.
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
959 * <SBus-level>*1
961 * (This property obsoletes the 'intr' property).
963 * The OBP_RANGES property is optional.
965 static void
966 make_sbus_ppd(dev_info_t *child)
968 struct sysio_parent_private_data *pdptr;
969 int n;
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)
978 return;
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, &reg_prop, &reg_len) != DDI_SUCCESS)
993 reg_len = 0;
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;
1000 if (reg_len != 0) {
1001 pdptr->slot = ((struct regspec *)reg_prop)->regspec_bustype;
1002 pdptr->offset = ((struct regspec *)reg_prop)->regspec_addr;
1005 rgstr_len = 0;
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;
1017 int i;
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;
1025 if (reg_len != 0)
1026 kmem_free(reg_prop, reg_len);
1028 reg_prop = rgstr_prop;
1029 reg_len = rgstr_len;
1031 if (reg_len != 0) {
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) ==
1040 DDI_SUCCESS) {
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
1053 * the child node.
1055 static int
1056 sbusmem_initchild(dev_info_t *dip, dev_info_t *child)
1058 int i, n;
1059 int slot, size;
1060 char ident[10];
1062 slot = ddi_getprop(DDI_DEV_T_NONE, child,
1063 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "slot", -1);
1064 if (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) {
1077 struct regspec r;
1079 /* create reg property */
1081 r.regspec_bustype = (uint_t)slot;
1082 r.regspec_addr = 0;
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
1107 * in the buffer.
1109 static int
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
1123 name[0] = '\0';
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:
1138 * Property value
1139 * Name type
1141 * reg register spec
1142 * registers wildcard s/w sbus register spec (.conf file property)
1143 * intr old-form interrupt spec
1144 * interrupts new (bus-oriented) interrupt spec
1145 * ranges range spec
1147 static int
1148 sbus_initchild(dev_info_t *dip, dev_info_t *child)
1150 char name[MAXNAMELEN];
1151 ulong_t slave_burstsizes;
1152 int slot;
1153 volatile uint64_t *slot_reg;
1154 #ifndef lint
1155 uint64_t tmp;
1156 #endif /* !lint */
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) {
1172 int len = 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) {
1202 #ifdef DEBUG
1203 cmn_err(CE_WARN, "?Invalid sbus slot address 0x%x for %s "
1204 "device\n", slot, ddi_get_name(child));
1205 #endif /* DEBUG */
1206 goto done;
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
1224 * too.
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)
1249 goto done;
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] &=
1257 (slave_burstsizes &
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;
1271 } else {
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] &
1277 SYSIO_BURST_MASK) {
1278 burstsizes =
1279 softsp->sbus_slave_burstsizes[slot] &
1280 SYSIO_BURST_MASK;
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 */
1294 #ifndef lint
1295 tmp = *slot_reg;
1296 #endif /* !lint */
1299 done:
1300 return (DDI_SUCCESS);
1303 static int
1304 sbus_uninitchild(dev_info_t *dip)
1306 struct sysio_parent_private_data *pdptr;
1307 size_t n;
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);
1329 #ifdef DEBUG
1330 int sbus_peekfault_cnt = 0;
1331 int sbus_pokefault_cnt = 0;
1332 #endif /* DEBUG */
1334 static int
1335 sbus_ctlops_poke(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args)
1337 int err = DDI_SUCCESS;
1338 on_trap_data_t otd;
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;
1356 } else
1357 err = DDI_FAILURE;
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. */
1373 no_trap();
1375 softsp->ontrap_data = NULL;
1376 mutex_exit(&softsp->pokefault_mutex);
1378 #ifdef DEBUG
1379 if (err == DDI_FAILURE)
1380 sbus_pokefault_cnt++;
1381 #endif
1382 return (err);
1385 /*ARGSUSED*/
1386 static int
1387 sbus_ctlops_peek(struct sbus_soft_state *softsp, peekpoke_ctlops_t *in_args,
1388 void *result)
1390 int err = DDI_SUCCESS;
1391 on_trap_data_t otd;
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;
1405 } else
1406 err = DDI_FAILURE;
1408 #ifdef DEBUG
1409 if (err == DDI_FAILURE)
1410 sbus_peekfault_cnt++;
1411 #endif
1412 no_trap();
1413 return (err);
1416 static int
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));
1423 switch (op) {
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)
1441 val = maxbit(val,
1442 (1 << (ddi_fls(softsp->sbus_burst_sizes) - 1)));
1443 else
1444 val = maxbit(val,
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: {
1452 dev_info_t *pdev;
1453 int i, n, len, f_len;
1454 char *msgbuf;
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++) {
1480 struct regspec *rp;
1482 rp = sysio_pd_getreg(rdip, i);
1483 if (i != 0) {
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;
1498 if (i != 0) {
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 ");
1514 else
1515 f_len += snprintf(msgbuf + len,
1516 REPORTDEV_BUFSIZE - len, " SBus level %d ",
1517 sbuslevel);
1518 len = strlen(msgbuf);
1520 f_len += snprintf(msgbuf + len, REPORTDEV_BUFSIZE - len,
1521 "sparc9 ipl %d", pri);
1522 len = strlen(msgbuf);
1524 #ifdef DEBUG
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);
1529 #endif /* DEBUG */
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;
1543 int r_slot, b_slot;
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,
1563 result));
1565 case DDI_CTLOPS_DVMAPAGESIZE:
1566 *(ulong_t *)result = IOMMU_PAGESIZE;
1567 return (DDI_SUCCESS);
1569 default:
1570 return (ddi_ctlops(dip, rdip, op, arg, result));
1574 static int
1575 find_sbus_slot(dev_info_t *dip, dev_info_t *rdip)
1577 dev_info_t *child;
1578 int slot = -1;
1581 * look for the node that's a direct child of this Sbus node.
1583 while (rdip && (child = ddi_get_parent(rdip)) != dip) {
1584 rdip = child;
1588 * If there is one, get the slot number of *my* child
1590 if (child == dip)
1591 slot = sysio_pd_getslot(rdip);
1593 return (slot);
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
1608 static uint_t
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;
1626 int r;
1628 if (intr_handler->intr_state == SBUS_INTR_STATE_DISABLE) {
1629 intr_handler = intr_handler->next;
1630 continue;
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);
1641 intr_return |= 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) {
1652 (*spurious_cntr)++;
1654 if (*spurious_cntr < MAX_INTR_CNT) {
1655 if (intr_cntr_on)
1656 return (DDI_INTR_CLAIMED);
1658 #ifdef DEBUG
1659 else if (intr_info->pil >= LOCK_LEVEL) {
1660 cmn_err(CE_PANIC, "%d unclaimed interrupts at "
1661 "interrupt level %d", MAX_INTR_CNT,
1662 intr_info->pil);
1664 #endif
1667 * Reset spurious counter once we acknowledge
1668 * it to the system level.
1670 *spurious_cntr = (uchar_t)0;
1671 } else {
1672 *spurious_cntr = (uchar_t)0;
1675 return (intr_return);
1679 * add_intrspec - Add an interrupt specification.
1681 static int
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 */
1691 uint_t start_bit;
1692 int ino;
1693 uint_t cpu_id;
1694 struct sbus_wrapper_arg *sbus_arg;
1695 struct sbus_intr_handler *intr_handler;
1696 uint32_t slot;
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",
1705 slot);
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;
1734 } else {
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 */
1758 if (sbus_arg) {
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;
1764 #ifdef lint
1765 tmpreg = tmpreg;
1766 #endif
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)
1777 /* empty */;
1779 intr_handler->next = sbus_arg->handler_list;
1780 sbus_arg->handler_list = intr_handler;
1782 reset_ism_register = 0;
1783 } else {
1784 sbus_arg = kmem_zalloc(sizeof (struct sbus_wrapper_arg),
1785 KM_SLEEP);
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);
1817 goto done;
1820 if ((slot >= EXT_SBUS_SLOTS) ||
1821 (softsp->intr_hndlr_cnt[slot] == 0)) {
1823 cpu_id = intr_dist_cpuid();
1824 #ifdef _STARFIRE
1825 tmp_mondo_vec = pc_translate_tgtid(
1826 softsp->ittrans_cookie, cpu_id,
1827 mondo_vec_reg) << IMR_TID_SHIFT;
1828 #else
1829 tmp_mondo_vec =
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 */
1834 } else {
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;
1883 done:
1884 return (ret);
1887 static void
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;
1893 if (sbus_arg) {
1894 prevp = NULL;
1895 listp = sbus_arg->handler_list;
1897 while (listp) {
1898 if (listp->dip == dip && listp->inum == inum) {
1899 if (prevp)
1900 prevp->next = listp->next;
1901 else {
1902 prevp = listp->next;
1903 sbus_arg->handler_list = prevp;
1906 kmem_free(listp,
1907 sizeof (struct sbus_intr_handler));
1908 break;
1910 prevp = listp;
1911 listp = listp->next;
1917 * remove_intrspec - Remove an interrupt specification.
1919 /*ARGSUSED*/
1920 static void
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;
1926 #ifndef lint
1927 volatile uint64_t tmpreg;
1928 #endif /* !lint */
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));
1942 goto done;
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;
1952 #ifndef lint
1953 tmpreg = *softsp->sbus_ctrl_reg;
1954 #endif /* !lint */
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;
1960 } else {
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 &&
1966 !panicstr)
1967 /* empty */;
1969 slot = find_sbus_slot(dip, rdip);
1971 /* Return if the slot is invalid */
1972 if (slot >= MAX_SBUS_SLOT_ADDR || slot < 0) {
1973 goto done;
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;
2000 #ifndef lint
2001 tmpreg = *softsp->sbus_ctrl_reg;
2002 #endif /* !lint */
2005 if ((softsp->intr_hndlr_cnt[slot] == 0) || (slot >= EXT_SBUS_SLOTS)) {
2006 ASSERT(sbus_arg->handler_list == NULL);
2007 #ifdef _STARFIRE
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;
2022 done:
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.
2033 static int
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) {
2049 ino = level;
2050 } else {
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));
2055 ret = DDI_FAILURE;
2056 goto done;
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));
2062 ret = DDI_FAILURE;
2063 goto done;
2066 ino = slot << 3;
2067 ino |= level;
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);
2073 ret = DDI_FAILURE;
2074 goto done;
2076 /* Sanity check the inos value */
2077 if (!ino_table[ino]) {
2078 cmn_err(CE_WARN, "Ino vector 0x%x is invalid", ino);
2079 ret = DDI_FAILURE;
2080 goto done;
2083 if (*pil == 0) {
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;
2090 } else {
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));
2103 done:
2104 return (ret);
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;
2117 switch (intr_op) {
2118 case DDI_INTROP_GETCAP:
2119 *(int *)result = DDI_INTR_FLAG_LEVEL;
2120 break;
2121 case DDI_INTROP_ALLOC:
2122 *(int *)result = hdlp->ih_scratch1;
2123 break;
2124 case DDI_INTROP_FREE:
2125 break;
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;
2135 break;
2136 case DDI_INTROP_SETPRI:
2137 break;
2138 case DDI_INTROP_ADDISR:
2139 ret = sbus_add_intr_impl(dip, rdip, hdlp);
2140 break;
2141 case DDI_INTROP_REMISR:
2142 sbus_remove_intr_impl(dip, rdip, hdlp);
2143 break;
2144 case DDI_INTROP_ENABLE:
2145 ret = sbus_update_intr_state(dip, rdip, hdlp,
2146 SBUS_INTR_STATE_ENABLE);
2147 break;
2148 case DDI_INTROP_DISABLE:
2149 ret = sbus_update_intr_state(dip, rdip, hdlp,
2150 SBUS_INTR_STATE_DISABLE);
2151 break;
2152 case DDI_INTROP_NINTRS:
2153 case DDI_INTROP_NAVAIL:
2154 *(int *)result = i_ddi_get_intx_nintrs(rdip);
2155 break;
2156 case DDI_INTROP_SETCAP:
2157 case DDI_INTROP_SETMASK:
2158 case DDI_INTROP_CLRMASK:
2159 case DDI_INTROP_GETPENDING:
2160 ret = DDI_ENOTSUP;
2161 break;
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;
2166 break;
2167 default:
2168 ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
2169 break;
2172 return (ret);
2177 * Called by suspend/resume to save/restore the interrupt status (valid bit)
2178 * of the interrupt mapping registers.
2180 static void
2181 sbus_cpr_handle_intr_map_reg(uint64_t *cpr_softsp, volatile uint64_t *baddr,
2182 int save)
2184 int i;
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;
2190 if (save) {
2191 if (*mondo_vec_reg & INTERRUPT_VALID) {
2192 cpr_softsp[i] = *mondo_vec_reg;
2194 } else {
2195 if (cpr_softsp[i]) {
2196 *mondo_vec_reg = cpr_softsp[i];
2203 #define SZ_INO_TABLE (sizeof (ino_table) / sizeof (ino_table[0]))
2206 * sbus_intrdist
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.
2213 static void
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;
2220 uint64_t mondo_vec;
2221 volatile uint64_t *intr_state_reg;
2222 uint_t start_bit;
2223 volatile uint64_t tmpreg; /* HW flush reg */
2224 uint_t mondo;
2225 uint_t cpu_id;
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)
2233 continue;
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)
2240 continue;
2242 if ((*mondo_vec_reg & INTERRUPT_VALID) == 0)
2243 continue;
2245 last_mondo_vec_reg = (uint64_t *)mondo_vec_reg;
2247 cpu_id = intr_dist_cpuid();
2248 #ifdef _STARFIRE
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.
2256 #else
2257 if (((*mondo_vec_reg & IMR_TID) >> IMR_TID_SHIFT) == cpu_id) {
2258 /* It is the same, don't reprogram */
2259 return;
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;
2270 #ifdef lint
2271 tmpreg = tmpreg;
2272 #endif /* lint */
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)
2284 /* empty */;
2285 } else {
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
2297 * are not pending.
2299 do {
2300 int level; /* Sbus interrupt level */
2301 int shift; /* # of bits to shift */
2302 uint64_t state_reg = *intr_state_reg;
2304 int_pending = 0;
2306 for (shift = start_bit, level = 1; level < 8;
2307 level++, shift += 2) {
2308 if (((state_reg >> shift) &
2309 0x3) == INT_PENDING) {
2310 int_pending = 1;
2311 break;
2314 } while (int_pending && !panicstr);
2317 /* re-target the mondo and turn it on */
2318 #ifdef _STARFIRE
2319 mondo_vec = (pc_translate_tgtid(softsp->ittrans_cookie,
2320 cpu_id, mondo_vec_reg) <<
2321 INTERRUPT_CPU_FIELD) |
2322 INTERRUPT_VALID;
2323 #else
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;
2333 #ifdef lint
2334 tmpreg = tmpreg;
2335 #endif /* lint */
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.
2347 static uint_t
2348 sbus_intr_reset(void *arg)
2350 dev_info_t *dip = (dev_info_t *)arg;
2351 struct sbus_soft_state *softsp;
2352 uint_t mondo;
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) {
2361 continue;
2364 mondo_clear_reg = (softsp->clr_intr_reg +
2365 ino_table[mondo]->clear_reg);
2366 *mondo_clear_reg = SBUS_INTR_IDLE;
2369 return (BF_NONE);
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.
2393 static void
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
2415 * each pic.
2417 sbus_event_mask_t sbus_clear_pic[SBUS_NUM_PICS] = {
2418 /* pic0 */
2419 {"clear_pic", (uint64_t)~(0xf)},
2420 /* pic1 */
2421 {"clear_pic", (uint64_t)~(0xf << 8)}
2424 struct kstat_named *sbus_pic_named_data;
2425 int event, pic;
2426 char pic_name[30];
2427 int instance = ddi_get_instance(dip);
2428 int pic_shift = 0;
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",
2440 pic_name);
2442 /* remove pic0 kstat if pic1 create fails */
2443 if (pic == 1) {
2444 kstat_delete(sbus_picN_ksp[0]);
2445 sbus_picN_ksp[0] = NULL;
2447 return;
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.
2457 if (pic == 1)
2458 pic_shift = 8;
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 ++) {
2466 /* pcr_mask */
2467 sbus_pic_named_data[event].value.ui64 =
2468 sbus_events_arr[event].pcr_mask << pic_shift;
2470 /* event-name */
2471 kstat_named_init(&sbus_pic_named_data[event],
2472 sbus_events_arr[event].event_name,
2473 KSTAT_DATA_UINT64);
2477 * we add the clear_pic event and mask as the last
2478 * record in the kstat
2480 /* pcr mask */
2481 sbus_pic_named_data[SBUS_NUM_EVENTS].value.ui64 =
2482 sbus_clear_pic[pic].pcr_mask;
2484 /* event-name */
2485 kstat_named_init(&sbus_pic_named_data[SBUS_NUM_EVENTS],
2486 sbus_clear_pic[pic].event_name,
2487 KSTAT_DATA_UINT64);
2489 kstat_install(sbus_picN_ksp[pic]);
2493 static void
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
2503 * a mutex.
2505 mutex_enter(&sbus_attachcnt_mutex);
2506 if (sbus_attachcnt == 0)
2507 sbus_add_picN_kstats(softsp->dip);
2509 sbus_attachcnt ++;
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));
2526 return;
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;
2551 static int
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.
2569 *softsp->sbus_pcr =
2570 (uint32_t)sbus_counters_data[0].value.ui64;
2572 } else {
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.
2581 /* pcr */
2582 sbus_counters_data[0].value.ui64 = *softsp->sbus_pcr >> 4;
2584 pic_register = *softsp->sbus_pic;
2586 * sbus pic register:
2587 * (63:32) = pic0
2588 * (31:00) = pic1
2591 /* pic0 */
2592 sbus_counters_data[1].value.ui64 = pic_register >> 32;
2593 /* pic1 */
2594 sbus_counters_data[2].value.ui64 =
2595 pic_register & SBUS_PIC0_MASK;
2598 return (0);
2601 static int
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));
2607 int ino;
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);