1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #include <gelf.h>
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate #include <sys/mdb_modapi.h>
32*0Sstevel@tonic-gate #include <mdb/mdb_ks.h>
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate #include <sys/usb/usba.h>
35*0Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h>
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhci.h>
38*0Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
39*0Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gate #define UHCI_TD 0
43*0Sstevel@tonic-gate #define UHCI_QH 1
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate /* Prototypes */
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate int uhci_td(uintptr_t, uint_t, int, const mdb_arg_t *);
49*0Sstevel@tonic-gate int uhci_qh(uintptr_t, uint_t, int, const mdb_arg_t *);
50*0Sstevel@tonic-gate int uhci_td_walk_init(mdb_walk_state_t *);
51*0Sstevel@tonic-gate int uhci_td_walk_step(mdb_walk_state_t *);
52*0Sstevel@tonic-gate int uhci_qh_walk_init(mdb_walk_state_t *);
53*0Sstevel@tonic-gate int uhci_qh_walk_step(mdb_walk_state_t *);
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate * Callback for find_uhci_statep (called back from walk "softstate" in
58*0Sstevel@tonic-gate * find_uhci_statep).
59*0Sstevel@tonic-gate *
60*0Sstevel@tonic-gate * - uhci_instancep is the value of the current pointer in the array of soft
61*0Sstevel@tonic-gate * state instance pointers (see i_ddi_soft_state in ddi_impldefs.h)
62*0Sstevel@tonic-gate * - local_ss is a pointer to the copy of the i_ddi_soft_state in local space
63*0Sstevel@tonic-gate * - cb_arg is a pointer to the cb arg (an instance of state_find_data).
64*0Sstevel@tonic-gate *
65*0Sstevel@tonic-gate * For the current uchi_state_t*, see if the td address is in its pool.
66*0Sstevel@tonic-gate *
67*0Sstevel@tonic-gate * Returns WALK_NEXT on success (match not found yet), WALK_ERR on errors.
68*0Sstevel@tonic-gate *
69*0Sstevel@tonic-gate * WALK_DONE is returned, cb_data.found is set to TRUE, and
70*0Sstevel@tonic-gate * *cb_data.fic_uhci_statep is filled in with the contents of the state
71*0Sstevel@tonic-gate * struct in core. This forces the walk to terminate.
72*0Sstevel@tonic-gate */
73*0Sstevel@tonic-gate typedef struct find_instance_struct {
74*0Sstevel@tonic-gate void *fic_td_qh; /* td/qh we want uhci instance for */
75*0Sstevel@tonic-gate boolean_t fic_td_or_qh; /* which one td_qh points to */
76*0Sstevel@tonic-gate boolean_t fic_found;
77*0Sstevel@tonic-gate uhci_state_t *fic_uhci_statep; /* buffer uhci_state's written into */
78*0Sstevel@tonic-gate } find_instance_cb_t;
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate /*ARGSUSED*/
81*0Sstevel@tonic-gate static int
find_uhci_instance(uintptr_t uhci_instancep,const void * local_ss,void * cb_arg)82*0Sstevel@tonic-gate find_uhci_instance(uintptr_t uhci_instancep, const void *local_ss, void *cb_arg)
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate int td_pool_size, qh_pool_size;
85*0Sstevel@tonic-gate find_instance_cb_t *cb_data = (find_instance_cb_t *)cb_arg;
86*0Sstevel@tonic-gate uhci_state_t *uhcip = cb_data->fic_uhci_statep;
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate if (mdb_vread(cb_data->fic_uhci_statep, sizeof (uhci_state_t),
90*0Sstevel@tonic-gate uhci_instancep) == -1) {
91*0Sstevel@tonic-gate mdb_warn("failed to read uhci_state at %p", uhci_instancep);
92*0Sstevel@tonic-gate return (-1);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate if (mdb_readsym(&td_pool_size, sizeof (int), "uhci_td_pool_size") ==
96*0Sstevel@tonic-gate -1) {
97*0Sstevel@tonic-gate mdb_warn("failed to read uhci_td_pool_size");
98*0Sstevel@tonic-gate return (-1);
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate if (mdb_readsym(&qh_pool_size, sizeof (int), "uhci_qh_pool_size") ==
102*0Sstevel@tonic-gate -1) {
103*0Sstevel@tonic-gate mdb_warn("failed to read uhci_td_pool_size");
104*0Sstevel@tonic-gate return (-1);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate * See if the addr is within the appropriate pool for this instance.
109*0Sstevel@tonic-gate */
110*0Sstevel@tonic-gate if ((cb_data->fic_td_or_qh == UHCI_TD &&
111*0Sstevel@tonic-gate
112*0Sstevel@tonic-gate ((uhci_td_t *)cb_data->fic_td_qh >= uhcip->uhci_td_pool_addr &&
113*0Sstevel@tonic-gate (uhci_td_t *)cb_data->fic_td_qh <= (uhcip->uhci_td_pool_addr +
114*0Sstevel@tonic-gate td_pool_size - sizeof (uhci_td_t)))) ||
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate (cb_data->fic_td_or_qh == UHCI_QH &&
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate ((queue_head_t *)cb_data->fic_td_qh >= uhcip->uhci_qh_pool_addr &&
119*0Sstevel@tonic-gate (queue_head_t *)cb_data->fic_td_qh <= (uhcip->uhci_qh_pool_addr +
120*0Sstevel@tonic-gate qh_pool_size - sizeof (queue_head_t))))) {
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gate /* td/qh address is within pool for this instance of uhci. */
123*0Sstevel@tonic-gate cb_data->fic_found = TRUE;
124*0Sstevel@tonic-gate return (WALK_DONE);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gate return (WALK_NEXT);
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate /*
131*0Sstevel@tonic-gate * Figure out which instance of uhci owns a td/qh.
132*0Sstevel@tonic-gate *
133*0Sstevel@tonic-gate * - td_qh: a pointer to a uhci td or qh
134*0Sstevel@tonic-gate * - td_or_qh: a flag indicating which it is (td/qh),
135*0Sstevel@tonic-gate * - uhci_statep, pointer to a uhci_state_t, to be filled in with data from
136*0Sstevel@tonic-gate * the found instance of uhci_state_t.
137*0Sstevel@tonic-gate *
138*0Sstevel@tonic-gate * Only works for Cntl/Interrupt tds/qhs; others are dynamically allocated
139*0Sstevel@tonic-gate * and so cannot be found with this method.
140*0Sstevel@tonic-gate *
141*0Sstevel@tonic-gate * Returns 0 on success (no match found), 1 on success (match found),
142*0Sstevel@tonic-gate * -1 on errors.
143*0Sstevel@tonic-gate */
144*0Sstevel@tonic-gate static int
find_uhci_statep(void * td_qh,boolean_t td_or_qh,uhci_state_t * uhci_statep)145*0Sstevel@tonic-gate find_uhci_statep(void *td_qh, boolean_t td_or_qh, uhci_state_t *uhci_statep)
146*0Sstevel@tonic-gate {
147*0Sstevel@tonic-gate find_instance_cb_t cb_data;
148*0Sstevel@tonic-gate uintptr_t uhci_ss;
149*0Sstevel@tonic-gate
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate if (uhci_statep == NULL) {
152*0Sstevel@tonic-gate mdb_warn("failed to find uhci statep: "
153*0Sstevel@tonic-gate "NULL uhci_statep param\n");
154*0Sstevel@tonic-gate return (-1);
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate cb_data.fic_td_qh = td_qh;
158*0Sstevel@tonic-gate cb_data.fic_td_or_qh = td_or_qh;
159*0Sstevel@tonic-gate cb_data.fic_found = FALSE;
160*0Sstevel@tonic-gate cb_data.fic_uhci_statep = uhci_statep;
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate if (mdb_readsym(&uhci_ss, sizeof (uhci_statep),
164*0Sstevel@tonic-gate "uhci_statep") == -1) {
165*0Sstevel@tonic-gate mdb_warn("failed to read uhci_statep");
166*0Sstevel@tonic-gate return (-1);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate /*
171*0Sstevel@tonic-gate * Walk all instances of uhci.
172*0Sstevel@tonic-gate * The callback func checks if td_qh belongs to a given instance
173*0Sstevel@tonic-gate * of uhci.
174*0Sstevel@tonic-gate */
175*0Sstevel@tonic-gate if (mdb_pwalk("softstate", find_uhci_instance, &cb_data,
176*0Sstevel@tonic-gate uhci_ss) != 0) {
177*0Sstevel@tonic-gate mdb_warn("failed to walk softstate");
178*0Sstevel@tonic-gate return (-1);
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate if (cb_data.fic_found == TRUE) {
182*0Sstevel@tonic-gate return (1);
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate return (0);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate * Dump a UHCI TD (transaction descriptor);
190*0Sstevel@tonic-gate * or (-d) the chain of TDs starting with the one specified.
191*0Sstevel@tonic-gate */
192*0Sstevel@tonic-gate int
uhci_td(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)193*0Sstevel@tonic-gate uhci_td(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate uint_t depth_flag = FALSE;
196*0Sstevel@tonic-gate uhci_state_t uhci_state, *uhcip = &uhci_state;
197*0Sstevel@tonic-gate uhci_td_t td;
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
201*0Sstevel@tonic-gate return (DCMD_USAGE);
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate if (addr & ~QH_LINK_PTR_MASK) {
204*0Sstevel@tonic-gate mdb_warn("address must be on a 16-byte boundary.\n");
205*0Sstevel@tonic-gate return (DCMD_ERR);
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate if (mdb_getopts(argc, argv,
209*0Sstevel@tonic-gate 'd', MDB_OPT_SETBITS, TRUE, &depth_flag,
210*0Sstevel@tonic-gate NULL) != argc) {
211*0Sstevel@tonic-gate return (DCMD_USAGE);
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate
214*0Sstevel@tonic-gate
215*0Sstevel@tonic-gate if (depth_flag) {
216*0Sstevel@tonic-gate if (mdb_pwalk_dcmd("uhci_td", "uhci_td", 0, NULL, addr) == -1) {
217*0Sstevel@tonic-gate mdb_warn("failed to walk 'uhci_td'");
218*0Sstevel@tonic-gate return (DCMD_ERR);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate return (DCMD_OK);
221*0Sstevel@tonic-gate }
222*0Sstevel@tonic-gate
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate if (find_uhci_statep((void *)addr, UHCI_TD, uhcip) != 1) {
225*0Sstevel@tonic-gate mdb_warn("failed to find uhci_statep");
226*0Sstevel@tonic-gate return (DCMD_ERR);
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gate if (mdb_vread(&td, sizeof (td), addr) != sizeof (td)) {
230*0Sstevel@tonic-gate mdb_warn("failed to read td at vaddr %p", addr);
231*0Sstevel@tonic-gate return (DCMD_ERR);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate
234*0Sstevel@tonic-gate mdb_printf("\n UHCI td struct at (vaddr) %08x:\n", addr);
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate if (!(td.link_ptr & HC_END_OF_LIST) && td.link_ptr != NULL) {
237*0Sstevel@tonic-gate mdb_printf(" link_ptr (paddr) : %-8x "
238*0Sstevel@tonic-gate "(vaddr) : %p\n",
239*0Sstevel@tonic-gate td.link_ptr,
240*0Sstevel@tonic-gate /* Note: uhcip needed by TD_VADDR macro */
241*0Sstevel@tonic-gate TD_VADDR(td.link_ptr & QH_LINK_PTR_MASK));
242*0Sstevel@tonic-gate } else {
243*0Sstevel@tonic-gate mdb_printf(" link_ptr (paddr) : %-8x\n",
244*0Sstevel@tonic-gate td.link_ptr);
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate mdb_printf(" td_dword2 : %08x\n", td.dw2);
247*0Sstevel@tonic-gate mdb_printf(" td_dword3 : %08x\n", td.dw3);
248*0Sstevel@tonic-gate mdb_printf(" buffer_address : %08x\n", td.buffer_address);
249*0Sstevel@tonic-gate mdb_printf(" qh_td_prev : %?p "
250*0Sstevel@tonic-gate "tw_td_next : %?p\n",
251*0Sstevel@tonic-gate td.qh_td_prev, td.tw_td_next);
252*0Sstevel@tonic-gate mdb_printf(" outst_td_prev : %?p "
253*0Sstevel@tonic-gate "outst_td_next : %?p\n",
254*0Sstevel@tonic-gate td.outst_td_prev, td.outst_td_next);
255*0Sstevel@tonic-gate mdb_printf(" tw : %?p "
256*0Sstevel@tonic-gate "flag : %02x\n", td.tw, td.flag);
257*0Sstevel@tonic-gate mdb_printf(" isoc_next : %?p "
258*0Sstevel@tonic-gate "isoc_prev : %0x\n", td.isoc_next, td.isoc_prev);
259*0Sstevel@tonic-gate mdb_printf(" isoc_pkt_index : %0x "
260*0Sstevel@tonic-gate "startingframe: %0x\n", td.isoc_pkt_index, td.starting_frame);
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gate if (td.link_ptr == NULL) {
264*0Sstevel@tonic-gate mdb_printf(" --> Link pointer = NULL\n");
265*0Sstevel@tonic-gate return (DCMD_ERR);
266*0Sstevel@tonic-gate } else {
267*0Sstevel@tonic-gate
268*0Sstevel@tonic-gate /* Inform user if link is to a TD or QH. */
269*0Sstevel@tonic-gate if (td.link_ptr & HC_END_OF_LIST) {
270*0Sstevel@tonic-gate mdb_printf(" "
271*0Sstevel@tonic-gate "--> Link pointer invalid (terminate bit set).\n");
272*0Sstevel@tonic-gate } else {
273*0Sstevel@tonic-gate if ((td.link_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD) {
274*0Sstevel@tonic-gate mdb_printf(" "
275*0Sstevel@tonic-gate "--> Link pointer points to a QH.\n");
276*0Sstevel@tonic-gate } else {
277*0Sstevel@tonic-gate mdb_printf(" "
278*0Sstevel@tonic-gate "--> Link pointer points to a TD.\n");
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate }
282*0Sstevel@tonic-gate
283*0Sstevel@tonic-gate return (DCMD_OK);
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate
286*0Sstevel@tonic-gate /*
287*0Sstevel@tonic-gate * Dump a UHCI QH (queue head).
288*0Sstevel@tonic-gate * -b walk/dump the chian of QHs starting with the one specified.
289*0Sstevel@tonic-gate * -d also dump the chain of TDs starting with the one specified.
290*0Sstevel@tonic-gate */
291*0Sstevel@tonic-gate int
uhci_qh(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)292*0Sstevel@tonic-gate uhci_qh(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
293*0Sstevel@tonic-gate {
294*0Sstevel@tonic-gate uint_t breadth_flag = FALSE, depth_flag = FALSE;
295*0Sstevel@tonic-gate uhci_state_t uhci_state, *uhcip = &uhci_state;
296*0Sstevel@tonic-gate queue_head_t qh;
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
300*0Sstevel@tonic-gate return (DCMD_USAGE);
301*0Sstevel@tonic-gate
302*0Sstevel@tonic-gate if (addr & ~QH_LINK_PTR_MASK) {
303*0Sstevel@tonic-gate mdb_warn("address must be on a 16-byte boundary.\n");
304*0Sstevel@tonic-gate return (DCMD_ERR);
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate if (mdb_getopts(argc, argv,
308*0Sstevel@tonic-gate 'b', MDB_OPT_SETBITS, TRUE, &breadth_flag,
309*0Sstevel@tonic-gate 'd', MDB_OPT_SETBITS, TRUE, &depth_flag,
310*0Sstevel@tonic-gate NULL) != argc) {
311*0Sstevel@tonic-gate return (DCMD_USAGE);
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate
314*0Sstevel@tonic-gate
315*0Sstevel@tonic-gate if (breadth_flag) {
316*0Sstevel@tonic-gate uint_t new_argc = 0;
317*0Sstevel@tonic-gate mdb_arg_t new_argv[1];
318*0Sstevel@tonic-gate
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate if (depth_flag) {
321*0Sstevel@tonic-gate new_argc = 1;
322*0Sstevel@tonic-gate new_argv[0].a_type = MDB_TYPE_STRING;
323*0Sstevel@tonic-gate new_argv[0].a_un.a_str = "-d";
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate if ((mdb_pwalk_dcmd("uhci_qh", "uhci_qh", new_argc, new_argv,
327*0Sstevel@tonic-gate addr)) != 0) {
328*0Sstevel@tonic-gate mdb_warn("failed to walk 'uhci_qh'");
329*0Sstevel@tonic-gate return (DCMD_ERR);
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate return (DCMD_OK);
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate if (find_uhci_statep((void *)addr, UHCI_QH, uhcip) != 1) {
336*0Sstevel@tonic-gate mdb_warn("failed to find uhci_statep");
337*0Sstevel@tonic-gate return (DCMD_ERR);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate
340*0Sstevel@tonic-gate
341*0Sstevel@tonic-gate if (mdb_vread(&qh, sizeof (qh), addr) != sizeof (qh)) {
342*0Sstevel@tonic-gate mdb_warn("failed to read qh at vaddr %p", addr);
343*0Sstevel@tonic-gate return (DCMD_ERR);
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gate mdb_printf("\n UHCI qh struct at (vaddr) %08x:\n", addr);
347*0Sstevel@tonic-gate
348*0Sstevel@tonic-gate if (!(qh.link_ptr & HC_END_OF_LIST) && qh.link_ptr != NULL) {
349*0Sstevel@tonic-gate mdb_printf(" link_ptr (paddr) : %08x "
350*0Sstevel@tonic-gate "(vaddr) : %p\n",
351*0Sstevel@tonic-gate qh.link_ptr,
352*0Sstevel@tonic-gate /* Note: uhcip needed by QH_VADDR macro */
353*0Sstevel@tonic-gate QH_VADDR(qh.link_ptr & QH_LINK_PTR_MASK));
354*0Sstevel@tonic-gate } else {
355*0Sstevel@tonic-gate mdb_printf(
356*0Sstevel@tonic-gate " link_ptr (paddr) : %08x\n",
357*0Sstevel@tonic-gate qh.link_ptr);
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate
360*0Sstevel@tonic-gate if (!(qh.element_ptr & HC_END_OF_LIST) && qh.element_ptr != NULL) {
361*0Sstevel@tonic-gate mdb_printf(" element_ptr (paddr) : %08x "
362*0Sstevel@tonic-gate "(vaddr) : %p\n",
363*0Sstevel@tonic-gate qh.element_ptr,
364*0Sstevel@tonic-gate /* Note: uhcip needed by TD_VADDR macro */
365*0Sstevel@tonic-gate TD_VADDR(qh.element_ptr & QH_LINK_PTR_MASK));
366*0Sstevel@tonic-gate } else {
367*0Sstevel@tonic-gate mdb_printf(
368*0Sstevel@tonic-gate " element_ptr (paddr) : %08x\n", qh.element_ptr);
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate
371*0Sstevel@tonic-gate mdb_printf(" node : %04x "
372*0Sstevel@tonic-gate "flag : %04x\n",
373*0Sstevel@tonic-gate qh.node, qh.qh_flag);
374*0Sstevel@tonic-gate mdb_printf(" prev_qh : %?p "
375*0Sstevel@tonic-gate "td_tailp : %?p\n",
376*0Sstevel@tonic-gate qh.prev_qh, qh.td_tailp);
377*0Sstevel@tonic-gate mdb_printf(" bulk_xfer_isoc_info : %?p\n", qh.bulk_xfer_info);
378*0Sstevel@tonic-gate
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate if (qh.link_ptr == NULL) {
381*0Sstevel@tonic-gate mdb_printf(" --> Link pointer = NULL\n");
382*0Sstevel@tonic-gate return (DCMD_ERR);
383*0Sstevel@tonic-gate } else {
384*0Sstevel@tonic-gate
385*0Sstevel@tonic-gate /* Inform user if next link is a TD or QH. */
386*0Sstevel@tonic-gate if (qh.link_ptr & HC_END_OF_LIST) {
387*0Sstevel@tonic-gate mdb_printf(" "
388*0Sstevel@tonic-gate "--> Link pointer invalid (terminate bit set).\n");
389*0Sstevel@tonic-gate } else {
390*0Sstevel@tonic-gate if ((qh.link_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD) {
391*0Sstevel@tonic-gate mdb_printf(" "
392*0Sstevel@tonic-gate "--> Link pointer points to a QH.\n");
393*0Sstevel@tonic-gate } else {
394*0Sstevel@tonic-gate /* Should never happen. */
395*0Sstevel@tonic-gate mdb_warn(" "
396*0Sstevel@tonic-gate "--> Link pointer points to a TD.\n");
397*0Sstevel@tonic-gate return (DCMD_ERR);
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate }
400*0Sstevel@tonic-gate }
401*0Sstevel@tonic-gate
402*0Sstevel@tonic-gate
403*0Sstevel@tonic-gate if (qh.element_ptr == NULL) {
404*0Sstevel@tonic-gate mdb_printf(" element_ptr = NULL\n");
405*0Sstevel@tonic-gate return (DCMD_ERR);
406*0Sstevel@tonic-gate } else {
407*0Sstevel@tonic-gate
408*0Sstevel@tonic-gate /* Inform user if next element is a TD or QH. */
409*0Sstevel@tonic-gate if (qh.element_ptr & HC_END_OF_LIST) {
410*0Sstevel@tonic-gate mdb_printf(" "
411*0Sstevel@tonic-gate "-->Element pointer invalid (terminate bit set)."
412*0Sstevel@tonic-gate "\n");
413*0Sstevel@tonic-gate return (DCMD_OK);
414*0Sstevel@tonic-gate } else {
415*0Sstevel@tonic-gate if ((qh.element_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD) {
416*0Sstevel@tonic-gate mdb_printf(" "
417*0Sstevel@tonic-gate "--> Element pointer points to a QH.\n");
418*0Sstevel@tonic-gate /* Should never happen in UHCI implementation */
419*0Sstevel@tonic-gate return (DCMD_ERR);
420*0Sstevel@tonic-gate } else {
421*0Sstevel@tonic-gate mdb_printf(" "
422*0Sstevel@tonic-gate "--> Element pointer points to a TD.\n");
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate }
426*0Sstevel@tonic-gate
427*0Sstevel@tonic-gate /*
428*0Sstevel@tonic-gate * If the user specified the -d (depth) option,
429*0Sstevel@tonic-gate * dump all TDs linked to this TD via the element_ptr.
430*0Sstevel@tonic-gate */
431*0Sstevel@tonic-gate if (depth_flag) {
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate /* Traverse and display all the TDs in the chain */
434*0Sstevel@tonic-gate if (mdb_pwalk_dcmd("uhci_td", "uhci_td", argc, argv,
435*0Sstevel@tonic-gate (uintptr_t)(TD_VADDR(qh.element_ptr &
436*0Sstevel@tonic-gate QH_LINK_PTR_MASK))) == -1) {
437*0Sstevel@tonic-gate mdb_warn("failed to walk 'uhci_td'");
438*0Sstevel@tonic-gate return (DCMD_ERR);
439*0Sstevel@tonic-gate }
440*0Sstevel@tonic-gate }
441*0Sstevel@tonic-gate
442*0Sstevel@tonic-gate return (DCMD_OK);
443*0Sstevel@tonic-gate }
444*0Sstevel@tonic-gate
445*0Sstevel@tonic-gate /*
446*0Sstevel@tonic-gate * Walk a list of UHCI Transaction Descriptors (td's).
447*0Sstevel@tonic-gate * Stop at the end of the list, or if the next element in the list is a
448*0Sstevel@tonic-gate * queue head (qh).
449*0Sstevel@tonic-gate * User must specify the address of the first td to look at.
450*0Sstevel@tonic-gate */
451*0Sstevel@tonic-gate int
uhci_td_walk_init(mdb_walk_state_t * wsp)452*0Sstevel@tonic-gate uhci_td_walk_init(mdb_walk_state_t *wsp)
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate if (wsp->walk_addr == NULL) {
455*0Sstevel@tonic-gate return (DCMD_USAGE);
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate
458*0Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (uhci_td_t), UM_SLEEP | UM_GC);
459*0Sstevel@tonic-gate wsp->walk_arg = mdb_alloc(sizeof (uhci_state_t), UM_SLEEP | UM_GC);
460*0Sstevel@tonic-gate
461*0Sstevel@tonic-gate
462*0Sstevel@tonic-gate /*
463*0Sstevel@tonic-gate * Read the uhci_state_t for the instance of uhci
464*0Sstevel@tonic-gate * using this td address into buf pointed to by walk_arg.
465*0Sstevel@tonic-gate */
466*0Sstevel@tonic-gate if (find_uhci_statep((void *)wsp->walk_addr, UHCI_TD,
467*0Sstevel@tonic-gate wsp->walk_arg) != 1) {
468*0Sstevel@tonic-gate mdb_warn("failed to find uhci_statep");
469*0Sstevel@tonic-gate return (WALK_ERR);
470*0Sstevel@tonic-gate }
471*0Sstevel@tonic-gate
472*0Sstevel@tonic-gate return (WALK_NEXT);
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate
475*0Sstevel@tonic-gate /*
476*0Sstevel@tonic-gate * At each step, read a TD into our private storage, and then invoke
477*0Sstevel@tonic-gate * the callback function. We terminate when we reach a QH, or
478*0Sstevel@tonic-gate * link_ptr is NULL.
479*0Sstevel@tonic-gate */
480*0Sstevel@tonic-gate int
uhci_td_walk_step(mdb_walk_state_t * wsp)481*0Sstevel@tonic-gate uhci_td_walk_step(mdb_walk_state_t *wsp)
482*0Sstevel@tonic-gate {
483*0Sstevel@tonic-gate int status;
484*0Sstevel@tonic-gate uhci_state_t *uhcip = (uhci_state_t *)wsp->walk_arg;
485*0Sstevel@tonic-gate
486*0Sstevel@tonic-gate
487*0Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (uhci_td_t), wsp->walk_addr)
488*0Sstevel@tonic-gate == -1) {
489*0Sstevel@tonic-gate mdb_warn("failed to read td at %p", wsp->walk_addr);
490*0Sstevel@tonic-gate return (WALK_DONE);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
494*0Sstevel@tonic-gate wsp->walk_cbdata);
495*0Sstevel@tonic-gate
496*0Sstevel@tonic-gate /* Next td. */
497*0Sstevel@tonic-gate wsp->walk_addr = ((uhci_td_t *)wsp->walk_data)->link_ptr;
498*0Sstevel@tonic-gate
499*0Sstevel@tonic-gate /* Check if we're at the last element */
500*0Sstevel@tonic-gate if (wsp->walk_addr == NULL || wsp->walk_addr & HC_END_OF_LIST)
501*0Sstevel@tonic-gate return (WALK_DONE);
502*0Sstevel@tonic-gate
503*0Sstevel@tonic-gate /* Make sure next element is a TD. If a QH, stop. */
504*0Sstevel@tonic-gate if (((((uhci_td_t *)wsp->walk_data)->link_ptr) & HC_QUEUE_HEAD)
505*0Sstevel@tonic-gate == HC_QUEUE_HEAD) {
506*0Sstevel@tonic-gate return (WALK_DONE);
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gate /* Strip terminate etc. bits. */
510*0Sstevel@tonic-gate wsp->walk_addr &= QH_LINK_PTR_MASK; /* there is no TD_LINK_PTR_MASK */
511*0Sstevel@tonic-gate
512*0Sstevel@tonic-gate if (wsp->walk_addr == NULL)
513*0Sstevel@tonic-gate return (WALK_DONE);
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate /*
516*0Sstevel@tonic-gate * Convert link_ptr paddr to vaddr
517*0Sstevel@tonic-gate * Note: uhcip needed by TD_VADDR macro
518*0Sstevel@tonic-gate */
519*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)TD_VADDR(wsp->walk_addr);
520*0Sstevel@tonic-gate
521*0Sstevel@tonic-gate return (status);
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate /*
525*0Sstevel@tonic-gate * Walk a list of UHCI Queue Heads (qh's).
526*0Sstevel@tonic-gate * Stop at the end of the list, or if the next element in the list is a
527*0Sstevel@tonic-gate * Transaction Descriptor (td).
528*0Sstevel@tonic-gate * User must specify the address of the first qh to look at.
529*0Sstevel@tonic-gate */
530*0Sstevel@tonic-gate int
uhci_qh_walk_init(mdb_walk_state_t * wsp)531*0Sstevel@tonic-gate uhci_qh_walk_init(mdb_walk_state_t *wsp)
532*0Sstevel@tonic-gate {
533*0Sstevel@tonic-gate if (wsp->walk_addr == NULL)
534*0Sstevel@tonic-gate return (DCMD_USAGE);
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (queue_head_t), UM_SLEEP | UM_GC);
537*0Sstevel@tonic-gate wsp->walk_arg = mdb_alloc(sizeof (uhci_state_t), UM_SLEEP | UM_GC);
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate
540*0Sstevel@tonic-gate /*
541*0Sstevel@tonic-gate * Read the uhci_state_t for the instance of uhci
542*0Sstevel@tonic-gate * using this td address into buf pointed to by walk_arg.
543*0Sstevel@tonic-gate */
544*0Sstevel@tonic-gate if (find_uhci_statep((void *)wsp->walk_addr, UHCI_QH,
545*0Sstevel@tonic-gate (uhci_state_t *)wsp->walk_arg) != 1) {
546*0Sstevel@tonic-gate mdb_warn("failed to find uhci_statep");
547*0Sstevel@tonic-gate return (WALK_ERR);
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate
550*0Sstevel@tonic-gate return (WALK_NEXT);
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate
553*0Sstevel@tonic-gate /*
554*0Sstevel@tonic-gate * At each step, read a QH into our private storage, and then invoke
555*0Sstevel@tonic-gate * the callback function. We terminate when we reach a QH, or
556*0Sstevel@tonic-gate * link_ptr is NULL.
557*0Sstevel@tonic-gate */
558*0Sstevel@tonic-gate int
uhci_qh_walk_step(mdb_walk_state_t * wsp)559*0Sstevel@tonic-gate uhci_qh_walk_step(mdb_walk_state_t *wsp)
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate int status;
562*0Sstevel@tonic-gate uhci_state_t *uhcip = (uhci_state_t *)wsp->walk_arg;
563*0Sstevel@tonic-gate
564*0Sstevel@tonic-gate
565*0Sstevel@tonic-gate if (wsp->walk_addr == NULL) /* Should never occur */
566*0Sstevel@tonic-gate return (WALK_DONE);
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (queue_head_t), wsp->walk_addr)
569*0Sstevel@tonic-gate == -1) {
570*0Sstevel@tonic-gate mdb_warn("failure reading qh at %p", wsp->walk_addr);
571*0Sstevel@tonic-gate return (WALK_DONE);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate
574*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
575*0Sstevel@tonic-gate wsp->walk_cbdata);
576*0Sstevel@tonic-gate
577*0Sstevel@tonic-gate /* Next QH. */
578*0Sstevel@tonic-gate wsp->walk_addr = ((queue_head_t *)wsp->walk_data)->link_ptr;
579*0Sstevel@tonic-gate
580*0Sstevel@tonic-gate
581*0Sstevel@tonic-gate /* Check if we're at the last element */
582*0Sstevel@tonic-gate if (wsp->walk_addr == NULL || wsp->walk_addr & HC_END_OF_LIST) {
583*0Sstevel@tonic-gate return (WALK_DONE);
584*0Sstevel@tonic-gate }
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate /* Make sure next element is a QH. If a TD, stop. */
587*0Sstevel@tonic-gate if (! ((((queue_head_t *)wsp->walk_data)->link_ptr) & HC_QUEUE_HEAD)
588*0Sstevel@tonic-gate == HC_QUEUE_HEAD) {
589*0Sstevel@tonic-gate return (WALK_DONE);
590*0Sstevel@tonic-gate }
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate /* Strip terminate etc. bits. */
593*0Sstevel@tonic-gate wsp->walk_addr &= QH_LINK_PTR_MASK;
594*0Sstevel@tonic-gate
595*0Sstevel@tonic-gate if (wsp->walk_addr == NULL)
596*0Sstevel@tonic-gate return (WALK_DONE);
597*0Sstevel@tonic-gate
598*0Sstevel@tonic-gate /*
599*0Sstevel@tonic-gate * Convert link_ptr paddr to vaddr
600*0Sstevel@tonic-gate * Note: uhcip needed by QH_VADDR macro
601*0Sstevel@tonic-gate */
602*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)QH_VADDR(wsp->walk_addr);
603*0Sstevel@tonic-gate
604*0Sstevel@tonic-gate return (status);
605*0Sstevel@tonic-gate }
606*0Sstevel@tonic-gate
607*0Sstevel@tonic-gate /*
608*0Sstevel@tonic-gate * MDB module linkage information:
609*0Sstevel@tonic-gate *
610*0Sstevel@tonic-gate * We declare a list of structures describing our dcmds, and a function
611*0Sstevel@tonic-gate * named _mdb_init to return a pointer to our module information.
612*0Sstevel@tonic-gate */
613*0Sstevel@tonic-gate
614*0Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
615*0Sstevel@tonic-gate { "uhci_td", ": [-d]", "print UHCI TD", uhci_td, NULL },
616*0Sstevel@tonic-gate { "uhci_qh", ": [-bd]", "print UHCI QH", uhci_qh, NULL},
617*0Sstevel@tonic-gate { NULL }
618*0Sstevel@tonic-gate };
619*0Sstevel@tonic-gate
620*0Sstevel@tonic-gate
621*0Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
622*0Sstevel@tonic-gate { "uhci_td", "walk list of UHCI TD structures",
623*0Sstevel@tonic-gate uhci_td_walk_init, uhci_td_walk_step, NULL,
624*0Sstevel@tonic-gate NULL },
625*0Sstevel@tonic-gate { "uhci_qh", "walk list of UHCI QH structures",
626*0Sstevel@tonic-gate uhci_qh_walk_init, uhci_qh_walk_step, NULL,
627*0Sstevel@tonic-gate NULL },
628*0Sstevel@tonic-gate { NULL }
629*0Sstevel@tonic-gate };
630*0Sstevel@tonic-gate
631*0Sstevel@tonic-gate static const mdb_modinfo_t modinfo = {
632*0Sstevel@tonic-gate MDB_API_VERSION, dcmds, walkers
633*0Sstevel@tonic-gate };
634*0Sstevel@tonic-gate
635*0Sstevel@tonic-gate
636*0Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)637*0Sstevel@tonic-gate _mdb_init(void)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate return (&modinfo);
640*0Sstevel@tonic-gate }
641