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 *
irm_get_type(int type)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
check_irm_enabled(void)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
irmpools_walk_init(mdb_walk_state_t * wsp)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
irmreqs_walk_init(mdb_walk_state_t * wsp)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
irmpools_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 /*
144 * Include driver instance number only if the node has an
145 * instance number assigned (i.e. instance != -1) to it.
146 * This will cover cases like rootnex driver which doesn't
147 * have instance number assigned to it.
148 */
149 if (dev.devi_instance != -1)
150 mdb_snprintf(devname, sizeof (devname), "%s#%d", driver,
151 dev.devi_instance);
152 else
153 mdb_snprintf(devname, sizeof (devname), "%s", driver);
154
155 mdb_printf("%0?p %-18s %-8s %-6d %-9d %-8d\n", addr, devname,
156 irm_get_type(pool.ipool_types), pool.ipool_totsz,
157 pool.ipool_reqno, pool.ipool_resno);
158
159 return (DCMD_OK);
160 }
161
162 int
irmreqs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)163 irmreqs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
164 {
165 if (argc != 0)
166 return (DCMD_USAGE);
167
168 if (check_irm_enabled() == 0) {
169 mdb_warn("IRM is not enabled");
170 return (DCMD_ERR);
171 }
172
173 if (!(flags & DCMD_ADDRSPEC)) {
174 mdb_warn("can't perform global interrupt request walk");
175 return (DCMD_ERR);
176 }
177
178 if (mdb_pwalk_dcmd("irmreqs", "irmreq", argc, argv, addr) == -1) {
179 mdb_warn("can't walk interrupt requests");
180 return (DCMD_ERR);
181 }
182
183 return (DCMD_OK);
184 }
185
186 /*ARGSUSED*/
187 int
irmreq_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)188 irmreq_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
189 {
190 ddi_irm_req_t req;
191 struct dev_info dev;
192 struct devinfo_intr intr;
193 char driver[MODMAXNAMELEN + 1] = "";
194 char devname[MODMAXNAMELEN + 1] = "";
195
196 if (argc != 0)
197 return (DCMD_USAGE);
198
199 if (!(flags & DCMD_ADDRSPEC)) {
200 return (DCMD_ERR);
201 }
202
203 if (DCMD_HDRSPEC(flags)) {
204 mdb_printf("%<u>%?s %-18s %-8s %-8s %-6s %-4s "
205 "%-6s%</u>\n", "ADDR", "OWNER", "TYPE", "CALLBACK",
206 "NINTRS", "NREQ", "NAVAIL");
207 }
208
209 if (mdb_vread(&req, sizeof (req), addr) != sizeof (req)) {
210 mdb_warn("couldn't read interrupt request at %p", addr);
211 return (DCMD_ERR);
212 }
213
214 if (mdb_vread(&dev, sizeof (dev),
215 (uintptr_t)req.ireq_dip) != sizeof (dev)) {
216 mdb_warn("couldn't read dev_info at %p", req.ireq_dip);
217 return (DCMD_ERR);
218 }
219
220 if (mdb_vread(&intr, sizeof (intr),
221 (uintptr_t)dev.devi_intr_p) != sizeof (intr)) {
222 mdb_warn("couldn't read devinfo_intr at %p", dev.devi_intr_p);
223 return (DCMD_ERR);
224 }
225
226 mdb_devinfo2driver((uintptr_t)req.ireq_dip, driver, sizeof (driver));
227 mdb_snprintf(devname, sizeof (devname), "%s#%d", driver,
228 dev.devi_instance);
229
230 mdb_printf("%0?p %-18s %-8s %-8s %-6d %-4d %-6d\n",
231 addr, devname, irm_get_type(req.ireq_type),
232 (req.ireq_flags & DDI_IRM_FLAG_CALLBACK) ? "Yes" : "No",
233 intr.devi_intr_sup_nintrs, req.ireq_nreq, req.ireq_navail);
234
235 return (DCMD_OK);
236 }
237