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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/mdb_modapi.h> 26 #include <sys/proc.h> 27 #include <sys/types.h> 28 #include <sys/sunddi.h> 29 #include <sys/ddi_intr.h> 30 #include <sys/ddi_intr_impl.h> 31 #include <stddef.h> 32 33 #include "list.h" 34 35 extern int mdb_devinfo2driver(uintptr_t, char *, size_t); 36 37 static char * 38 irm_get_type(int type) 39 { 40 if (type == (DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX)) 41 return ("MSI/X"); 42 43 switch (type) { 44 case DDI_INTR_TYPE_FIXED: 45 return ("Fixed"); 46 case DDI_INTR_TYPE_MSI: 47 return ("MSI"); 48 case DDI_INTR_TYPE_MSIX: 49 return ("MSI-X"); 50 default: 51 return ("Unknown"); 52 } 53 } 54 55 static int 56 check_irm_enabled(void) 57 { 58 GElf_Sym sym; 59 uintptr_t addr; 60 int value; 61 62 if (mdb_lookup_by_name("irm_enable", &sym) == -1) { 63 mdb_warn("couldn't find irm_enable"); 64 return (0); 65 } 66 67 addr = (uintptr_t)sym.st_value; 68 69 if (mdb_vread(&value, sizeof (value), addr) != sizeof (value)) { 70 mdb_warn("couldn't read irm_enable at %p", addr); 71 return (0); 72 } 73 74 return (value); 75 } 76 77 int 78 irmpools_walk_init(mdb_walk_state_t *wsp) 79 { 80 GElf_Sym sym; 81 82 if (mdb_lookup_by_name("irm_pools_list", &sym) == -1) { 83 mdb_warn("couldn't find irm_pools_list"); 84 return (WALK_ERR); 85 } 86 87 wsp->walk_addr = (uintptr_t)sym.st_value; 88 89 return (list_walk_init_named(wsp, "interrupt pools", "pool")); 90 } 91 92 int 93 irmreqs_walk_init(mdb_walk_state_t *wsp) 94 { 95 wsp->walk_addr = (uintptr_t)(wsp->walk_addr + 96 offsetof(ddi_irm_pool_t, ipool_req_list)); 97 98 return (list_walk_init_named(wsp, "interrupt requests", "request")); 99 } 100 101 int 102 irmpools_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 103 { 104 ddi_irm_pool_t pool; 105 struct dev_info dev; 106 char driver[MODMAXNAMELEN + 1] = ""; 107 char devname[MODMAXNAMELEN + 1] = ""; 108 109 if (argc != 0) 110 return (DCMD_USAGE); 111 112 if (check_irm_enabled() == 0) { 113 mdb_warn("IRM is not enabled"); 114 return (DCMD_ERR); 115 } 116 117 if (!(flags & DCMD_ADDRSPEC)) { 118 if (mdb_walk_dcmd("irmpools", "irmpools", argc, argv) == -1) { 119 mdb_warn("can't walk interrupt pools"); 120 return (DCMD_ERR); 121 } 122 return (DCMD_OK); 123 } 124 125 if (DCMD_HDRSPEC(flags)) { 126 mdb_printf("%<u>%?s %-18s %-8s %-6s %-9s %-8s%</u>\n", 127 "ADDR", "OWNER", "TYPE", "SIZE", "REQUESTED", "RESERVED"); 128 } 129 130 if (mdb_vread(&pool, sizeof (pool), addr) != sizeof (pool)) { 131 mdb_warn("couldn't read interrupt pool at %p", addr); 132 return (DCMD_ERR); 133 } 134 135 if (mdb_vread(&dev, sizeof (dev), 136 (uintptr_t)pool.ipool_owner) != sizeof (dev)) { 137 mdb_warn("couldn't read dev_info at %p", pool.ipool_owner); 138 return (DCMD_ERR); 139 } 140 141 mdb_devinfo2driver((uintptr_t)pool.ipool_owner, driver, 142 sizeof (driver)); 143 mdb_snprintf(devname, sizeof (devname), "%s#%d", driver, 144 dev.devi_instance); 145 146 mdb_printf("%0?p %-18s %-8s %-6d %-9d %-8d\n", addr, devname, 147 irm_get_type(pool.ipool_types), pool.ipool_totsz, 148 pool.ipool_reqno, pool.ipool_resno); 149 150 return (DCMD_OK); 151 } 152 153 int 154 irmreqs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 155 { 156 if (argc != 0) 157 return (DCMD_USAGE); 158 159 if (check_irm_enabled() == 0) { 160 mdb_warn("IRM is not enabled"); 161 return (DCMD_ERR); 162 } 163 164 if (!(flags & DCMD_ADDRSPEC)) { 165 mdb_warn("can't perform global interrupt request walk"); 166 return (DCMD_ERR); 167 } 168 169 if (mdb_pwalk_dcmd("irmreqs", "irmreq", argc, argv, addr) == -1) { 170 mdb_warn("can't walk interrupt requests"); 171 return (DCMD_ERR); 172 } 173 174 return (DCMD_OK); 175 } 176 177 /*ARGSUSED*/ 178 int 179 irmreq_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 180 { 181 ddi_irm_req_t req; 182 struct dev_info dev; 183 struct devinfo_intr intr; 184 char driver[MODMAXNAMELEN + 1] = ""; 185 char devname[MODMAXNAMELEN + 1] = ""; 186 187 if (argc != 0) 188 return (DCMD_USAGE); 189 190 if (!(flags & DCMD_ADDRSPEC)) { 191 return (DCMD_ERR); 192 } 193 194 if (DCMD_HDRSPEC(flags)) { 195 mdb_printf("%<u>%?s %-18s %-8s %-8s %-6s %-4s " 196 "%-6s%</u>\n", "ADDR", "OWNER", "TYPE", "CALLBACK", 197 "NINTRS", "NREQ", "NAVAIL"); 198 } 199 200 if (mdb_vread(&req, sizeof (req), addr) != sizeof (req)) { 201 mdb_warn("couldn't read interrupt request at %p", addr); 202 return (DCMD_ERR); 203 } 204 205 if (mdb_vread(&dev, sizeof (dev), 206 (uintptr_t)req.ireq_dip) != sizeof (dev)) { 207 mdb_warn("couldn't read dev_info at %p", req.ireq_dip); 208 return (DCMD_ERR); 209 } 210 211 if (mdb_vread(&intr, sizeof (intr), 212 (uintptr_t)dev.devi_intr_p) != sizeof (intr)) { 213 mdb_warn("couldn't read devinfo_intr at %p", dev.devi_intr_p); 214 return (DCMD_ERR); 215 } 216 217 mdb_devinfo2driver((uintptr_t)req.ireq_dip, driver, sizeof (driver)); 218 mdb_snprintf(devname, sizeof (devname), "%s#%d", driver, 219 dev.devi_instance); 220 221 mdb_printf("%0?p %-18s %-8s %-8s %-6d %-4d %-6d\n", 222 addr, devname, irm_get_type(req.ireq_type), 223 (req.ireq_flags & DDI_IRM_FLAG_CALLBACK) ? "Yes" : "No", 224 intr.devi_intr_sup_nintrs, req.ireq_nreq, req.ireq_navail); 225 226 return (DCMD_OK); 227 } 228