4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Starcat PCI SBBC Nexus Driver.
30 * This source code's compiled binary runs on both a Starcat System
31 * Controller (SSC) and a Starcat Domain. One of the SBBC hardware
32 * registers is read during attach(9e) in order to determine which
33 * environment the driver is executing on.
35 * On both the SSC and the Domain, this driver provides nexus driver
36 * services to its Device Tree children. Note that the children in
37 * each environment are not necessarily the same.
39 * This driver allows one concurrent open(2) of its associated device
40 * (/dev/sbbc0). The client uses the file descriptor to issue
41 * ioctl(2)'s in order to read and write from the 2MB (PCI) space
42 * reserved for "SBBC Internal Registers". Among other things,
43 * these registers consist of command/control/status registers for
44 * devices such as Console Bus, I2C, EPLD, IOSRAM, and JTAG. The 2MB
45 * space is very sparse; EINVAL is returned if a reserved or unaligned
46 * address is specified in the ioctl(2).
48 * Note that the 2MB region reserved for SBBC Internal Registers is
49 * a subset of the 128MB of PCI address space addressable by the SBBC
50 * ASIC. Address space outside of the 2MB (such as the 64MB reserved
51 * for the Console Bus) is not accessible via this driver.
53 * Also, note that the SBBC Internal Registers are only read and
54 * written by the SSC; no process on the Domain accesses these
55 * registers. As a result, the registers are unmapped (when running
56 * on the Domain) near the end of attach(9e) processing. This conserves
57 * kernel virtual address space resources (as one instance of the driver
58 * is created for each Domain-side IO assembly). (To be complete, only
59 * one instance of the driver is created on the SSC).
62 #include <sys/types.h>
64 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */
66 #include <sys/sunddi.h>
67 #include <sys/ddi_impldefs.h>
68 #include <sys/ddi_subrdefs.h>
70 #include <sys/pci/pci_nexus.h>
71 #include <sys/autoconf.h>
72 #include <sys/cmn_err.h>
73 #include <sys/param.h>
74 #include <sys/errno.h>
76 #include <sys/debug.h>
77 #include <sys/sysmacros.h>
78 #include <sys/machsystm.h>
79 #include <sys/modctl.h>
83 #include <sys/sbbcreg.h> /* hw description */
84 #include <sys/sbbcvar.h> /* driver description */
85 #include <sys/sbbcio.h> /* ioctl description */
87 #define getprop(dip, name, addr, intp) \
88 ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
89 (name), (caddr_t)(addr), (intp))
91 /* driver entry point fn definitions */
92 static int sbbc_open(dev_t
*, int, int, cred_t
*);
93 static int sbbc_close(dev_t
, int, int, cred_t
*);
94 static int sbbc_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
96 /* configuration entry point fn definitions */
97 static int sbbc_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
98 static int sbbc_attach(dev_info_t
*, ddi_attach_cmd_t
);
99 static int sbbc_detach(dev_info_t
*, ddi_detach_cmd_t
);
101 /* local utility routines */
103 * NOTE - sbbc_offset_valid contains detailed address information taken from
104 * the Serengeti Architecture Programmer's Reference Manual. If any
105 * changes are made to the SBBC registers, this routine may need to be
108 static int sbbc_offset_valid(uint32_t offset
);
111 * function prototypes for bus ops routines:
113 static int sbbc_busmap(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_map_req_t
*mp
,
114 off_t offset
, off_t len
, caddr_t
*addrp
);
115 static int sbbc_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
,
116 ddi_ctl_enum_t op
, void *arg
, void *result
);
118 static int sbbc_intr_ops(dev_info_t
*dip
, dev_info_t
*rdip
,
119 ddi_intr_op_t intr_op
, ddi_intr_handle_impl_t
*hdlp
, void *result
);
120 static int sbbc_add_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
121 ddi_intr_op_t intr_op
, ddi_intr_handle_impl_t
*hdlp
, void *result
);
122 static int sbbc_remove_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
123 ddi_intr_op_t intr_op
, ddi_intr_handle_impl_t
*hdlp
, void *result
);
124 static int sbbc_update_intr_state(dev_info_t
*dip
, dev_info_t
*rdip
,
125 ddi_intr_op_t intr_op
, ddi_intr_handle_impl_t
*hdlp
, void *result
);
127 static int sbbc_apply_range(struct sbbcsoft
*sbbc_p
, dev_info_t
*rdip
,
128 sbbc_child_regspec_t
*child_rp
, pci_regspec_t
*rp
);
130 static int sbbc_init(struct sbbcsoft
*);
132 static uint_t
sbbc_intr_wrapper(caddr_t arg
);
134 static int sbbc_get_ranges(struct sbbcsoft
*);
135 static int sbbc_config4pci(struct sbbcsoft
*);
136 static int sbbc_initchild(dev_info_t
*, dev_info_t
*, dev_info_t
*);
137 static int sbbc_uninitchild(dev_info_t
*, dev_info_t
*);
138 static void sbbc_remove_reg_maps(struct sbbcsoft
*);
140 /* debugging functions */
142 uint32_t sbbc_dbg_flags
= 0x0;
143 static void sbbc_dbg(uint32_t flag
, dev_info_t
*dip
, char *fmt
,
144 uintptr_t a1
, uintptr_t a2
, uintptr_t a3
, uintptr_t a4
, uintptr_t a5
);
145 static void sbbc_dump_devid(dev_info_t
*, struct sbbcsoft
*, int instance
);
149 * For tracing, allocate space for the trace buffer
151 #if defined(SBBC_TRACE)
152 struct sbbctrace sbbctrace_buffer
[NSBBCTRACE
+1];
153 struct sbbctrace
*sbbctrace_ptr
;
158 * Local declarations and variables
161 static void *sbbcsoft_statep
;
163 /* Determines whether driver is executing on System Controller or Domain */
164 int sbbc_scmode
= FALSE
;
169 static struct bus_ops sbbc_bus_ops
= {
175 NULL
, /* (*bus_map_fault)() */
178 ddi_no_dma_freehdl
, /* (*bus_dma_freehdl)() */
179 ddi_no_dma_bindhdl
, /* (*bus_dma_bindhdl)() */
180 ddi_no_dma_unbindhdl
, /* (*bus_dma_unbindhdl)() */
181 ddi_no_dma_flush
, /* (*bus_dma_flush)() */
182 ddi_no_dma_win
, /* (*bus_dma_win)() */
183 ddi_no_dma_mctl
, /* (*bus_dma_ctl)() */
186 0, /* (*bus_get_eventcookie)(); */
187 0, /* (*bus_add_eventcall)(); */
188 0, /* (*bus_remove_eventcall)(); */
189 0, /* (*bus_post_event)(); */
190 0, /* (*bus_intr_ctl)(); */
191 0, /* (*bus_config)(); */
192 0, /* (*bus_unconfig)(); */
193 0, /* (*bus_fm_init)(); */
194 0, /* (*bus_fm_fini)(); */
195 0, /* (*bus_fm_access_enter)(); */
196 0, /* (*bus_fm_access_exit)(); */
197 0, /* (*bus_power)(); */
198 sbbc_intr_ops
/* (*bus_intr_op)(); */
204 static struct cb_ops sbbc_cb_ops
= {
205 sbbc_open
, /* cb_open */
206 sbbc_close
, /* cb_close */
207 nodev
, /* cb_strategy */
208 nodev
, /* cb_print */
211 nodev
, /* cb_write */
212 sbbc_ioctl
, /* cb_ioctl */
213 nodev
, /* cb_devmap */
215 nodev
, /* cb_segmap */
216 nochpoll
, /* cb_chpoll */
217 ddi_prop_op
, /* cb_prop_op */
218 NULL
, /* cb_stream */
219 (int)(D_NEW
| D_MP
) /* cb_flag */
223 * Declare ops vectors for auto configuration.
225 struct dev_ops sbbc_ops
= {
226 DEVO_REV
, /* devo_rev */
228 sbbc_getinfo
, /* devo_getinfo */
229 nulldev
, /* devo_identify */
230 nulldev
, /* devo_probe */
231 sbbc_attach
, /* devo_attach */
232 sbbc_detach
, /* devo_detach */
233 nodev
, /* devo_reset */
234 &sbbc_cb_ops
, /* devo_cb_ops */
235 &sbbc_bus_ops
, /* devo_bus_ops */
236 nulldev
, /* devo_power */
237 ddi_quiesce_not_supported
, /* devo_quiesce */
241 * Loadable module support.
243 extern struct mod_ops mod_driverops
;
245 static struct modldrv sbbcmodldrv
= {
246 &mod_driverops
, /* type of module - driver */
247 "PCI Sbbc Nexus Driver",
251 static struct modlinkage sbbcmodlinkage
= {
262 if ((error
= ddi_soft_state_init(&sbbcsoft_statep
,
263 sizeof (struct sbbcsoft
), 1)) != 0)
265 if ((error
= mod_install(&sbbcmodlinkage
)) != 0)
266 ddi_soft_state_fini(&sbbcsoft_statep
);
276 if ((error
= mod_remove(&sbbcmodlinkage
)) == 0)
277 ddi_soft_state_fini(&sbbcsoft_statep
);
283 _info(struct modinfo
*modinfop
)
285 return (mod_info(&sbbcmodlinkage
, modinfop
));
289 sbbc_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
293 struct sbbcsoft
*sbbcsoftp
;
294 struct ddi_device_acc_attr attr
;
295 uint32_t sbbc_id_reg
;
297 attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V0
;
298 attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
299 attr
.devacc_attr_endian_flags
= DDI_NEVERSWAP_ACC
;
301 /* initialize tracing */
304 SBBC_DBG0(SBBC_DBG_ATTACH
, dip
, "Attaching\n");
306 instance
= ddi_get_instance(dip
);
312 ddi_get_soft_state(sbbcsoft_statep
, instance
))) {
313 cmn_err(CE_WARN
, "sbbc_attach:resume: unable "
314 "to acquire sbbcsoftp for instance %d",
316 return (DDI_FAILURE
);
318 mutex_enter(&sbbcsoftp
->umutex
);
319 if (!sbbcsoftp
->suspended
) {
320 mutex_exit(&sbbcsoftp
->umutex
);
321 return (DDI_FAILURE
);
323 sbbcsoftp
->suspended
= 0;
324 mutex_exit(&sbbcsoftp
->umutex
);
325 return (DDI_SUCCESS
);
328 return (DDI_FAILURE
);
331 if (ddi_soft_state_zalloc(sbbcsoft_statep
, instance
) != 0) {
332 cmn_err(CE_WARN
, "sbbc_attach: Unable to allocate statep "
333 "for instance %d", instance
);
334 return (DDI_FAILURE
);
337 sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
);
339 if (sbbcsoftp
== NULL
) {
340 cmn_err(CE_WARN
, "sbbc_attach: Unable to acquire "
341 "sbbcsoftp for instance %d", instance
);
342 ddi_soft_state_free(sbbcsoft_statep
, instance
);
343 return (DDI_FAILURE
);
346 sbbcsoftp
->instance
= instance
;
347 sbbcsoftp
->dip
= dip
;
348 sbbcsoftp
->oflag
= FALSE
;
351 * Read our ranges property from OBP to map children space.
352 * And setup the internal structure for a later use when
353 * a child gets initialized.
355 if (sbbc_get_ranges(sbbcsoftp
)) {
356 cmn_err(CE_WARN
, "sbbc_attach: Unable to read sbbc "
357 "ranges from OBP %d", instance
);
358 ddi_soft_state_free(sbbcsoft_statep
, instance
);
359 return (DDI_FAILURE
);
362 if (sbbc_config4pci(sbbcsoftp
)) {
363 cmn_err(CE_WARN
, "sbbc_attach: Unable to configure "
364 "sbbc on PCI %d", instance
);
365 kmem_free(sbbcsoftp
->rangep
, sbbcsoftp
->range_len
);
366 ddi_soft_state_free(sbbcsoft_statep
, instance
);
367 return (DDI_FAILURE
);
370 mutex_init(&sbbcsoftp
->umutex
, NULL
, MUTEX_DRIVER
, (void *)NULL
);
371 mutex_init(&sbbcsoftp
->sbbc_intr_mutex
, NULL
,
372 MUTEX_DRIVER
, (void *)NULL
);
374 /* Map SBBC's Internal Registers */
375 if (ddi_regs_map_setup(dip
, 1, (caddr_t
*)&sbbcsoftp
->pci_sbbc_map
,
376 offsetof(struct pci_sbbc
, sbbc_internal_regs
),
377 sizeof (struct sbbc_regs_map
), &attr
,
378 &sbbcsoftp
->pci_sbbc_map_handle
) != DDI_SUCCESS
) {
379 cmn_err(CE_WARN
, "(%d):sbbc_attach failed to map sbbc_reg",
384 SBBC_DBG1(SBBC_DBG_ATTACH
, dip
, "Mapped sbbc at %lx\n",
385 sbbcsoftp
->pci_sbbc_map
);
387 sbbc_dump_devid(dip
, sbbcsoftp
, instance
);
390 * Read a hardware register to determine if we are executing on
391 * a Starcat System Controller or a Starcat Domain.
393 sbbc_id_reg
= ddi_get32(sbbcsoftp
->pci_sbbc_map_handle
,
394 &sbbcsoftp
->pci_sbbc_map
->device_conf
);
396 if (sbbc_id_reg
& SBBC_SC_MODE
) {
398 SBBC_DBG1(SBBC_DBG_ATTACH
, dip
, "SBBC(%d) nexus running "
399 "in System Controller Mode.\n", instance
);
401 /* initialize SBBC ASIC */
402 if (!sbbc_init(sbbcsoftp
)) {
407 SBBC_DBG1(SBBC_DBG_ATTACH
, dip
, "SBBC(%d) nexus "
408 "running in Domain Mode.\n", instance
);
410 /* initialize SBBC ASIC before we unmap registers */
411 if (!sbbc_init(sbbcsoftp
)) {
416 * Access to SBBC registers is no longer needed. Unmap
417 * the registers to conserve kernel virtual address space.
419 SBBC_DBG1(SBBC_DBG_ATTACH
, dip
, "SBBC(%d): unmap "
420 "SBBC registers\n", instance
);
421 sbbc_remove_reg_maps(sbbcsoftp
);
422 sbbcsoftp
->pci_sbbc_map
= NULL
;
425 (void) sprintf(name
, "sbbc%d", instance
);
427 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, instance
, NULL
,
428 NULL
) == DDI_FAILURE
) {
429 ddi_remove_minor_node(dip
, NULL
);
435 SBBC_DBG0(SBBC_DBG_ATTACH
, dip
, "Attached successfully\n");
437 return (DDI_SUCCESS
);
440 mutex_destroy(&sbbcsoftp
->sbbc_intr_mutex
);
441 mutex_destroy(&sbbcsoftp
->umutex
);
443 sbbc_remove_reg_maps(sbbcsoftp
);
444 kmem_free(sbbcsoftp
->rangep
, sbbcsoftp
->range_len
);
445 ddi_soft_state_free(sbbcsoft_statep
, instance
);
447 SBBC_DBG0(SBBC_DBG_ATTACH
, dip
, "Attach failed\n");
449 return (DDI_FAILURE
);
453 sbbc_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
456 struct sbbcsoft
*sbbcsoftp
;
458 SBBCTRACE(sbbc_detach
, 'DETA', dip
);
460 instance
= ddi_get_instance(dip
);
468 ddi_get_soft_state(sbbcsoft_statep
, instance
))) {
470 "sbbc_detach: unable to get softstate %p",
472 return (DDI_FAILURE
);
474 mutex_enter(&sbbcsoftp
->umutex
);
475 if (sbbcsoftp
->suspended
) {
476 mutex_exit(&sbbcsoftp
->umutex
);
477 return (DDI_FAILURE
);
479 sbbcsoftp
->suspended
= 1;
480 mutex_exit(&sbbcsoftp
->umutex
);
481 return (DDI_SUCCESS
);
484 return (DDI_FAILURE
);
487 if (!(sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
))) {
488 cmn_err(CE_WARN
, "sbbc_detach: unable to get softstate %p",
490 return (DDI_FAILURE
);
493 ddi_remove_minor_node(dip
, NULL
);
495 mutex_destroy(&sbbcsoftp
->sbbc_intr_mutex
);
496 mutex_destroy(&sbbcsoftp
->umutex
);
498 sbbc_remove_reg_maps(sbbcsoftp
);
499 kmem_free(sbbcsoftp
->rangep
, sbbcsoftp
->range_len
);
501 ddi_soft_state_free(sbbcsoft_statep
, instance
);
503 return (DDI_SUCCESS
);
509 * Translate child's address into parents.
512 sbbc_busmap(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_map_req_t
*mp
,
513 off_t off
, off_t len
, caddr_t
*addrp
)
515 struct sbbcsoft
*sbbcsoftp
;
516 sbbc_child_regspec_t
*child_rp
, *child_regs
;
517 pci_regspec_t pci_reg
;
518 ddi_map_req_t p_map_request
;
520 int rval
= DDI_SUCCESS
;
523 SBBC_DBG4(SBBC_DBG_BUSMAP
, dip
,
524 "mapping child %s, type %llx, off %llx, len %llx\n",
525 ddi_driver_name(rdip
), mp
->map_type
, off
, len
);
527 SBBCTRACE(sbbc_busmap
, 'BMAP', mp
);
530 * Handle the mapping according to its type.
532 instance
= ddi_get_instance(dip
);
533 if (!(sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
)))
534 return (DDI_FAILURE
);
536 switch (mp
->map_type
) {
540 * We assume the register specification is in sbbc format.
541 * We must convert it into a PCI format regspec and pass
542 * the request to our parent.
544 child_rp
= (sbbc_child_regspec_t
*)mp
->map_obj
.rp
;
551 * Get the "reg" property from the device node and convert
552 * it to our parent's format.
554 rnumber
= mp
->map_obj
.rnumber
;
556 /* get the requester's reg property */
557 if (ddi_getlongprop(DDI_DEV_T_ANY
, rdip
, DDI_PROP_DONTPASS
,
558 "reg", (caddr_t
)&child_regs
, &i
) != DDI_SUCCESS
) {
560 "SBBC: couldn't get %s ranges property %d",
561 ddi_get_name(sbbcsoftp
->dip
), instance
);
562 return (DDI_ME_RNUMBER_RANGE
);
564 n
= i
/ sizeof (sbbc_child_regspec_t
);
566 if (rnumber
< 0 || rnumber
>= n
) {
567 kmem_free(child_regs
, i
);
568 return (DDI_ME_RNUMBER_RANGE
);
570 child_rp
= &child_regs
[rnumber
];
574 return (DDI_ME_INVAL
);
578 /* Adjust our reg property with offset and length */
579 child_rp
->addr_low
+= off
;
582 child_rp
->size
= len
;
585 * Combine this reg prop. into our parents PCI address using the ranges
588 rval
= sbbc_apply_range(sbbcsoftp
, rdip
, child_rp
, &pci_reg
);
590 if (mp
->map_type
== DDI_MT_RNUMBER
)
591 kmem_free(child_regs
, i
);
593 if (rval
!= DDI_SUCCESS
)
597 p_map_request
.map_type
= DDI_MT_REGSPEC
;
598 p_map_request
.map_obj
.rp
= (struct regspec
*)&pci_reg
;
600 /* Send it to PCI nexus to map into the PCI space */
601 rval
= ddi_map(dip
, &p_map_request
, 0, 0, addrp
);
608 /* new intr_ops structure */
610 sbbc_intr_ops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
611 ddi_intr_handle_impl_t
*hdlp
, void *result
)
613 int ret
= DDI_SUCCESS
;
616 case DDI_INTROP_GETCAP
:
617 *(int *)result
= DDI_INTR_FLAG_LEVEL
;
619 case DDI_INTROP_ALLOC
:
620 *(int *)result
= hdlp
->ih_scratch1
;
622 case DDI_INTROP_FREE
:
624 case DDI_INTROP_GETPRI
:
625 if (hdlp
->ih_pri
== 0) {
628 cmn_err(CE_WARN
, "%s%d assigning default interrupt "
629 "level %d for device %s%d", ddi_driver_name(dip
),
630 ddi_get_instance(dip
), hdlp
->ih_pri
,
631 ddi_driver_name(rdip
), ddi_get_instance(rdip
));
634 *(int *)result
= hdlp
->ih_pri
;
637 case DDI_INTROP_ADDISR
:
638 ret
= sbbc_add_intr_impl(dip
, rdip
, intr_op
, hdlp
, result
);
640 case DDI_INTROP_REMISR
:
641 ret
= sbbc_remove_intr_impl(dip
, rdip
, intr_op
, hdlp
, result
);
643 case DDI_INTROP_ENABLE
:
644 ret
= sbbc_update_intr_state(dip
, rdip
, intr_op
, hdlp
, &result
);
646 case DDI_INTROP_DISABLE
:
647 ret
= sbbc_update_intr_state(dip
, rdip
, intr_op
, hdlp
, &result
);
649 case DDI_INTROP_NINTRS
:
650 case DDI_INTROP_NAVAIL
:
651 *(int *)result
= i_ddi_get_intx_nintrs(rdip
);
653 case DDI_INTROP_SUPPORTED_TYPES
:
654 /* PCI nexus driver supports only fixed interrupts */
655 *(int *)result
= i_ddi_get_intx_nintrs(rdip
) ?
656 DDI_INTR_TYPE_FIXED
: 0;
668 sbbc_add_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
669 ddi_intr_handle_impl_t
*hdlp
, void *result
)
671 sbbcsoft_t
*sbbcsoftp
;
672 sbbc_child_intr_t
*childintr
;
673 int instance
, i
, rval
= DDI_SUCCESS
;
675 SBBC_DBG2(SBBC_DBG_INTR
, dip
,
676 "add: rdip 0x%llx hdlp 0x%llx\n", rdip
, hdlp
);
678 /* insert the sbbc isr wrapper instead */
679 instance
= ddi_get_instance(dip
);
680 if (!(sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
)))
681 return (DDI_FAILURE
);
683 childintr
= kmem_zalloc(sizeof (struct sbbc_child_intr
), KM_SLEEP
);
685 childintr
->name
= ddi_get_name(rdip
);
686 childintr
->inum
= hdlp
->ih_inum
;
687 childintr
->intr_handler
= hdlp
->ih_cb_func
;
688 childintr
->arg1
= hdlp
->ih_cb_arg1
;
689 childintr
->arg2
= hdlp
->ih_cb_arg2
;
690 childintr
->status
= SBBC_INTR_STATE_DISABLE
;
692 for (i
= 0; i
< MAX_SBBC_DEVICES
; i
++) {
693 if (sbbcsoftp
->child_intr
[i
] == 0) {
694 sbbcsoftp
->child_intr
[i
] = childintr
;
699 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp
,
700 (ddi_intr_handler_t
*)sbbc_intr_wrapper
,
701 (caddr_t
)sbbcsoftp
, NULL
);
703 if ((rval
= i_ddi_intr_ops(dip
, rdip
, intr_op
,
704 hdlp
, result
)) != DDI_SUCCESS
) {
705 cmn_err(CE_WARN
, "sbbc%d: failed to add intr for %s",
706 instance
, ddi_get_name(rdip
));
707 kmem_free(childintr
, sizeof (struct sbbc_child_intr
));
708 sbbcsoftp
->child_intr
[i
] = NULL
;
712 * Restore original interrupt handler
713 * and arguments in interrupt handle.
715 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp
, childintr
->intr_handler
,
716 childintr
->arg1
, childintr
->arg2
);
722 sbbc_remove_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
723 ddi_intr_handle_impl_t
*hdlp
, void *result
)
725 sbbcsoft_t
*sbbcsoftp
;
726 sbbc_child_intr_t
*childintr
;
727 int instance
, i
, rval
= DDI_SUCCESS
;
729 SBBC_DBG2(SBBC_DBG_INTR
, dip
,
730 "remove: rdip 0x%llx hdlp 0x%llx\n", rdip
, hdlp
);
732 instance
= ddi_get_instance(dip
);
733 if (!(sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
)))
734 return (DDI_FAILURE
);
736 /* remove the sbbc isr wrapper instead */
737 for (i
= 0; i
< MAX_SBBC_DEVICES
; i
++) {
738 if (sbbcsoftp
->child_intr
[i
]) {
739 childintr
= sbbcsoftp
->child_intr
[i
];
740 if (childintr
->status
== SBBC_INTR_STATE_DISABLE
&&
741 childintr
->name
== ddi_get_name(rdip
)) {
742 /* put back child's inum */
743 hdlp
->ih_inum
= childintr
->inum
;
749 if (i
>= MAX_SBBC_DEVICES
) {
750 cmn_err(CE_WARN
, "sbbc%d:obound failed to remove intr for %s",
751 instance
, ddi_get_name(rdip
));
752 return (DDI_FAILURE
);
755 if ((rval
= i_ddi_intr_ops(dip
, rdip
, intr_op
,
756 hdlp
, result
)) != DDI_SUCCESS
) {
757 cmn_err(CE_WARN
, "sbbc%d: failed to remove intr for %s",
758 instance
, ddi_get_name(rdip
));
762 kmem_free(childintr
, sizeof (struct sbbc_child_intr
));
763 sbbcsoftp
->child_intr
[i
] = NULL
;
770 sbbc_update_intr_state(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
771 ddi_intr_handle_impl_t
*hdlp
, void *result
)
773 sbbcsoft_t
*sbbcsoftp
;
774 sbbc_child_intr_t
*childintr
;
776 int ret
= DDI_SUCCESS
;
778 SBBC_DBG2(SBBC_DBG_INTR
, dip
, "sbbc_update_intr_state: "
779 "rdip 0x%llx hdlp 0x%llx state 0x%x\n", rdip
, hdlp
);
781 instance
= ddi_get_instance(dip
);
782 if (!(sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, instance
)))
783 return (DDI_FAILURE
);
785 for (i
= 0; i
< MAX_SBBC_DEVICES
; i
++) {
786 if (sbbcsoftp
->child_intr
[i
]) {
787 childintr
= sbbcsoftp
->child_intr
[i
];
788 if (childintr
->name
== ddi_get_name(rdip
))
793 if (i
>= MAX_SBBC_DEVICES
) {
794 cmn_err(CE_WARN
, "sbbc%d: failed to update intr state for %s",
795 instance
, ddi_get_name(rdip
));
796 return (DDI_FAILURE
);
799 if ((ret
= i_ddi_intr_ops(dip
, rdip
, intr_op
,
800 hdlp
, result
)) != DDI_SUCCESS
) {
801 cmn_err(CE_WARN
, "sbbc%d: failed to update intr state for %s",
802 instance
, ddi_get_name(rdip
));
806 /* Update the interrupt state */
807 childintr
->status
= (intr_op
== DDI_INTROP_ENABLE
) ?
808 SBBC_INTR_STATE_ENABLE
: SBBC_INTR_STATE_DISABLE
;
815 * This entry point is called before a child's probe or attach is called.
816 * The arg pointer points to child's dev_info_t structure.
819 sbbc_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t op
,
820 void *arg
, void *result
)
822 sbbc_child_regspec_t
*child_rp
;
825 SBBC_DBG3(SBBC_DBG_CTLOPS
, dip
,
826 "Initializing %s, arg %x, op %x\n",
827 ddi_driver_name(rdip
), arg
, op
);
829 SBBCTRACE(sbbc_ctlops
, 'CTLO', arg
);
832 case DDI_CTLOPS_INITCHILD
: {
833 return (sbbc_initchild(dip
, rdip
, (dev_info_t
*)arg
));
836 case DDI_CTLOPS_UNINITCHILD
: {
837 return (sbbc_uninitchild(rdip
, (dev_info_t
*)arg
));
840 case DDI_CTLOPS_REPORTDEV
:
842 cmn_err(CE_CONT
, "?%s%d at %s%d: offset %s\n",
843 ddi_driver_name(rdip
), ddi_get_instance(rdip
),
844 ddi_driver_name(dip
), ddi_get_instance(dip
),
845 ddi_get_name_addr(rdip
));
846 return (DDI_SUCCESS
);
848 case DDI_CTLOPS_REGSIZE
:
850 if (getprop(rdip
, "reg", &child_rp
, &i
) != DDI_SUCCESS
) {
851 return (DDI_FAILURE
);
853 n
= i
/ sizeof (sbbc_child_regspec_t
);
854 if (*(int *)arg
< 0 || *(int *)arg
>= n
) {
855 kmem_free(child_rp
, i
);
856 return (DDI_FAILURE
);
858 *((off_t
*)result
) = child_rp
[*(int *)arg
].size
;
859 kmem_free(child_rp
, i
);
860 return (DDI_SUCCESS
);
862 case DDI_CTLOPS_NREGS
:
864 if (getprop(rdip
, "reg", &child_rp
, &i
) != DDI_SUCCESS
) {
865 return (DDI_FAILURE
);
867 *((uint_t
*)result
) = i
/ sizeof (sbbc_child_regspec_t
);
868 kmem_free(child_rp
, i
);
869 return (DDI_SUCCESS
);
873 * Now pass the request up to our parent.
875 SBBC_DBG0(SBBC_DBG_CTLOPS
, dip
, "Calling ddi_ctlops\n");
877 return (ddi_ctlops(dip
, rdip
, op
, arg
, result
));
882 * The following routine uses ranges property, that was read earlier, and
883 * takes child's reg property, and computes the complete address and size
884 * for the PCI parent to map.
887 sbbc_apply_range(struct sbbcsoft
*sbbc_p
, dev_info_t
*rdip
,
888 sbbc_child_regspec_t
*child_rp
, pci_regspec_t
*rp
)
891 int rval
= DDI_SUCCESS
;
892 struct sbbc_pci_rangespec
*rangep
= sbbc_p
->rangep
;
893 int nrange
= sbbc_p
->range_cnt
;
895 SBBC_DBG4(SBBC_DBG_MAPRANGES
, rdip
,
896 "Applying ranges for %s, rangep %llx, child_rp %llx, range %x\n",
897 ddi_driver_name(rdip
), sbbc_p
->rangep
, child_rp
, nrange
);
899 SBBCTRACE(sbbc_apply_range
, 'APPL', sbbc_p
);
901 for (b
= 0; b
< nrange
; ++b
, ++rangep
) {
903 /* Make sure the correct range is being mapped */
904 if (child_rp
->addr_hi
== rangep
->sbbc_phys_hi
)
905 /* See if we fit in this range */
906 if ((child_rp
->addr_low
>=
907 rangep
->sbbc_phys_low
) &&
908 ((child_rp
->addr_low
+ child_rp
->size
- 1)
909 <= (rangep
->sbbc_phys_low
+
910 rangep
->rng_size
- 1))) {
911 uint_t addr_offset
= child_rp
->addr_low
-
912 rangep
->sbbc_phys_low
;
914 * Use the range entry to translate
915 * the SBBC physical address into the
920 rp
->pci_phys_mid
= rangep
->pci_phys_mid
;
922 rangep
->pci_phys_low
+ addr_offset
;
925 min(child_rp
->size
, (rangep
->rng_size
-
933 cmn_err(CE_WARN
, "out_of_range %s", ddi_get_name(rdip
));
934 return (DDI_ME_REGSPEC_RANGE
);
942 * The following routine reads sbbc's ranges property from OBP and sets up
943 * its soft structure with it.
946 sbbc_get_ranges(struct sbbcsoft
*sbbcsoftp
)
948 struct sbbc_pci_rangespec
*rangep
;
949 int range_len
, nrange
;
951 if (ddi_getlongprop(DDI_DEV_T_ANY
, sbbcsoftp
->dip
, DDI_PROP_DONTPASS
,
952 "ranges", (caddr_t
)&rangep
, &range_len
) != DDI_SUCCESS
) {
953 cmn_err(CE_WARN
, "SBBC: couldn't get %s ranges property %d",
954 ddi_get_name(sbbcsoftp
->dip
), sbbcsoftp
->instance
);
955 return (DDI_ME_REGSPEC_RANGE
);
958 nrange
= range_len
/ sizeof (struct sbbc_pci_rangespec
);
961 kmem_free(rangep
, range_len
);
962 return (DDI_FAILURE
);
965 /* setup the soft structure with ranges info. */
966 sbbcsoftp
->rangep
= rangep
;
967 sbbcsoftp
->range_cnt
= nrange
;
968 sbbcsoftp
->range_len
= range_len
;
970 return (DDI_SUCCESS
);
975 * Configure the SBBC for PCI
978 sbbc_config4pci(struct sbbcsoft
*sbbcsoftp
)
980 ddi_acc_handle_t conf_handle
;
981 uint16_t comm
, vendid
, devid
, stat
;
985 if (sbbc_dbg_flags
& SBBC_DBG_PCICONF
) {
987 "sbbc_config4pci: sbbcsoftp %p\n", (void *)sbbcsoftp
);
990 if (pci_config_setup(sbbcsoftp
->dip
, &conf_handle
) != DDI_SUCCESS
)
993 vendid
= pci_config_get16(conf_handle
, PCI_CONF_VENID
);
994 devid
= pci_config_get16(conf_handle
, PCI_CONF_DEVID
);
995 comm
= pci_config_get16(conf_handle
, PCI_CONF_COMM
);
996 stat
= pci_config_get16(conf_handle
, PCI_CONF_STAT
);
997 revid
= pci_config_get8(conf_handle
, PCI_CONF_REVID
);
1000 if (sbbc_dbg_flags
& SBBC_DBG_PCICONF
) {
1002 "SBBC vendid %x, devid %x, comm %x, stat %x, revid %x\n",
1003 vendid
, devid
, comm
, stat
, revid
);
1006 comm
= (PCI_COMM_ME
| PCI_COMM_MAE
| PCI_COMM_SERR_ENABLE
|
1007 PCI_COMM_PARITY_DETECT
);
1009 pci_config_put16(conf_handle
, PCI_CONF_COMM
, comm
);
1011 comm
= pci_config_get16(conf_handle
, PCI_CONF_COMM
);
1014 if (sbbc_dbg_flags
& SBBC_DBG_PCICONF
) {
1015 cmn_err(CE_CONT
, "comm %x\n", comm
);
1018 pci_config_teardown(&conf_handle
);
1026 sbbc_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
1028 dev_t dev
= (dev_t
)arg
;
1029 struct sbbcsoft
*sbbcsoftp
;
1032 instance
= getminor(dev
);
1034 SBBCTRACE(sbbc_getinfo
, 'GINF', instance
);
1037 case DDI_INFO_DEVT2DEVINFO
:
1038 sbbcsoftp
= (struct sbbcsoft
*)
1039 ddi_get_soft_state(sbbcsoft_statep
, instance
);
1040 if (sbbcsoftp
== NULL
) {
1041 *result
= (void *) NULL
;
1044 *result
= sbbcsoftp
->dip
;
1048 case DDI_INFO_DEVT2INSTANCE
:
1049 *result
= (void *)(uintptr_t)instance
;
1062 sbbc_open(dev_t
*dev
, int flag
, int otype
, cred_t
*credp
)
1064 struct sbbcsoft
*sbbcsoftp
;
1067 /* check privilege of caller process */
1068 if (drv_priv(credp
)) {
1072 instance
= getminor(*dev
);
1075 sbbcsoftp
= (struct sbbcsoft
*)ddi_get_soft_state(sbbcsoft_statep
,
1077 SBBCTRACE(sbbc_open
, 'OPEN', sbbcsoftp
);
1079 if (sbbcsoftp
== NULL
)
1082 mutex_enter(&sbbcsoftp
->umutex
);
1084 /* check for exclusive access */
1085 if ((sbbcsoftp
->oflag
== TRUE
)) {
1086 mutex_exit(&sbbcsoftp
->umutex
);
1089 sbbcsoftp
->oflag
= TRUE
;
1091 mutex_exit(&sbbcsoftp
->umutex
);
1098 sbbc_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
)
1100 struct sbbcsoft
*sbbcsoftp
;
1103 instance
= getminor(dev
);
1106 sbbcsoftp
= (struct sbbcsoft
*)ddi_get_soft_state(sbbcsoft_statep
,
1108 /* wait till all output activity has ceased */
1110 mutex_enter(&sbbcsoftp
->umutex
);
1112 SBBCTRACE(sbbc_close
, 'CLOS', sbbcsoftp
);
1114 sbbcsoftp
->oflag
= FALSE
;
1116 mutex_exit(&sbbcsoftp
->umutex
);
1123 sbbc_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
1126 struct sbbcsoft
*sbbcsoftp
;
1128 SBBCTRACE(sbbc_ioctl
, 'IOCT', arg
);
1130 sbbcsoftp
= ddi_get_soft_state(sbbcsoft_statep
, getminor(dev
));
1132 if (sbbcsoftp
== NULL
) {
1137 case SBBC_SBBCREG_WR
:
1139 struct ssc_sbbc_regio sbbcregs
;
1142 if (sbbc_scmode
== FALSE
) {
1143 /* then we're executing on Domain; Writes not allowed */
1151 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&sbbcregs
,
1152 sizeof (struct ssc_sbbc_regio
), mode
)) {
1153 cmn_err(CE_WARN
, "sbbc_ioctl: copyin failed arg %p",
1159 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
1161 * Note that I've also added a check to make sure the offset is
1162 * valid, since misaligned (i.e. not on 16-byte boundary)
1163 * accesses or accesses to "Reserved" register offsets are
1164 * treated as unmapped by the SBBC.
1166 if ((sbbcregs
.len
!= 4) ||
1167 !sbbc_offset_valid(sbbcregs
.offset
)) {
1171 offset
= (uint64_t)sbbcsoftp
->pci_sbbc_map
;
1172 offset
+= sbbcregs
.offset
;
1173 ddi_put32(sbbcsoftp
->pci_sbbc_map_handle
, (uint32_t *)offset
,
1177 case SBBC_SBBCREG_RD
:
1179 struct ssc_sbbc_regio sbbcregs
;
1182 if (sbbc_scmode
== FALSE
) {
1183 /* then we're executing on Domain; Reads not allowed */
1191 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&sbbcregs
,
1192 sizeof (struct ssc_sbbc_regio
), mode
)) {
1193 cmn_err(CE_WARN
, "sbbc_ioctl: copyin failed arg %p",
1199 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
1201 * Note that I've also added a check to make sure the offset is
1202 * valid, since misaligned (i.e. not on 16-byte boundary)
1203 * accesses or accesses to "Reserved" register offsets are
1204 * treated as unmapped by the SBBC.
1206 if ((sbbcregs
.len
!= 4) ||
1207 !sbbc_offset_valid(sbbcregs
.offset
)) {
1211 offset
= (uint64_t)sbbcsoftp
->pci_sbbc_map
;
1212 offset
+= sbbcregs
.offset
;
1214 sbbcregs
.value
= ddi_get32(sbbcsoftp
->pci_sbbc_map_handle
,
1215 (uint32_t *)offset
);
1217 if (ddi_copyout((caddr_t
)&sbbcregs
.value
,
1218 &((struct ssc_sbbc_regio
*)arg
)->value
,
1219 sbbcregs
.len
, mode
)) {
1220 cmn_err(CE_WARN
, "sbbc_ioctl:copyout failed arg %p",
1227 cmn_err(CE_WARN
, "sbbc_ioctl:Illegal command 0x%08x", cmd
);
1231 return (DDI_SUCCESS
);
1235 sbbc_remove_reg_maps(struct sbbcsoft
*sbbcsoftp
)
1237 SBBCTRACE(sbbc_remove_reg_maps
, 'RMAP', sbbcsoftp
);
1238 if (sbbcsoftp
->pci_sbbc_map_handle
)
1239 ddi_regs_map_free(&sbbcsoftp
->pci_sbbc_map_handle
);
1244 sbbc_init(struct sbbcsoft
*sbbcsoftp
)
1246 /* Mask all the interrupts until we are ready. */
1247 ddi_put32(sbbcsoftp
->pci_sbbc_map_handle
,
1248 &sbbcsoftp
->pci_sbbc_map
->sys_intr_enable
,
1255 * The following routine is a generic routine to initialize any child of
1256 * sbbc nexus driver information into parent private data structure.
1260 sbbc_initchild(dev_info_t
*dip
, dev_info_t
*rdip
, dev_info_t
*child
)
1262 sbbc_child_regspec_t
*child_rp
;
1266 SBBC_DBG1(SBBC_DBG_INITCHILD
, dip
, "Initializing %s\n",
1267 ddi_driver_name(rdip
));
1270 * Initialize a child
1271 * Set the address portion of the node name based on the
1274 if (ddi_getlongprop(DDI_DEV_T_ANY
, child
, DDI_PROP_DONTPASS
,
1275 "reg", (caddr_t
)&child_rp
, ®len
) != DDI_SUCCESS
) {
1276 if (strcmp(ddi_node_name(child
), "hotplug-controller") == 0) {
1278 (void) sprintf(name
, "%x", slot
);
1279 ddi_set_name_addr(child
, name
);
1280 return (DDI_SUCCESS
);
1282 return (DDI_FAILURE
);
1285 SBBC_DBG3(SBBC_DBG_INITCHILD
, dip
, "hi 0x%x, low 0x%x, size 0x%x\n",
1286 child_rp
->addr_hi
, child_rp
->addr_low
, child_rp
->size
);
1288 (void) sprintf(name
, "%x,%x", child_rp
->addr_hi
, child_rp
->addr_low
);
1291 * set child's addresses from the reg property into parent private
1294 ddi_set_name_addr(child
, name
);
1295 kmem_free(child_rp
, reglen
);
1297 ddi_set_parent_data(child
, NULL
);
1299 return (DDI_SUCCESS
);
1305 sbbc_uninitchild(dev_info_t
*rdip
, dev_info_t
*child
)
1308 SBBC_DBG1(SBBC_DBG_UNINITCHILD
, rdip
, "Uninitializing %s\n",
1309 ddi_driver_name(rdip
));
1311 ddi_set_name_addr(child
, NULL
);
1312 ddi_remove_minor_node(child
, NULL
);
1313 impl_rem_dev_props(child
);
1315 return (DDI_SUCCESS
);
1321 * The following routine is an interrupt service routine that is used
1322 * as a wrapper to all the children requiring interrupt services.
1325 sbbc_intr_wrapper(caddr_t arg
)
1328 struct sbbcsoft
*sbbcsoftp
= (struct sbbcsoft
*)arg
;
1331 SBBC_DBG1(SBBC_DBG_INTR
, sbbcsoftp
->dip
, "Isr arg 0x%llx\n", arg
);
1333 mutex_enter(&sbbcsoftp
->sbbc_intr_mutex
);
1335 for (i
= 0; i
< MAX_SBBC_DEVICES
; i
++) {
1337 * Check the interrupt status reg. to determine the cause.
1340 * Check the error status reg. to determine the cause.
1342 if (sbbcsoftp
->child_intr
[i
] &&
1343 sbbcsoftp
->child_intr
[i
]->status
==
1344 SBBC_INTR_STATE_ENABLE
) {
1346 * Dispatch the children interrupt service routines and
1347 * look for someone to claim.
1349 rval
= sbbcsoftp
->child_intr
[i
]->intr_handler(
1350 sbbcsoftp
->child_intr
[i
]->arg1
,
1351 sbbcsoftp
->child_intr
[i
]->arg2
);
1353 if (rval
== DDI_INTR_CLAIMED
) {
1354 mutex_exit(&sbbcsoftp
->sbbc_intr_mutex
);
1360 mutex_exit(&sbbcsoftp
->sbbc_intr_mutex
);
1362 /* for now do not claim since we know its not enabled */
1363 return (DDI_INTR_UNCLAIMED
);
1368 * This function checks an SBBC register offset to make sure that it is properly
1369 * aligned (i.e. on a 16-byte boundary) and that it corresponds to an accessible
1370 * register. Since the SBBC treates accesses to unaligned or reserved addresses
1371 * as unmapped, failing to check for these would leave a loophole that could be
1372 * used to crash the system.
1375 sbbc_offset_valid(uint32_t offset
) {
1377 * Check for proper alignment first.
1379 if ((offset
% 16) != 0) {
1384 * Now start checking for the various reserved ranges.
1385 * While sticking a bunch of constants in the code (rather than
1386 * #define'd values) is usually best avoided, it would probably
1387 * do more harm than good here. These values were taken from the
1388 * Serengeti Architecture Programmer's Reference Manual dated
1389 * August 10, 1999, pages 2-99 through 2-103. While there are
1390 * various "clever" ways this check could be performed that would
1391 * be slightly more efficient, arranging the code in this fashion
1392 * should maximize maintainability.
1394 if (((offset
>= 0x001a0) && (offset
<= 0x001ff)) ||
1395 ((offset
>= 0x002a0) && (offset
<= 0x002ff)) ||
1396 ((offset
>= 0x00350) && (offset
<= 0x003ff)) ||
1397 ((offset
>= 0x00500) && (offset
<= 0x00fff)) ||
1398 ((offset
>= 0x01160) && (offset
<= 0x011ff)) ||
1399 ((offset
>= 0x01210) && (offset
<= 0x017ff)) ||
1400 ((offset
>= 0x01810) && (offset
<= 0x01fff)) ||
1401 ((offset
>= 0x02030) && (offset
<= 0x022ff)) ||
1402 ((offset
>= 0x02340) && (offset
<= 0x03fff)) ||
1403 ((offset
>= 0x04030) && (offset
<= 0x05fff)) ||
1404 ((offset
>= 0x060a0) && (offset
<= 0x060ff)) ||
1405 (offset
== 0x06120) ||
1406 ((offset
>= 0x06190) && (offset
<= 0x061ff)) ||
1407 ((offset
>= 0x06230) && (offset
<= 0x062f0)) ||
1408 (offset
> 0x06320)) {
1417 sbbc_dbg(uint32_t flag
, dev_info_t
*dip
, char *fmt
,
1418 uintptr_t a1
, uintptr_t a2
, uintptr_t a3
, uintptr_t a4
, uintptr_t a5
)
1422 if (sbbc_dbg_flags
&& ((sbbc_dbg_flags
& flag
) == flag
)) {
1424 case SBBC_DBG_ATTACH
:
1427 case SBBC_DBG_DETACH
:
1430 case SBBC_DBG_CTLOPS
:
1433 case SBBC_DBG_INITCHILD
:
1436 case SBBC_DBG_UNINITCHILD
:
1439 case SBBC_DBG_BUSMAP
:
1445 case SBBC_DBG_INTROPS
:
1448 case SBBC_DBG_PCICONF
:
1451 case SBBC_DBG_MAPRANGES
:
1454 case SBBC_DBG_PROPERTIES
:
1460 case SBBC_DBG_CLOSE
:
1463 case SBBC_DBG_IOCTL
:
1467 s
= "Unknown debug flag";
1471 cmn_err(CE_CONT
, "%s_%s(%d): ", ddi_driver_name(dip
), s
,
1472 ddi_get_instance(dip
));
1473 cmn_err(CE_CONT
, fmt
, a1
, a2
, a3
, a4
, a5
);
1478 * Dump the SBBC chip's Device ID Register
1480 static void sbbc_dump_devid(dev_info_t
*dip
, struct sbbcsoft
*sbbcsoftp
,
1483 uint32_t sbbc_id_reg
;
1484 uint16_t sbbc_id_reg_partid
;
1485 uint16_t sbbc_id_reg_manfid
;
1487 sbbc_id_reg
= ddi_get32(sbbcsoftp
->pci_sbbc_map_handle
,
1488 (uint32_t *)&sbbcsoftp
->pci_sbbc_map
->devid
);
1490 sbbc_id_reg_partid
= ((sbbc_id_reg
<< 4) >> 16);
1491 sbbc_id_reg_manfid
= ((sbbc_id_reg
<< 20) >> 21);
1493 SBBC_DBG4(SBBC_DBG_ATTACH
, dip
,
1494 "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n",
1495 instance
, (sbbc_id_reg
>> 28), sbbc_id_reg_partid
,
1496 sbbc_id_reg_manfid
);