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