17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2230ef5f63Set142600 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * PCI nexus driver general debug support 287c478bd9Sstevel@tonic-gate */ 29de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h> 307c478bd9Sstevel@tonic-gate #include <sys/async.h> 317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> /* dev_info_t */ 327c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 337c478bd9Sstevel@tonic-gate #include <sys/disp.h> 34bf8fc234Set142600 #include <sys/archsystm.h> /* getpil() */ 35bf8fc234Set142600 #include "px_obj.h" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #ifdef DEBUG 406b2ad4beSjchu uint64_t px_debug_flags = 0; 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate static char *px_debug_sym [] = { /* same sequence as px_debug_bit */ 437c478bd9Sstevel@tonic-gate /* 0 */ "attach", 447c478bd9Sstevel@tonic-gate /* 1 */ "detach", 457c478bd9Sstevel@tonic-gate /* 2 */ "map", 467c478bd9Sstevel@tonic-gate /* 3 */ "nex-ctlops", 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 4 */ "introps", 497c478bd9Sstevel@tonic-gate /* 5 */ "intx-add", 507c478bd9Sstevel@tonic-gate /* 6 */ "intx-rem", 517c478bd9Sstevel@tonic-gate /* 7 */ "intx-intr", 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 8 */ "msiq", 547c478bd9Sstevel@tonic-gate /* 9 */ "msiq-intr", 557c478bd9Sstevel@tonic-gate /* 10 */ "msg", 567c478bd9Sstevel@tonic-gate /* 11 */ "msg-intr", 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 12 */ "msix-add", 597c478bd9Sstevel@tonic-gate /* 13 */ "msix-rem", 607c478bd9Sstevel@tonic-gate /* 14 */ "msix-intr", 617c478bd9Sstevel@tonic-gate /* 15 */ "err", 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* 16 */ "dma-alloc", 647c478bd9Sstevel@tonic-gate /* 17 */ "dma-free", 657c478bd9Sstevel@tonic-gate /* 18 */ "dma-bind", 667c478bd9Sstevel@tonic-gate /* 19 */ "dma-unbind", 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* 20 */ "chk-dma-mode", 697c478bd9Sstevel@tonic-gate /* 21 */ "bypass-dma", 707c478bd9Sstevel@tonic-gate /* 22 */ "fast-dvma", 717c478bd9Sstevel@tonic-gate /* 23 */ "init_child", 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 24 */ "dma-map", 747c478bd9Sstevel@tonic-gate /* 25 */ "dma-win", 757c478bd9Sstevel@tonic-gate /* 26 */ "map-win", 767c478bd9Sstevel@tonic-gate /* 27 */ "unmap-win", 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 28 */ "dma-ctl", 797c478bd9Sstevel@tonic-gate /* 29 */ "dma-sync", 807c478bd9Sstevel@tonic-gate /* 30 */ NULL, 817c478bd9Sstevel@tonic-gate /* 31 */ NULL, 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 32 */ "ib", 847c478bd9Sstevel@tonic-gate /* 33 */ "cb", 857c478bd9Sstevel@tonic-gate /* 34 */ "dmc", 867c478bd9Sstevel@tonic-gate /* 35 */ "pec", 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 36 */ "ilu", 897c478bd9Sstevel@tonic-gate /* 37 */ "tlu", 907c478bd9Sstevel@tonic-gate /* 38 */ "lpu", 9125cf1a30Sjl139090 /* 39 */ "mmu", 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 40 */ "open", 947c478bd9Sstevel@tonic-gate /* 41 */ "close", 957c478bd9Sstevel@tonic-gate /* 42 */ "ioctl", 967c478bd9Sstevel@tonic-gate /* 43 */ "pwr", 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 44 */ "lib-cfg", 997c478bd9Sstevel@tonic-gate /* 45 */ "lib-intr", 1007c478bd9Sstevel@tonic-gate /* 46 */ "lib-dma", 1017c478bd9Sstevel@tonic-gate /* 47 */ "lib-msiq", 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 48 */ "lib-msi", 1047c478bd9Sstevel@tonic-gate /* 49 */ "lib-msg", 1057c478bd9Sstevel@tonic-gate /* 50 */ "NULL", 1067c478bd9Sstevel@tonic-gate /* 51 */ "NULL", 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 52 */ "tools", 1097c478bd9Sstevel@tonic-gate /* 53 */ "phys_acc", 110f94c6026Sjj156685 111f94c6026Sjj156685 /* 54 */ "hotplug", 1127c478bd9Sstevel@tonic-gate /* LAST */ "unknown" 1137c478bd9Sstevel@tonic-gate }; 1147c478bd9Sstevel@tonic-gate 115bf8fc234Set142600 /* Tunables */ 116bf8fc234Set142600 static int px_dbg_msg_size = 16; /* # of Qs. Must be ^2 */ 117bf8fc234Set142600 118bf8fc234Set142600 /* Non-Tunables */ 119bf8fc234Set142600 static int px_dbg_qmask = 0xFFFF; /* Mask based on Q size */ 120bf8fc234Set142600 static px_dbg_msg_t *px_dbg_msgq = NULL; /* Debug Msg Queue */ 121bf8fc234Set142600 static uint8_t px_dbg_reference = 0; /* Reference Counter */ 122bf8fc234Set142600 static kmutex_t px_dbg_mutex; /* Mutex for dequeuing */ 123bf8fc234Set142600 static uint8_t px_dbg_qtail = 0; /* Pointer to q tail */ 124bf8fc234Set142600 static uint8_t px_dbg_qhead = 0; /* Pointer to q head */ 125bf8fc234Set142600 static uint_t px_dbg_qsize = 0; /* # of pending messages */ 126bf8fc234Set142600 static uint_t px_dbg_failed = 0; /* # of overflows */ 127bf8fc234Set142600 128bf8fc234Set142600 /* Forward Declarations */ 129bf8fc234Set142600 static void px_dbg_print(px_debug_bit_t bit, dev_info_t *dip, char *fmt, 130bf8fc234Set142600 va_list args); 131bf8fc234Set142600 static void px_dbg_queue(px_debug_bit_t bit, dev_info_t *dip, char *fmt, 132bf8fc234Set142600 va_list args); 133bf8fc234Set142600 static uint_t px_dbg_drain(caddr_t arg1, caddr_t arg2); 134bf8fc234Set142600 135bf8fc234Set142600 /* 136bf8fc234Set142600 * Print function called either directly by px_dbg or through soft interrupt. 137bf8fc234Set142600 * This function cannot be called directly in threads with PIL above clock. 138bf8fc234Set142600 */ 139bf8fc234Set142600 static void 140bf8fc234Set142600 px_dbg_print(px_debug_bit_t bit, dev_info_t *dip, char *fmt, va_list args) 1417c478bd9Sstevel@tonic-gate { 1427c478bd9Sstevel@tonic-gate int cont = bit >> DBG_BITS; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (cont) 1457c478bd9Sstevel@tonic-gate goto body; 146f8d2de6bSjchu 1477c478bd9Sstevel@tonic-gate if (dip) 1486b2ad4beSjchu prom_printf("%s(%d): %s: ", ddi_driver_name(dip), 1496b2ad4beSjchu ddi_get_instance(dip), px_debug_sym[bit]); 1507c478bd9Sstevel@tonic-gate else 1516b2ad4beSjchu prom_printf("px: %s: ", px_debug_sym[bit]); 1526b2ad4beSjchu body: 153bf8fc234Set142600 if (args) 154bf8fc234Set142600 prom_vprintf(fmt, args); 155bf8fc234Set142600 else 156bf8fc234Set142600 prom_printf(fmt); 157bf8fc234Set142600 } 158bf8fc234Set142600 159bf8fc234Set142600 /* 160bf8fc234Set142600 * Queueing mechanism to log px_dbg messages if calling thread is running with a 161bf8fc234Set142600 * PIL above clock. It's Multithreaded safe. 162bf8fc234Set142600 */ 163bf8fc234Set142600 static void 164bf8fc234Set142600 px_dbg_queue(px_debug_bit_t bit, dev_info_t *dip, char *fmt, va_list args) 165bf8fc234Set142600 { 166bf8fc234Set142600 int instance = DIP_TO_INST(dip); 167bf8fc234Set142600 px_t *px_p = INST_TO_STATE(instance); 168bf8fc234Set142600 uint8_t q_no; 169bf8fc234Set142600 px_dbg_msg_t *msg_p; 170bf8fc234Set142600 171bf8fc234Set142600 /* Check to make sure the queue hasn't overflowed */ 172bf8fc234Set142600 if (atomic_inc_uint_nv(&px_dbg_qsize) >= px_dbg_msg_size) { 173bf8fc234Set142600 px_dbg_failed++; 174bf8fc234Set142600 atomic_dec_uint(&px_dbg_qsize); 175bf8fc234Set142600 return; 176bf8fc234Set142600 } 177bf8fc234Set142600 178bf8fc234Set142600 /* 179bf8fc234Set142600 * Grab the next available queue bucket. Incrementing the tail here 180bf8fc234Set142600 * doesn't need to be protected, as it is guaranteed to not overflow. 181bf8fc234Set142600 */ 182bf8fc234Set142600 q_no = ++px_dbg_qtail & px_dbg_qmask; 183bf8fc234Set142600 msg_p = &px_dbg_msgq[q_no]; 184bf8fc234Set142600 185bf8fc234Set142600 ASSERT(msg_p->active == B_FALSE); 186bf8fc234Set142600 187bf8fc234Set142600 /* Print the message in the buffer */ 188bf8fc234Set142600 vsnprintf(msg_p->msg, DBG_MSG_SIZE, fmt, args); 189bf8fc234Set142600 msg_p->bit = bit; 190bf8fc234Set142600 msg_p->dip = dip; 191bf8fc234Set142600 msg_p->active = B_TRUE; 192bf8fc234Set142600 193bf8fc234Set142600 /* Trigger Soft Int */ 194bf8fc234Set142600 ddi_intr_trigger_softint(px_p->px_dbg_hdl, (caddr_t)NULL); 195bf8fc234Set142600 } 196bf8fc234Set142600 197bf8fc234Set142600 /* 198bf8fc234Set142600 * Callback function for queuing px_dbg in high PIL by soft intr. This code 199bf8fc234Set142600 * assumes it will be called serially for every msg. 200bf8fc234Set142600 */ 201bf8fc234Set142600 static uint_t 202bf8fc234Set142600 px_dbg_drain(caddr_t arg1, caddr_t arg2) { 203bf8fc234Set142600 uint8_t q_no; 204bf8fc234Set142600 px_dbg_msg_t *msg_p; 205bf8fc234Set142600 uint_t ret = DDI_INTR_UNCLAIMED; 206bf8fc234Set142600 207bf8fc234Set142600 mutex_enter(&px_dbg_mutex); 208bf8fc234Set142600 while (px_dbg_qsize) { 209bf8fc234Set142600 atomic_dec_uint(&px_dbg_qsize); 210bf8fc234Set142600 if (px_dbg_failed) { 211bf8fc234Set142600 cmn_err(CE_WARN, "%d msg(s) were lost", 212bf8fc234Set142600 px_dbg_failed); 213bf8fc234Set142600 px_dbg_failed = 0; 214bf8fc234Set142600 } 215bf8fc234Set142600 216bf8fc234Set142600 q_no = ++px_dbg_qhead & px_dbg_qmask; 217bf8fc234Set142600 msg_p = &px_dbg_msgq[q_no]; 218bf8fc234Set142600 219bf8fc234Set142600 if (msg_p->active) { 220bf8fc234Set142600 px_dbg_print(msg_p->bit, msg_p->dip, msg_p->msg, NULL); 221bf8fc234Set142600 msg_p->active = B_FALSE; 222bf8fc234Set142600 } 223bf8fc234Set142600 ret = DDI_INTR_CLAIMED; 224bf8fc234Set142600 } 225bf8fc234Set142600 226bf8fc234Set142600 mutex_exit(&px_dbg_mutex); 227bf8fc234Set142600 return (ret); 228bf8fc234Set142600 } 229bf8fc234Set142600 230bf8fc234Set142600 void 231bf8fc234Set142600 px_dbg(px_debug_bit_t bit, dev_info_t *dip, char *fmt, ...) 232bf8fc234Set142600 { 233bf8fc234Set142600 va_list ap; 234bf8fc234Set142600 235bf8fc234Set142600 bit &= DBG_MASK; 236bf8fc234Set142600 if (bit >= sizeof (px_debug_sym) / sizeof (char *)) 237bf8fc234Set142600 return; 238bf8fc234Set142600 if (!(1ull << bit & px_debug_flags)) 239bf8fc234Set142600 return; 240bf8fc234Set142600 2417c478bd9Sstevel@tonic-gate va_start(ap, fmt); 242bf8fc234Set142600 if (getpil() > LOCK_LEVEL) 243bf8fc234Set142600 px_dbg_queue(bit, dip, fmt, ap); 244bf8fc234Set142600 else 245bf8fc234Set142600 px_dbg_print(bit, dip, fmt, ap); 2467c478bd9Sstevel@tonic-gate va_end(ap); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 249bf8fc234Set142600 250bf8fc234Set142600 void 251bf8fc234Set142600 px_dbg_attach(dev_info_t *dip, ddi_softint_handle_t *dbg_hdl) 252bf8fc234Set142600 { 253bf8fc234Set142600 #ifdef DEBUG 254bf8fc234Set142600 if (px_dbg_reference++ == 0) { 255bf8fc234Set142600 int size = px_dbg_msg_size; 256bf8fc234Set142600 257bf8fc234Set142600 /* Check if px_dbg_msg_size is ^2 */ 258*0716b62fSJosef 'Jeff' Sipek /* 259*0716b62fSJosef 'Jeff' Sipek * WARNING: The bellow statement makes no sense. If size is 260*0716b62fSJosef 'Jeff' Sipek * not a power of 2, it will set size to zero. 261*0716b62fSJosef 'Jeff' Sipek */ 262de710d24SJosef 'Jeff' Sipek size = !ISP2(size) ? ((size | ~size) + 1) : size; 263bf8fc234Set142600 px_dbg_msg_size = size; 264bf8fc234Set142600 px_dbg_qmask = size - 1; 265bf8fc234Set142600 px_dbg_msgq = kmem_zalloc(sizeof (px_dbg_msg_t) * size, 266bf8fc234Set142600 KM_SLEEP); 267bf8fc234Set142600 268bf8fc234Set142600 mutex_init(&px_dbg_mutex, NULL, MUTEX_DRIVER, NULL); 269bf8fc234Set142600 } 270bf8fc234Set142600 271bf8fc234Set142600 if (ddi_intr_add_softint(dip, dbg_hdl, 272bf8fc234Set142600 DDI_INTR_SOFTPRI_MAX, px_dbg_drain, NULL) != DDI_SUCCESS) { 273bf8fc234Set142600 DBG(DBG_ATTACH, dip, 274bf8fc234Set142600 "Unable to allocate soft int for DBG printing.\n"); 275bf8fc234Set142600 dbg_hdl = NULL; 276bf8fc234Set142600 } 277bf8fc234Set142600 #endif /* DEBUG */ 278bf8fc234Set142600 } 279bf8fc234Set142600 280bf8fc234Set142600 /* ARGSUSED */ 281bf8fc234Set142600 void 282bf8fc234Set142600 px_dbg_detach(dev_info_t *dip, ddi_softint_handle_t *dbg_hdl) 283bf8fc234Set142600 { 284bf8fc234Set142600 #ifdef DEBUG 285bf8fc234Set142600 if (dbg_hdl != NULL) 286bf8fc234Set142600 (void) ddi_intr_remove_softint(*dbg_hdl); 28730ef5f63Set142600 28830ef5f63Set142600 if (--px_dbg_reference == 0) { 289bf8fc234Set142600 if (px_dbg_msgq != NULL) 290bf8fc234Set142600 kmem_free(px_dbg_msgq, 291bf8fc234Set142600 sizeof (px_dbg_msg_t) * px_dbg_msg_size); 292bf8fc234Set142600 mutex_destroy(&px_dbg_mutex); 293bf8fc234Set142600 } 294bf8fc234Set142600 #endif /* DEBUG */ 295bf8fc234Set142600 } 296