1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019, Joyent, Inc.
14  */
15 
16 /*
17  * PCIe related dcmds
18  */
19 
20 #include <mdb/mdb_modapi.h>
21 #include <sys/dditypes.h>
22 #include <sys/ddi_impldefs.h>
23 #include <sys/pcie_impl.h>
24 
25 boolean_t
26 pcie_bus_match(const struct dev_info *devi, uintptr_t *bus_p)
27 {
28 	if (devi->devi_bus.port_up.info.port.type == DEVI_PORT_TYPE_PCI) {
29 		*bus_p = (uintptr_t)devi->devi_bus.port_up.priv_p;
30 	} else if (devi->devi_bus.port_down.info.port.type ==
31 	    DEVI_PORT_TYPE_PCI) {
32 		*bus_p = (uintptr_t)devi->devi_bus.port_down.priv_p;
33 	} else {
34 		return (B_FALSE);
35 	}
36 
37 	return (B_TRUE);
38 }
39 
40 int
41 pcie_bus_walk_init(mdb_walk_state_t *wsp)
42 {
43 	if (wsp->walk_addr != 0) {
44 		mdb_warn("pcie_bus walker doesn't support non-global walks\n");
45 		return (WALK_ERR);
46 	}
47 
48 	if (mdb_layered_walk("devinfo", wsp) == -1) {
49 		mdb_warn("couldn't walk \"devinfo\"");
50 		return (WALK_ERR);
51 	}
52 
53 	return (WALK_NEXT);
54 }
55 
56 int
57 pcie_bus_walk_step(mdb_walk_state_t *wsp)
58 {
59 	const struct dev_info *devi;
60 	uintptr_t bus_addr;
61 	struct pcie_bus bus;
62 
63 	if (wsp->walk_layer == NULL) {
64 		mdb_warn("missing layered walk info\n");
65 		return (WALK_ERR);
66 	}
67 
68 	devi = wsp->walk_layer;
69 	if (!pcie_bus_match(devi, &bus_addr)) {
70 		return (WALK_NEXT);
71 	}
72 
73 	if (mdb_vread(&bus, sizeof (bus), bus_addr) == -1) {
74 		mdb_warn("failed to read pcie_bus_t at %p", bus_addr);
75 		return (WALK_NEXT);
76 	}
77 
78 	return (wsp->walk_callback(bus_addr, &bus, wsp->walk_cbdata));
79 }
80