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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * PCI nexus driver general debug support
29 #include <sys/sysmacros.h>
30 #include <sys/async.h>
31 #include <sys/sunddi.h> /* dev_info_t */
32 #include <sys/ddi_impldefs.h>
34 #include <sys/archsystm.h> /* getpil() */
40 uint64_t px_debug_flags
= 0;
42 static char *px_debug_sym
[] = { /* same sequence as px_debug_bit */
66 /* 19 */ "dma-unbind",
68 /* 20 */ "chk-dma-mode",
69 /* 21 */ "bypass-dma",
71 /* 23 */ "init_child",
116 static int px_dbg_msg_size
= 16; /* # of Qs. Must be ^2 */
119 static int px_dbg_qmask
= 0xFFFF; /* Mask based on Q size */
120 static px_dbg_msg_t
*px_dbg_msgq
= NULL
; /* Debug Msg Queue */
121 static uint8_t px_dbg_reference
= 0; /* Reference Counter */
122 static kmutex_t px_dbg_mutex
; /* Mutex for dequeuing */
123 static uint8_t px_dbg_qtail
= 0; /* Pointer to q tail */
124 static uint8_t px_dbg_qhead
= 0; /* Pointer to q head */
125 static uint_t px_dbg_qsize
= 0; /* # of pending messages */
126 static uint_t px_dbg_failed
= 0; /* # of overflows */
128 /* Forward Declarations */
129 static void px_dbg_print(px_debug_bit_t bit
, dev_info_t
*dip
, char *fmt
,
131 static void px_dbg_queue(px_debug_bit_t bit
, dev_info_t
*dip
, char *fmt
,
133 static uint_t
px_dbg_drain(caddr_t arg1
, caddr_t arg2
);
136 * Print function called either directly by px_dbg or through soft interrupt.
137 * This function cannot be called directly in threads with PIL above clock.
140 px_dbg_print(px_debug_bit_t bit
, dev_info_t
*dip
, char *fmt
, va_list args
)
142 int cont
= bit
>> DBG_BITS
;
148 prom_printf("%s(%d): %s: ", ddi_driver_name(dip
),
149 ddi_get_instance(dip
), px_debug_sym
[bit
]);
151 prom_printf("px: %s: ", px_debug_sym
[bit
]);
154 prom_vprintf(fmt
, args
);
160 * Queueing mechanism to log px_dbg messages if calling thread is running with a
161 * PIL above clock. It's Multithreaded safe.
164 px_dbg_queue(px_debug_bit_t bit
, dev_info_t
*dip
, char *fmt
, va_list args
)
166 int instance
= DIP_TO_INST(dip
);
167 px_t
*px_p
= INST_TO_STATE(instance
);
171 /* Check to make sure the queue hasn't overflowed */
172 if (atomic_inc_uint_nv(&px_dbg_qsize
) >= px_dbg_msg_size
) {
174 atomic_dec_uint(&px_dbg_qsize
);
179 * Grab the next available queue bucket. Incrementing the tail here
180 * doesn't need to be protected, as it is guaranteed to not overflow.
182 q_no
= ++px_dbg_qtail
& px_dbg_qmask
;
183 msg_p
= &px_dbg_msgq
[q_no
];
185 ASSERT(msg_p
->active
== B_FALSE
);
187 /* Print the message in the buffer */
188 vsnprintf(msg_p
->msg
, DBG_MSG_SIZE
, fmt
, args
);
191 msg_p
->active
= B_TRUE
;
193 /* Trigger Soft Int */
194 ddi_intr_trigger_softint(px_p
->px_dbg_hdl
, (caddr_t
)NULL
);
198 * Callback function for queuing px_dbg in high PIL by soft intr. This code
199 * assumes it will be called serially for every msg.
202 px_dbg_drain(caddr_t arg1
, caddr_t arg2
) {
205 uint_t ret
= DDI_INTR_UNCLAIMED
;
207 mutex_enter(&px_dbg_mutex
);
208 while (px_dbg_qsize
) {
209 atomic_dec_uint(&px_dbg_qsize
);
211 cmn_err(CE_WARN
, "%d msg(s) were lost",
216 q_no
= ++px_dbg_qhead
& px_dbg_qmask
;
217 msg_p
= &px_dbg_msgq
[q_no
];
220 px_dbg_print(msg_p
->bit
, msg_p
->dip
, msg_p
->msg
, NULL
);
221 msg_p
->active
= B_FALSE
;
223 ret
= DDI_INTR_CLAIMED
;
226 mutex_exit(&px_dbg_mutex
);
231 px_dbg(px_debug_bit_t bit
, dev_info_t
*dip
, char *fmt
, ...)
236 if (bit
>= sizeof (px_debug_sym
) / sizeof (char *))
238 if (!(1ull << bit
& px_debug_flags
))
242 if (getpil() > LOCK_LEVEL
)
243 px_dbg_queue(bit
, dip
, fmt
, ap
);
245 px_dbg_print(bit
, dip
, fmt
, ap
);
251 px_dbg_attach(dev_info_t
*dip
, ddi_softint_handle_t
*dbg_hdl
)
254 if (px_dbg_reference
++ == 0) {
255 int size
= px_dbg_msg_size
;
257 /* Check if px_dbg_msg_size is ^2 */
258 size
= !ISP2(size
) ? ((size
| ~size
) + 1) : size
;
259 px_dbg_msg_size
= size
;
260 px_dbg_qmask
= size
- 1;
261 px_dbg_msgq
= kmem_zalloc(sizeof (px_dbg_msg_t
) * size
,
264 mutex_init(&px_dbg_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
267 if (ddi_intr_add_softint(dip
, dbg_hdl
,
268 DDI_INTR_SOFTPRI_MAX
, px_dbg_drain
, NULL
) != DDI_SUCCESS
) {
270 "Unable to allocate soft int for DBG printing.\n");
278 px_dbg_detach(dev_info_t
*dip
, ddi_softint_handle_t
*dbg_hdl
)
282 (void) ddi_intr_remove_softint(*dbg_hdl
);
284 if (--px_dbg_reference
== 0) {
285 if (px_dbg_msgq
!= NULL
)
286 kmem_free(px_dbg_msgq
,
287 sizeof (px_dbg_msg_t
) * px_dbg_msg_size
);
288 mutex_destroy(&px_dbg_mutex
);