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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * PCI nexus driver general debug support 28 */ 29 #include <sys/sysmacros.h> 30 #include <sys/async.h> 31 #include <sys/sunddi.h> /* dev_info_t */ 32 #include <sys/ddi_impldefs.h> 33 #include <sys/disp.h> 34 #include <sys/archsystm.h> /* getpil() */ 35 #include "px_obj.h" 36 37 /*LINTLIBRARY*/ 38 39 #ifdef DEBUG 40 uint64_t px_debug_flags = 0; 41 42 static char *px_debug_sym [] = { /* same sequence as px_debug_bit */ 43 /* 0 */ "attach", 44 /* 1 */ "detach", 45 /* 2 */ "map", 46 /* 3 */ "nex-ctlops", 47 48 /* 4 */ "introps", 49 /* 5 */ "intx-add", 50 /* 6 */ "intx-rem", 51 /* 7 */ "intx-intr", 52 53 /* 8 */ "msiq", 54 /* 9 */ "msiq-intr", 55 /* 10 */ "msg", 56 /* 11 */ "msg-intr", 57 58 /* 12 */ "msix-add", 59 /* 13 */ "msix-rem", 60 /* 14 */ "msix-intr", 61 /* 15 */ "err", 62 63 /* 16 */ "dma-alloc", 64 /* 17 */ "dma-free", 65 /* 18 */ "dma-bind", 66 /* 19 */ "dma-unbind", 67 68 /* 20 */ "chk-dma-mode", 69 /* 21 */ "bypass-dma", 70 /* 22 */ "fast-dvma", 71 /* 23 */ "init_child", 72 73 /* 24 */ "dma-map", 74 /* 25 */ "dma-win", 75 /* 26 */ "map-win", 76 /* 27 */ "unmap-win", 77 78 /* 28 */ "dma-ctl", 79 /* 29 */ "dma-sync", 80 /* 30 */ NULL, 81 /* 31 */ NULL, 82 83 /* 32 */ "ib", 84 /* 33 */ "cb", 85 /* 34 */ "dmc", 86 /* 35 */ "pec", 87 88 /* 36 */ "ilu", 89 /* 37 */ "tlu", 90 /* 38 */ "lpu", 91 /* 39 */ "mmu", 92 93 /* 40 */ "open", 94 /* 41 */ "close", 95 /* 42 */ "ioctl", 96 /* 43 */ "pwr", 97 98 /* 44 */ "lib-cfg", 99 /* 45 */ "lib-intr", 100 /* 46 */ "lib-dma", 101 /* 47 */ "lib-msiq", 102 103 /* 48 */ "lib-msi", 104 /* 49 */ "lib-msg", 105 /* 50 */ "NULL", 106 /* 51 */ "NULL", 107 108 /* 52 */ "tools", 109 /* 53 */ "phys_acc", 110 111 /* 54 */ "hotplug", 112 /* LAST */ "unknown" 113 }; 114 115 /* Tunables */ 116 static int px_dbg_msg_size = 16; /* # of Qs. Must be ^2 */ 117 118 /* Non-Tunables */ 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 */ 127 128 /* Forward Declarations */ 129 static void px_dbg_print(px_debug_bit_t bit, dev_info_t *dip, char *fmt, 130 va_list args); 131 static void px_dbg_queue(px_debug_bit_t bit, dev_info_t *dip, char *fmt, 132 va_list args); 133 static uint_t px_dbg_drain(caddr_t arg1, caddr_t arg2); 134 135 /* 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. 138 */ 139 static void 140 px_dbg_print(px_debug_bit_t bit, dev_info_t *dip, char *fmt, va_list args) 141 { 142 int cont = bit >> DBG_BITS; 143 144 if (cont) 145 goto body; 146 147 if (dip) 148 prom_printf("%s(%d): %s: ", ddi_driver_name(dip), 149 ddi_get_instance(dip), px_debug_sym[bit]); 150 else 151 prom_printf("px: %s: ", px_debug_sym[bit]); 152 body: 153 if (args) 154 prom_vprintf(fmt, args); 155 else 156 prom_printf(fmt); 157 } 158 159 /* 160 * Queueing mechanism to log px_dbg messages if calling thread is running with a 161 * PIL above clock. It's Multithreaded safe. 162 */ 163 static void 164 px_dbg_queue(px_debug_bit_t bit, dev_info_t *dip, char *fmt, va_list args) 165 { 166 int instance = DIP_TO_INST(dip); 167 px_t *px_p = INST_TO_STATE(instance); 168 uint8_t q_no; 169 px_dbg_msg_t *msg_p; 170 171 /* Check to make sure the queue hasn't overflowed */ 172 if (atomic_inc_uint_nv(&px_dbg_qsize) >= px_dbg_msg_size) { 173 px_dbg_failed++; 174 atomic_dec_uint(&px_dbg_qsize); 175 return; 176 } 177 178 /* 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. 181 */ 182 q_no = ++px_dbg_qtail & px_dbg_qmask; 183 msg_p = &px_dbg_msgq[q_no]; 184 185 ASSERT(msg_p->active == B_FALSE); 186 187 /* Print the message in the buffer */ 188 vsnprintf(msg_p->msg, DBG_MSG_SIZE, fmt, args); 189 msg_p->bit = bit; 190 msg_p->dip = dip; 191 msg_p->active = B_TRUE; 192 193 /* Trigger Soft Int */ 194 ddi_intr_trigger_softint(px_p->px_dbg_hdl, (caddr_t)NULL); 195 } 196 197 /* 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. 200 */ 201 static uint_t 202 px_dbg_drain(caddr_t arg1, caddr_t arg2) { 203 uint8_t q_no; 204 px_dbg_msg_t *msg_p; 205 uint_t ret = DDI_INTR_UNCLAIMED; 206 207 mutex_enter(&px_dbg_mutex); 208 while (px_dbg_qsize) { 209 atomic_dec_uint(&px_dbg_qsize); 210 if (px_dbg_failed) { 211 cmn_err(CE_WARN, "%d msg(s) were lost", 212 px_dbg_failed); 213 px_dbg_failed = 0; 214 } 215 216 q_no = ++px_dbg_qhead & px_dbg_qmask; 217 msg_p = &px_dbg_msgq[q_no]; 218 219 if (msg_p->active) { 220 px_dbg_print(msg_p->bit, msg_p->dip, msg_p->msg, NULL); 221 msg_p->active = B_FALSE; 222 } 223 ret = DDI_INTR_CLAIMED; 224 } 225 226 mutex_exit(&px_dbg_mutex); 227 return (ret); 228 } 229 230 void 231 px_dbg(px_debug_bit_t bit, dev_info_t *dip, char *fmt, ...) 232 { 233 va_list ap; 234 235 bit &= DBG_MASK; 236 if (bit >= sizeof (px_debug_sym) / sizeof (char *)) 237 return; 238 if (!(1ull << bit & px_debug_flags)) 239 return; 240 241 va_start(ap, fmt); 242 if (getpil() > LOCK_LEVEL) 243 px_dbg_queue(bit, dip, fmt, ap); 244 else 245 px_dbg_print(bit, dip, fmt, ap); 246 va_end(ap); 247 } 248 #endif /* DEBUG */ 249 250 void 251 px_dbg_attach(dev_info_t *dip, ddi_softint_handle_t *dbg_hdl) 252 { 253 #ifdef DEBUG 254 if (px_dbg_reference++ == 0) { 255 int size = px_dbg_msg_size; 256 257 /* Check if px_dbg_msg_size is ^2 */ 258 /* 259 * WARNING: The bellow statement makes no sense. If size is 260 * not a power of 2, it will set size to zero. 261 */ 262 size = !ISP2(size) ? ((size | ~size) + 1) : size; 263 px_dbg_msg_size = size; 264 px_dbg_qmask = size - 1; 265 px_dbg_msgq = kmem_zalloc(sizeof (px_dbg_msg_t) * size, 266 KM_SLEEP); 267 268 mutex_init(&px_dbg_mutex, NULL, MUTEX_DRIVER, NULL); 269 } 270 271 if (ddi_intr_add_softint(dip, dbg_hdl, 272 DDI_INTR_SOFTPRI_MAX, px_dbg_drain, NULL) != DDI_SUCCESS) { 273 DBG(DBG_ATTACH, dip, 274 "Unable to allocate soft int for DBG printing.\n"); 275 dbg_hdl = NULL; 276 } 277 #endif /* DEBUG */ 278 } 279 280 /* ARGSUSED */ 281 void 282 px_dbg_detach(dev_info_t *dip, ddi_softint_handle_t *dbg_hdl) 283 { 284 #ifdef DEBUG 285 if (dbg_hdl != NULL) 286 (void) ddi_intr_remove_softint(*dbg_hdl); 287 288 if (--px_dbg_reference == 0) { 289 if (px_dbg_msgq != NULL) 290 kmem_free(px_dbg_msgq, 291 sizeof (px_dbg_msg_t) * px_dbg_msg_size); 292 mutex_destroy(&px_dbg_mutex); 293 } 294 #endif /* DEBUG */ 295 } 296