1// Copyright 2016 The Fuchsia Authors
2// Copyright (c) 2016, Google, Inc. All rights reserved
3//
4// Use of this source code is governed by a MIT-style
5// license that can be found in the LICENSE file or at
6// https://opensource.org/licenses/MIT
7
8#include <ctype.h>
9#include <debug.h>
10#include <err.h>
11#include <inttypes.h>
12#include <lib/console.h>
13#include <string.h>
14
15#include <dev/pcie_bridge.h>
16#include <dev/pcie_bus_driver.h>
17#include <dev/pcie_device.h>
18#include <fbl/algorithm.h>
19#include <fbl/auto_lock.h>
20
21class PcieDebugConsole {
22public:
23    static int CmdLsPci(int argc, const cmd_args *argv, uint32_t flags);
24    static int CmdPciUnplug(int argc, const cmd_args *argv, uint32_t flags);
25    static int CmdPciReset(int argc, const cmd_args *argv, uint32_t flags);
26    static int CmdPciRescan(int argc, const cmd_args *argv, uint32_t flags);
27    static int CmdPciRegionDump(int argc, const cmd_args *argv, uint32_t flags);
28};
29
30/* Class code/Subclass code definitions taken from
31 * http://wiki.osdev.org/Pci#Class_Codes */
32typedef struct {
33    uint8_t class_code;
34    uint8_t subclass;
35    uint8_t prof_if_start;
36    uint8_t prof_if_end;
37    const char* desc;
38} pci_dev_type_lut_entry_t;
39
40typedef struct lspci_params {
41    bool verbose;
42    uint base_level;
43    uint indent_level;
44    uint bus_id;
45    uint dev_id;
46    uint func_id;
47    uint cfg_dump_amt;
48    bool force_dump_cfg;
49    uint found;
50} lspci_params_t;
51
52#define WILDCARD_ID (0xFFFFFFFF)
53
54#define LUT_ENTRY(_class, _subclass, _pif_start, _pif_end, _desc) { \
55    .class_code    = _class,                                        \
56    .subclass      = _subclass,                                     \
57    .prof_if_start = _pif_start,                                    \
58    .prof_if_end   = _pif_end,                                      \
59    .desc          = _desc,                                         \
60}
61
62#define LUT_ENTRY_ONE_PIF(_class, _subclass, _pif, _desc) \
63    LUT_ENTRY(_class, _subclass, _pif, _pif, _desc)
64
65#define LUT_ENTRY_ALL_PIF(_class, _subclass, _desc) \
66    LUT_ENTRY(_class, _subclass, 0x00, 0xFF, _desc)
67
68static const pci_dev_type_lut_entry_t PCI_DEV_TYPE_LUT[] = {
69    LUT_ENTRY_ONE_PIF(0x00, 0x00, 0x00, "Any device except for VGA-Compatible devices"),
70    LUT_ENTRY_ONE_PIF(0x00, 0x01, 0x00, "VGA-Compatible Device"),
71    LUT_ENTRY_ONE_PIF(0x01, 0x00, 0x00, "SCSI Bus Controller"),
72    LUT_ENTRY_ALL_PIF(0x01, 0x01,       "IDE Controller"),
73    LUT_ENTRY_ONE_PIF(0x01, 0x02, 0x00, "Floppy Disk Controller"),
74    LUT_ENTRY_ONE_PIF(0x01, 0x03, 0x00, "IPI Bus Controller"),
75    LUT_ENTRY_ONE_PIF(0x01, 0x04, 0x00, "RAID Controller"),
76    LUT_ENTRY_ONE_PIF(0x01, 0x05, 0x20, "ATA Controller (Single DMA)"),
77    LUT_ENTRY_ONE_PIF(0x01, 0x05, 0x30, "ATA Controller (Chained DMA)"),
78    LUT_ENTRY_ONE_PIF(0x01, 0x06, 0x00, "Serial ATA (Vendor Specific Interface)"),
79    LUT_ENTRY_ONE_PIF(0x01, 0x06, 0x01, "Serial ATA (AHCI 1.0)"),
80    LUT_ENTRY_ONE_PIF(0x01, 0x07, 0x00, "Serial Attached SCSI (SAS)"),
81    LUT_ENTRY_ONE_PIF(0x01, 0x08, 0x01, "Non-Volatile Memory Controller (NVMHCI)"),
82    LUT_ENTRY_ONE_PIF(0x01, 0x08, 0x02, "Non-Volatile Memory Controller (NVM Express)"),
83    LUT_ENTRY_ONE_PIF(0x01, 0x80, 0x00, "Other Mass Storage Controller"),
84    LUT_ENTRY_ONE_PIF(0x02, 0x00, 0x00, "Ethernet Controller"),
85    LUT_ENTRY_ONE_PIF(0x02, 0x01, 0x00, "Token Ring Controller"),
86    LUT_ENTRY_ONE_PIF(0x02, 0x02, 0x00, "FDDI Controller"),
87    LUT_ENTRY_ONE_PIF(0x02, 0x03, 0x00, "ATM Controller"),
88    LUT_ENTRY_ONE_PIF(0x02, 0x04, 0x00, "ISDN Controller"),
89    LUT_ENTRY_ONE_PIF(0x02, 0x05, 0x00, "WorldFip Controller"),
90    LUT_ENTRY_ALL_PIF(0x02, 0x06,       "PICMG 2.14 Multi Computing"),
91    LUT_ENTRY_ONE_PIF(0x02, 0x80, 0x00, "Other Network Controller"),
92    LUT_ENTRY_ONE_PIF(0x03, 0x00, 0x00, "VGA-Compatible Controller"),
93    LUT_ENTRY_ONE_PIF(0x03, 0x00, 0x01, "8512-Compatible Controller"),
94    LUT_ENTRY_ONE_PIF(0x03, 0x01, 0x00, "XGA Controller"),
95    LUT_ENTRY_ONE_PIF(0x03, 0x02, 0x00, "3D Controller (Not VGA-Compatible)"),
96    LUT_ENTRY_ONE_PIF(0x03, 0x80, 0x00, "Other Display Controller"),
97    LUT_ENTRY_ONE_PIF(0x04, 0x00, 0x00, "Video Device"),
98    LUT_ENTRY_ONE_PIF(0x04, 0x01, 0x00, "Audio Device"),
99    LUT_ENTRY_ONE_PIF(0x04, 0x02, 0x00, "Computer Telephony Device"),
100    LUT_ENTRY_ONE_PIF(0x04, 0x80, 0x00, "Other Multimedia Device"),
101    LUT_ENTRY_ONE_PIF(0x05, 0x00, 0x00, "RAM Controller"),
102    LUT_ENTRY_ONE_PIF(0x05, 0x01, 0x00, "Flash Controller"),
103    LUT_ENTRY_ONE_PIF(0x05, 0x80, 0x00, "Other Memory Controller"),
104    LUT_ENTRY_ONE_PIF(0x06, 0x00, 0x00, "Host Bridge"),
105    LUT_ENTRY_ONE_PIF(0x06, 0x01, 0x00, "ISA Bridge"),
106    LUT_ENTRY_ONE_PIF(0x06, 0x02, 0x00, "EISA Bridge"),
107    LUT_ENTRY_ONE_PIF(0x06, 0x03, 0x00, "MCA Bridge"),
108    LUT_ENTRY_ONE_PIF(0x06, 0x04, 0x00, "PCI-to-PCI Bridge"),
109    LUT_ENTRY_ONE_PIF(0x06, 0x04, 0x01, "PCI-to-PCI Bridge (Subtractive Decode)"),
110    LUT_ENTRY_ONE_PIF(0x06, 0x05, 0x00, "PCMCIA Bridge"),
111    LUT_ENTRY_ONE_PIF(0x06, 0x06, 0x00, "NuBus Bridge"),
112    LUT_ENTRY_ONE_PIF(0x06, 0x07, 0x00, "CardBus Bridge"),
113    LUT_ENTRY_ALL_PIF(0x06, 0x08,       "RACEway Bridge"),
114    LUT_ENTRY_ONE_PIF(0x06, 0x09, 0x40, "PCI-to-PCI Bridge (Semi-Transparent, Primary)"),
115    LUT_ENTRY_ONE_PIF(0x06, 0x09, 0x80, "PCI-to-PCI Bridge (Semi-Transparent, Secondary)"),
116    LUT_ENTRY_ONE_PIF(0x06, 0x0A, 0x00, "InfiniBrand-to-PCI Host Bridge"),
117    LUT_ENTRY_ONE_PIF(0x06, 0x80, 0x00, "Other Bridge Device"),
118    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x00, "Generic XT-Compatible Serial Controller"),
119    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x01, "16450-Compatible Serial Controller"),
120    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x02, "16550-Compatible Serial Controller"),
121    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x03, "16650-Compatible Serial Controller"),
122    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x04, "16750-Compatible Serial Controller"),
123    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x05, "16850-Compatible Serial Controller"),
124    LUT_ENTRY_ONE_PIF(0x07, 0x00, 0x06, "16950-Compatible Serial Controller"),
125    LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x00, "Parallel Port"),
126    LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x01, "Bi-Directional Parallel Port"),
127    LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x02, "ECP 1.X Compliant Parallel Port"),
128    LUT_ENTRY_ONE_PIF(0x07, 0x01, 0x03, "IEEE 1284 Controller"),
129    LUT_ENTRY_ONE_PIF(0x07, 0x01, 0xFE, "IEEE 1284 Target Device"),
130    LUT_ENTRY_ONE_PIF(0x07, 0x02, 0x00, "Multiport Serial Controller"),
131    LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x00, "Generic Modem"),
132    LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x01, "Hayes Compatible Modem (16450-Compatible Interface)"),
133    LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x02, "Hayes Compatible Modem (16550-Compatible Interface)"),
134    LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x03, "Hayes Compatible Modem (16650-Compatible Interface)"),
135    LUT_ENTRY_ONE_PIF(0x07, 0x03, 0x04, "Hayes Compatible Modem (16750-Compatible Interface)"),
136    LUT_ENTRY_ONE_PIF(0x07, 0x04, 0x00, "IEEE 488.1/2 (GPIB) Controller"),
137    LUT_ENTRY_ONE_PIF(0x07, 0x05, 0x00, "Smart Card"),
138    LUT_ENTRY_ONE_PIF(0x07, 0x80, 0x00, "Other Communications Device"),
139    LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x00, "Generic 8259 PIC"),
140    LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x01, "ISA PIC"),
141    LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x02, "EISA PIC"),
142    LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x10, "I/O APIC Interrupt Controller"),
143    LUT_ENTRY_ONE_PIF(0x08, 0x00, 0x20, "I/O(x) APIC Interrupt Controller"),
144    LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x00, "Generic 8237 DMA Controller"),
145    LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x01, "ISA DMA Controller"),
146    LUT_ENTRY_ONE_PIF(0x08, 0x01, 0x02, "EISA DMA Controller"),
147    LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x00, "Generic 8254 System Timer"),
148    LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x01, "ISA System Timer"),
149    LUT_ENTRY_ONE_PIF(0x08, 0x02, 0x02, "EISA System Timer"),
150    LUT_ENTRY_ONE_PIF(0x08, 0x03, 0x00, "Generic RTC Controller"),
151    LUT_ENTRY_ONE_PIF(0x08, 0x03, 0x01, "ISA RTC Controller"),
152    LUT_ENTRY_ONE_PIF(0x08, 0x04, 0x00, "Generic PCI Hot-Plug Controller"),
153    LUT_ENTRY_ONE_PIF(0x08, 0x80, 0x00, "Other System Peripheral"),
154    LUT_ENTRY_ONE_PIF(0x09, 0x00, 0x00, "Keyboard Controller"),
155    LUT_ENTRY_ONE_PIF(0x09, 0x01, 0x00, "Digitizer"),
156    LUT_ENTRY_ONE_PIF(0x09, 0x02, 0x00, "Mouse Controller"),
157    LUT_ENTRY_ONE_PIF(0x09, 0x03, 0x00, "Scanner Controller"),
158    LUT_ENTRY_ONE_PIF(0x09, 0x04, 0x00, "Gameport Controller (Generic)"),
159    LUT_ENTRY_ONE_PIF(0x09, 0x04, 0x10, "Gameport Contrlller (Legacy)"),
160    LUT_ENTRY_ONE_PIF(0x09, 0x80, 0x00, "Other Input Controller"),
161    LUT_ENTRY_ONE_PIF(0x0a, 0x00, 0x00, "Generic Docking Station"),
162    LUT_ENTRY_ONE_PIF(0x0a, 0x80, 0x00, "Other Docking Station"),
163    LUT_ENTRY_ONE_PIF(0x0b, 0x00, 0x00, "386 Processor"),
164    LUT_ENTRY_ONE_PIF(0x0b, 0x01, 0x00, "486 Processor"),
165    LUT_ENTRY_ONE_PIF(0x0b, 0x02, 0x00, "Pentium Processor"),
166    LUT_ENTRY_ONE_PIF(0x0b, 0x10, 0x00, "Alpha Processor"),
167    LUT_ENTRY_ONE_PIF(0x0b, 0x20, 0x00, "PowerPC Processor"),
168    LUT_ENTRY_ONE_PIF(0x0b, 0x30, 0x00, "MIPS Processor"),
169    LUT_ENTRY_ONE_PIF(0x0b, 0x40, 0x00, "Co-Processor"),
170    LUT_ENTRY_ONE_PIF(0x0c, 0x00, 0x00, "IEEE 1394 Controller (FireWire)"),
171    LUT_ENTRY_ONE_PIF(0x0c, 0x00, 0x10, "IEEE 1394 Controller (1394 OpenHCI Spec)"),
172    LUT_ENTRY_ONE_PIF(0x0c, 0x01, 0x00, "ACCESS.bus"),
173    LUT_ENTRY_ONE_PIF(0x0c, 0x02, 0x00, "SSA"),
174    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x00, "USB (Universal Host Controller Spec)"),
175    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x10, "USB (Open Host Controller Spec)"),
176    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x20, "USB2 Host Controller (Intel EHCI)"),
177    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x30, "USB3 XHCI Controller"),
178    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0x80, "Unspecified USB Controller"),
179    LUT_ENTRY_ONE_PIF(0x0c, 0x03, 0xFE, "USB (Not Host Controller)"),
180    LUT_ENTRY_ONE_PIF(0x0c, 0x04, 0x00, "Fibre Channel"),
181    LUT_ENTRY_ONE_PIF(0x0c, 0x05, 0x00, "SMBus"),
182    LUT_ENTRY_ONE_PIF(0x0c, 0x06, 0x00, "InfiniBand"),
183    LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x00, "IPMI SMIC Interface"),
184    LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x01, "IPMI Kybd Controller Style Interface"),
185    LUT_ENTRY_ONE_PIF(0x0c, 0x07, 0x02, "IPMI Block Transfer Interface"),
186    LUT_ENTRY_ONE_PIF(0x0c, 0x08, 0x00, "SERCOS Interface Standard (IEC 61491)"),
187    LUT_ENTRY_ONE_PIF(0x0c, 0x09, 0x00, "CANbus"),
188    LUT_ENTRY_ONE_PIF(0x0d, 0x00, 0x00, "iRDA Compatible Controller"),
189    LUT_ENTRY_ONE_PIF(0x0d, 0x01, 0x00, "Consumer IR Controller"),
190    LUT_ENTRY_ONE_PIF(0x0d, 0x10, 0x00, "RF Controller"),
191    LUT_ENTRY_ONE_PIF(0x0d, 0x11, 0x00, "Bluetooth Controller"),
192    LUT_ENTRY_ONE_PIF(0x0d, 0x12, 0x00, "Broadband Controller"),
193    LUT_ENTRY_ONE_PIF(0x0d, 0x20, 0x00, "Ethernet Controller (802.11a)"),
194    LUT_ENTRY_ONE_PIF(0x0d, 0x21, 0x00, "Ethernet Controller (802.11b)"),
195    LUT_ENTRY_ONE_PIF(0x0d, 0x80, 0x00, "Other Wireless Controller"),
196    LUT_ENTRY        (0x0e, 0x00, 0x01, 0xFF, "I20 Architecture"),
197    LUT_ENTRY_ONE_PIF(0x0e, 0x00, 0x00, "Message FIFO"),
198    LUT_ENTRY_ONE_PIF(0x0f, 0x01, 0x00, "TV Controller"),
199    LUT_ENTRY_ONE_PIF(0x0f, 0x02, 0x00, "Audio Controller"),
200    LUT_ENTRY_ONE_PIF(0x0f, 0x03, 0x00, "Voice Controller"),
201    LUT_ENTRY_ONE_PIF(0x0f, 0x04, 0x00, "Data Controller"),
202    LUT_ENTRY_ONE_PIF(0x10, 0x00, 0x00, "Network and Computing Encrpytion/Decryption"),
203    LUT_ENTRY_ONE_PIF(0x10, 0x10, 0x00, "Entertainment Encryption/Decryption"),
204    LUT_ENTRY_ONE_PIF(0x10, 0x80, 0x00, "Other Encryption/Decryption"),
205    LUT_ENTRY_ONE_PIF(0x11, 0x00, 0x00, "DPIO Modules"),
206    LUT_ENTRY_ONE_PIF(0x11, 0x01, 0x00, "Performance Counters"),
207    LUT_ENTRY_ONE_PIF(0x11, 0x10, 0x00, "Communications Syncrhonization"),
208    LUT_ENTRY_ONE_PIF(0x11, 0x20, 0x00, "Management Card"),
209    LUT_ENTRY_ONE_PIF(0x11, 0x80, 0x00, "Other Data Acquisition/Signal Processing Controller"),
210};
211
212#undef LUT_ENTRY
213#undef LUT_ENTRY_ONE_PIF
214#undef LUT_ENTRY_ALL_PIF
215
216static const char* pci_class_code_to_string(uint8_t class_code)
217{
218    switch (class_code) {
219        case 0x00: return "Pre-Class Code Device";
220        case 0x01: return "Mass Storage Controller";
221        case 0x02: return "Network Controller";
222        case 0x03: return "Display Controller";
223        case 0x04: return "Multimedia Controller";
224        case 0x05: return "Memory Controller";
225        case 0x06: return "Bridge Device";
226        case 0x07: return "Simple Communication Controller";
227        case 0x08: return "Base System Peripheral";
228        case 0x09: return "Input Device";
229        case 0x0A: return "Docking Station";
230        case 0x0B: return "Processor";
231        case 0x0C: return "Serial Bus Controller";
232        case 0x0D: return "Wireless Controller";
233        case 0x0E: return "Intelligent I/O Controller";
234        case 0x0F: return "Satellite Communication Controller";
235        case 0x10: return "Encryption/Decryption Controller";
236        case 0x11: return "Data Acquisition or Signal Processing Controller";
237        case 0xFF: return "Vendor";
238        default:   return "<Unknown>";
239    }
240}
241
242static const char* pci_device_type(const PcieDevice& dev)
243{
244    // TODO(johngro): It might be a good idea, some day, to make this something
245    // better than an O(n) search.
246
247    // If this is a PCIe style bridge with a specific device type spelled out in
248    // its PCI Express Capabilities structure, use that to provide the type
249    // string.
250    switch (dev.pcie_device_type()) {
251        case PCIE_DEVTYPE_RC_ROOT_PORT:           return "PCIe Root Port";
252        case PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT:   return "PCIe Upstream Switch Port";
253        case PCIE_DEVTYPE_SWITCH_DOWNSTREAM_PORT: return "PCIe Downstream Switch Port";
254        case PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE:     return "PCIe-to-PCI Bridge";
255        case PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE:     return "PCI-to-PCIe Bridge";
256        default: break;
257    }
258
259    for (size_t i = 0; i < fbl::count_of(PCI_DEV_TYPE_LUT); ++i) {
260        const pci_dev_type_lut_entry_t* entry = PCI_DEV_TYPE_LUT + i;
261
262        if ((dev.class_id() == entry->class_code)    &&
263            (dev.subclass() == entry->subclass)      &&
264            (dev.prog_if()  >= entry->prof_if_start) &&
265            (dev.prog_if()  <= entry->prof_if_end))
266            return entry->desc;
267    }
268
269    return pci_class_code_to_string(dev.class_id());
270}
271
272static void do_lspci_indent(uint level) {
273    while (level--)
274        printf("  ");
275}
276#define LSPCI_PRINTF(_fmt, ...)                \
277    do {                                       \
278        do_lspci_indent(params->indent_level); \
279        printf(_fmt, ##__VA_ARGS__);           \
280    } while (0)
281
282
283static void dump_pcie_hdr(const PcieDevice& dev, lspci_params_t* params)
284{
285    DEBUG_ASSERT(params);
286    LSPCI_PRINTF("[%02x:%02x.%01x] - VID 0x%04x DID 0x%04x :: %s",
287                 dev.bus_id(), dev.dev_id(), dev.func_id(),
288                 dev.vendor_id(), dev.device_id(),
289                 pci_device_type(dev));
290
291    if (dev.disabled())
292        printf(" [DISABLED]");
293
294    printf("\n");
295}
296
297static void dump_pcie_bars(const PcieDevice& dev,
298                           lspci_params_t* params)
299{
300    auto cfg = dev.config();
301
302    DEBUG_ASSERT(dev.bar_count() <= PCIE_MAX_BAR_REGS);
303    for (uint i = 0; i < dev.bar_count(); ++i) {
304        LSPCI_PRINTF("Base Addr[%u]      : 0x%08x", i, cfg->Read(PciConfig::kBAR(i)));
305
306        const pcie_bar_info_t* info = dev.GetBarInfo(i);
307        if (info == nullptr) {
308            printf("\n");
309            continue;
310        }
311
312        printf(" :: paddr %#" PRIx64 " size %#" PRIx64 "%s%s %s%s\n",
313                info->bus_addr,
314                info->size,
315                info->is_prefetchable ? " prefetchable" : "",
316                info->is_mmio ? (info->is_64bit ? " 64-bit" : " 32-bit") : "",
317                info->is_mmio ? "MMIO" : "PIO",
318                info->allocation == nullptr ? "" : " (allocated)");
319    }
320}
321
322static void dump_pcie_common(const PcieDevice& dev, lspci_params_t* params)
323{
324    auto cfg = dev.config();
325    uint8_t base_class = cfg->Read(PciConfig::kBaseClass);
326
327    LSPCI_PRINTF("Command           : 0x%04x\n",    cfg->Read(PciConfig::kCommand));
328    LSPCI_PRINTF("Status            : 0x%04x\n",    cfg->Read(PciConfig::kStatus));
329    LSPCI_PRINTF("Rev ID            : 0x%02x\n",    cfg->Read(PciConfig::kRevisionId));
330    LSPCI_PRINTF("Prog Iface        : 0x%02x\n",    cfg->Read(PciConfig::kProgramInterface));
331    LSPCI_PRINTF("Sub Class         : 0x%02x\n",    cfg->Read(PciConfig::kSubClass));
332    LSPCI_PRINTF("Base Class        : 0x%02x %s\n", base_class,
333                                                    pci_class_code_to_string(base_class));
334    LSPCI_PRINTF("Cache Line Sz     : 0x%02x\n",    cfg->Read(PciConfig::kCacheLineSize));
335    LSPCI_PRINTF("Latency Timer     : 0x%02x\n",    cfg->Read(PciConfig::kLatencyTimer));
336    LSPCI_PRINTF("Header Type       : 0x%02x\n",    cfg->Read(PciConfig::kHeaderType));
337    LSPCI_PRINTF("BIST              : 0x%02x\n",    cfg->Read(PciConfig::kBist));
338}
339
340static void dump_pcie_standard(const PcieDevice& dev, lspci_params_t* params)
341{
342    auto cfg = dev.config();
343    LSPCI_PRINTF("Cardbus CIS       : 0x%08x\n", cfg->Read(PciConfig::kCardbusCisPtr));
344    LSPCI_PRINTF("Subsystem VID     : 0x%04x\n", cfg->Read(PciConfig::kSubsystemVendorId));
345    LSPCI_PRINTF("Subsystem ID      : 0x%04x\n", cfg->Read(PciConfig::kSubsystemId));
346    LSPCI_PRINTF("Exp ROM addr      : 0x%08x\n", cfg->Read(PciConfig::kExpansionRomAddress));
347    LSPCI_PRINTF("Cap Ptr           : 0x%02x\n", cfg->Read(PciConfig::kCapabilitiesPtr));
348    LSPCI_PRINTF("IRQ line          : 0x%02x\n", cfg->Read(PciConfig::kInterruptLine));
349    LSPCI_PRINTF("IRQ pin           : 0x%02x\n", cfg->Read(PciConfig::kInterruptPin));
350    LSPCI_PRINTF("Min Grant         : 0x%02x\n", cfg->Read(PciConfig::kMinGrant));
351    LSPCI_PRINTF("Max Latency       : 0x%02x\n", cfg->Read(PciConfig::kMaxLatency));
352}
353
354static void dump_pcie_bridge(const PcieBridge& bridge, lspci_params_t* params)
355{
356    auto cfg = bridge.config();
357
358    LSPCI_PRINTF("P. Bus ID         : 0x%02x\n", cfg->Read(PciConfig::kPrimaryBusId));
359    LSPCI_PRINTF("S. Bus Range      : [0x%02x, 0x%02x]\n",
360                                                 cfg->Read(PciConfig::kSecondaryBusId),
361                                                 cfg->Read(PciConfig::kSubordinateBusId));
362    LSPCI_PRINTF("S. Latency Timer  : 0x%02x\n", cfg->Read(PciConfig::kSecondaryLatencyTimer));
363    LSPCI_PRINTF("IO Base           : 0x%02x\n", cfg->Read(PciConfig::kIoBase));
364    LSPCI_PRINTF("IO Base Upper     : 0x%04x\n", cfg->Read(PciConfig::kIoBaseUpper));
365    LSPCI_PRINTF("IO Limit          : 0x%02x\n", cfg->Read(PciConfig::kIoLimit));
366    LSPCI_PRINTF("IO Limit Upper    : 0x%04x",   cfg->Read(PciConfig::kIoLimitUpper));
367    if (bridge.io_base() < bridge.io_limit()) {
368        printf(" :: [0x%08x, 0x%08x]\n", bridge.io_base(), bridge.io_limit());
369    } else {
370        printf("\n");
371    }
372    LSPCI_PRINTF("Secondary Status  : 0x%04x\n", cfg->Read(PciConfig::kSecondaryStatus));
373    LSPCI_PRINTF("Memory Limit      : 0x%04x\n", cfg->Read(PciConfig::kMemoryLimit));
374    LSPCI_PRINTF("Memory Base       : 0x%04x", cfg->Read(PciConfig::kMemoryBase));
375    if (bridge.mem_base() < bridge.mem_limit()) {
376        printf(" :: [0x%08x, 0x%08x]\n", bridge.mem_base(), bridge.mem_limit());
377    } else {
378        printf("\n");
379    }
380    LSPCI_PRINTF("PFMem Base        : 0x%04x\n", cfg->Read(PciConfig::kPrefetchableMemoryBase));
381    LSPCI_PRINTF("PFMem Base Upper  : 0x%08x\n", cfg->Read(PciConfig::kPrefetchableMemoryBaseUpper));
382    LSPCI_PRINTF("PFMem Limit       : 0x%04x\n", cfg->Read(PciConfig::kPrefetchableMemoryLimit));
383    LSPCI_PRINTF("PFMem Limit Upper : 0x%08x", cfg->Read(PciConfig::kPrefetchableMemoryLimitUpper));
384    if (bridge.pf_mem_base() < bridge.pf_mem_limit()) {
385        printf(" :: [0x%016" PRIx64 ", 0x%016" PRIx64"]\n",
386                bridge.pf_mem_base(), bridge.pf_mem_limit());
387    } else {
388        printf("\n");
389    }
390
391    LSPCI_PRINTF("Capabilities Ptr  : 0x%02x\n", cfg->Read(PciConfig::kCapabilitiesPtr));
392    LSPCI_PRINTF("Exp ROM Address   : 0x%08x\n", cfg->Read(PciConfig::kExpansionRomAddress));
393    LSPCI_PRINTF("Interrupt Line    : 0x%02x\n", cfg->Read(PciConfig::kInterruptLine));
394    LSPCI_PRINTF("Interrupt Pin     : 0x%02x\n", cfg->Read(PciConfig::kInterruptPin));
395    LSPCI_PRINTF("Bridge Control    : 0x%04x\n", cfg->Read(PciConfig::kBridgeControl));
396}
397
398static void dump_pcie_raw_config(uint amt, const PciConfig* cfg)
399{
400    DEBUG_ASSERT(amt == PCIE_BASE_CONFIG_SIZE || amt == PCIE_EXTENDED_CONFIG_SIZE);
401    cfg->DumpConfig(static_cast<uint16_t>(amt & 0xFFFF));
402}
403
404#define CAP_TBL_ENTRY(s) (s, #s)
405static struct _cap_tbl {
406    uint8_t id;
407    const char *label;
408} cap_tbl[] = {
409    { PCIE_CAP_ID_PCI_PWR_MGMT, "PCI_PWR_MGMT" },
410    { PCIE_CAP_ID_AGP, "AGP" },
411    { PCIE_CAP_ID_VPD, "VPD" },
412    { PCIE_CAP_ID_MSI, "MSI" },
413    { PCIE_CAP_ID_PCIX, "PCIX" },
414    { PCIE_CAP_ID_HYPERTRANSPORT, "HYPERTRANSPORT" },
415    { PCIE_CAP_ID_VENDOR, "VENDOR" },
416    { PCIE_CAP_ID_DEBUG_PORT, "DEBUG_PORT" },
417    { PCIE_CAP_ID_COMPACTPCI_CRC, "COMPACTPCI_CRC" },
418    { PCIE_CAP_ID_PCI_HOTPLUG, "PCI_HOTPLUG" },
419    { PCIE_CAP_ID_PCI_BRIDGE_SUBSYSTEM_VID, "PCI_BRIDGE_SUBSYSTEM_VID" },
420    { PCIE_CAP_ID_AGP_8X, "AGP_8X" },
421    { PCIE_CAP_ID_SECURE_DEVICE, "SECURE_DEVICE" },
422    { PCIE_CAP_ID_PCI_EXPRESS, "PCI_EXPRESS" },
423    { PCIE_CAP_ID_MSIX, "MSIX" },
424    { PCIE_CAP_ID_SATA_DATA_NDX_CFG, "SATA_DATA_NDX_CFG" },
425    { PCIE_CAP_ID_ADVANCED_FEATURES, "ADVANCED_FEATURES" },
426    { PCIE_CAP_ID_ENHANCED_ALLOCATION, "ENHANCED_ALLOCATION" },
427};
428#undef CAP_TABLE_ENTRY
429
430static inline const char* get_cap_str(uint8_t id) {
431    for (const auto& cur : cap_tbl) {
432        if (cur.id == id) {
433            return cur.label;
434        }
435    }
436
437    return "<Unknown>";
438}
439
440static void dump_pcie_capabilities(fbl::RefPtr<PcieDevice> dev, void *ctx)
441{
442    bool is_first = true;
443    lspci_params_t* params = static_cast<lspci_params_t*>(ctx);
444    auto initial_indent = params->indent_level;
445    params->indent_level += 2;
446
447    if (!dev->capabilities().is_empty()) {
448        LSPCI_PRINTF("Std Capabilities  :");
449        for (const auto& cap : dev->capabilities()) {
450            if (is_first) {
451                printf(" %s (%#02x)\n", get_cap_str(cap.id()), cap.id());
452                is_first = false;
453                params->indent_level += 10;
454            } else {
455                LSPCI_PRINTF("%s (%#02x)\n", get_cap_str(cap.id()), cap.id());
456            }
457        }
458    }
459
460    params->indent_level = initial_indent;
461}
462
463static bool dump_pcie_device(const fbl::RefPtr<PcieDevice>& dev, void* ctx, uint level)
464{
465    DEBUG_ASSERT(dev && ctx);
466    lspci_params_t* params = (lspci_params_t*)ctx;
467    bool match;
468    auto cfg = dev->config();
469
470    /* Grab the device's lock so it cannot be unplugged out from under us while
471     * we print details. */
472    fbl::AutoLock lock(dev->dev_lock());
473
474    /* If the device has already been unplugged, just skip it */
475    if (!dev->plugged_in())
476        return true;
477
478    match = (((params->bus_id  == WILDCARD_ID) || (params->bus_id  == dev->bus_id())) &&
479             ((params->dev_id  == WILDCARD_ID) || (params->dev_id  == dev->dev_id())) &&
480             ((params->func_id == WILDCARD_ID) || (params->func_id == dev->func_id())));
481    if (!match)
482        return true;
483
484    if (!params->found && (params->bus_id != WILDCARD_ID)) {
485        params->base_level = level;
486    } else {
487        DEBUG_ASSERT(!params->base_level);
488    }
489
490    params->found++;
491
492    DEBUG_ASSERT(level >= params->base_level);
493    params->indent_level = params->verbose ? 0 : level - params->base_level;
494
495    /* Dump the header */
496    dump_pcie_hdr(*dev, params);
497
498    /* Only dump details if we are in verbose mode and this device matches our
499     * filter */
500    if (params->verbose) {
501        params->indent_level += 2;
502
503        dump_pcie_common(*dev, params);
504        dump_pcie_bars(*dev, params);
505
506        uint8_t header_type = cfg->Read(PciConfig::kHeaderType) & PCI_HEADER_TYPE_MASK;
507        switch (header_type) {
508        case PCI_HEADER_TYPE_STANDARD:
509            dump_pcie_standard(*dev, params);
510            break;
511
512        case PCI_HEADER_TYPE_PCI_BRIDGE: {
513            if (dev->is_bridge()) {
514                dump_pcie_bridge(*static_cast<PcieBridge*>(dev.get()), params);
515            } else {
516                printf("ERROR! Type 1 header detected for non-bridge device!\n");
517            }
518        } break;
519
520        case PCI_HEADER_TYPE_CARD_BUS:
521            printf("TODO : Implemnt CardBus Config header register dump\n");
522            break;
523
524        default:
525            printf("Unknown Header Type (0x%02x)\n", header_type);
526            break;
527        }
528
529        params->indent_level -= 2;
530        dump_pcie_capabilities(dev, params);
531    }
532
533    if (params->cfg_dump_amt)
534        dump_pcie_raw_config(params->cfg_dump_amt, dev->config());
535
536    return true;
537}
538
539int PcieDebugConsole::CmdLsPci(int argc, const cmd_args *argv, uint32_t flags) {
540    lspci_params_t params;
541    uint filter_ndx = 0;
542
543    memset(&params, 0, sizeof(params));
544    params.bus_id  = WILDCARD_ID;
545    params.dev_id  = WILDCARD_ID;
546    params.func_id = WILDCARD_ID;
547
548    for (int i = 1; i < argc; ++i) {
549        bool confused = false;
550
551        if (argv[i].str[0] == '-') {
552            const char* c = argv[i].str + 1;
553            if (!(*c))
554                confused = true;
555
556            while (!confused && *c) {
557                switch (*c) {
558                    case 'f':
559                        if (params.cfg_dump_amt < PCIE_BASE_CONFIG_SIZE)
560                            params.cfg_dump_amt = PCIE_BASE_CONFIG_SIZE;
561                        params.force_dump_cfg = true;
562                        break;
563
564                    case 'e':
565                        if (params.cfg_dump_amt < PCIE_EXTENDED_CONFIG_SIZE)
566                            params.cfg_dump_amt = PCIE_EXTENDED_CONFIG_SIZE;
567                        __FALLTHROUGH;
568
569                    case 'c':
570                        if (params.cfg_dump_amt < PCIE_BASE_CONFIG_SIZE)
571                            params.cfg_dump_amt = PCIE_BASE_CONFIG_SIZE;
572                        __FALLTHROUGH;
573
574                    case 'l':
575                        params.verbose = true;
576                        break;
577
578                    default:
579                        confused = true;
580                        break;
581                }
582
583                c++;
584            }
585        } else {
586            switch (filter_ndx) {
587                case 0:
588                    params.bus_id = static_cast<uint>(argv[i].i);
589                    if (params.bus_id >= PCIE_MAX_BUSSES)
590                        confused = true;
591                    break;
592
593                case 1:
594                    params.dev_id = static_cast<uint>(argv[i].i);
595                    if (params.dev_id >= PCIE_MAX_DEVICES_PER_BUS)
596                        confused = true;
597                    break;
598
599                case 2:
600                    params.func_id = static_cast<uint>(argv[i].i);
601                    if (params.func_id >= PCIE_MAX_FUNCTIONS_PER_DEVICE)
602                        confused = true;
603                    break;
604
605                default:
606                    confused = true;
607                    break;
608            }
609
610            filter_ndx++;
611        }
612
613        if (confused) {
614            printf("usage: %s [-t] [-l] [<bus_id>] [<dev_id>] [<func_id>]\n", argv[0].str);
615            printf("       -l : Be verbose when dumping info about discovered devices.\n");
616            printf("       -c : Dump raw standard config (implies -l)\n");
617            printf("       -e : Dump raw extended config (implies -l -c)\n");
618            printf("       -f : Force dump at least standard config, even if the device didn't "
619                               "enumerate (requires a full BDF address)\n");
620            return ZX_OK;
621        }
622    }
623
624    auto bus_drv = PcieBusDriver::GetDriver();
625    if (bus_drv == nullptr)
626        return ZX_ERR_BAD_STATE;
627
628    bus_drv->ForeachDevice(dump_pcie_device, &params);
629
630    if (!params.found && params.force_dump_cfg &&
631        (params.bus_id  != WILDCARD_ID) &&
632        (params.dev_id  != WILDCARD_ID) &&
633        (params.func_id != WILDCARD_ID)) {
634        const PciConfig* cfg;
635
636        cfg = bus_drv->GetConfig(params.bus_id, params.dev_id, params.func_id);
637        if (!cfg) {
638            printf("Config space for %02x:%02x.%01x not mapped by bus driver!\n",
639                   params.bus_id, params.dev_id, params.func_id);
640        } else {
641            dump_pcie_raw_config(params.cfg_dump_amt, cfg);
642        }
643    } else {
644        printf("PCIe scan discovered %u device%s\n", params.found, (params.found == 1) ? "" : "s");
645    }
646
647    return ZX_OK;
648}
649
650int PcieDebugConsole::CmdPciUnplug(int argc, const cmd_args *argv, uint32_t flags) {
651    bool confused = false;
652    uint bus_id, dev_id, func_id;
653
654    if (argc == 4) {
655        bus_id  = static_cast<uint>(argv[1].i);
656        dev_id  = static_cast<uint>(argv[2].i);
657        func_id = static_cast<uint>(argv[3].i);
658
659        if ((bus_id  >= PCIE_MAX_BUSSES) ||
660            (dev_id  >= PCIE_MAX_DEVICES_PER_BUS) ||
661            (func_id >= PCIE_MAX_FUNCTIONS_PER_DEVICE))
662            confused = true;
663    } else {
664        confused = true;
665    }
666
667    if (confused) {
668        printf("usage: %s <bus_id> <dev_id> <func_id>\n", argv[0].str);
669        return ZX_OK;
670    }
671
672    auto bus_drv = PcieBusDriver::GetDriver();
673    if (bus_drv == nullptr)
674        return ZX_ERR_BAD_STATE;
675
676    fbl::RefPtr<PcieDevice> dev = bus_drv->GetRefedDevice(bus_id, dev_id, func_id);
677
678    if (!dev) {
679        printf("Failed to find PCI device %02x:%02x.%01x\n", bus_id, dev_id, func_id);
680    } else {
681        printf("Unplugging PCI device %02x:%02x.%x...\n",
682                bus_id, dev_id, func_id);
683        dev->Unplug();
684        dev = nullptr;
685        printf("done\n");
686    }
687
688    return ZX_OK;
689}
690
691int PcieDebugConsole::CmdPciReset(int argc, const cmd_args *argv, uint32_t flags) {
692    bool confused = false;
693    uint bus_id, dev_id, func_id;
694
695    if (argc == 4) {
696        bus_id  = static_cast<uint>(argv[1].i);
697        dev_id  = static_cast<uint>(argv[2].i);
698        func_id = static_cast<uint>(argv[3].i);
699
700        if ((bus_id  >= PCIE_MAX_BUSSES) ||
701            (dev_id  >= PCIE_MAX_DEVICES_PER_BUS) ||
702            (func_id >= PCIE_MAX_FUNCTIONS_PER_DEVICE))
703            confused = true;
704    } else {
705        confused = true;
706    }
707
708    if (confused) {
709        printf("usage: %s <bus_id> <dev_id> <func_id>\n", argv[0].str);
710        return ZX_OK;
711    }
712
713    auto bus_drv = PcieBusDriver::GetDriver();
714    if (bus_drv == nullptr)
715        return ZX_ERR_BAD_STATE;
716
717    fbl::RefPtr<PcieDevice> dev = bus_drv->GetRefedDevice(bus_id, dev_id, func_id);
718
719    if (!dev) {
720        printf("Failed to find PCI device %02x:%02x.%01x\n", bus_id, dev_id, func_id);
721    } else {
722        printf("Attempting reset of device %02x:%02x.%01x...\n", bus_id, dev_id, func_id);
723        zx_status_t res = dev->DoFunctionLevelReset();
724        dev = nullptr;
725        if (res != ZX_OK)
726            printf("Reset attempt failed (res = %d).\n", res);
727        else
728            printf("Success, device %02x:%02x.%01x has been reset.\n", bus_id, dev_id, func_id);
729    }
730
731    return ZX_OK;
732}
733
734int PcieDebugConsole::CmdPciRescan(int argc, const cmd_args *argv, uint32_t flags) {
735    auto bus_drv = PcieBusDriver::GetDriver();
736    if (bus_drv == nullptr)
737        return ZX_ERR_BAD_STATE;
738
739    return bus_drv->RescanDevices();
740}
741
742int PcieDebugConsole::CmdPciRegionDump(int argc, const cmd_args *argv, uint32_t flags) {
743    auto walk_cb = [](const ralloc_region_t* r) -> bool {
744        printf("\tregion { base = %" PRIxPTR ", size = %#lx }\n", r->base, r->size);
745        return true;
746    };
747
748    auto bus_drv = PcieBusDriver::GetDriver();
749    printf("mmio_low:\n");
750    bus_drv->mmio_lo_regions_.WalkAllocatedRegions(walk_cb);
751    printf("mmio_high:\n");
752    bus_drv->mmio_hi_regions_.WalkAllocatedRegions(walk_cb);
753    printf("pio:\n");
754    bus_drv->pio_regions_.WalkAllocatedRegions(walk_cb);
755
756    return ZX_OK;
757}
758
759STATIC_COMMAND_START
760STATIC_COMMAND("lspci",
761               "Enumerate the devices detected in PCIe ECAM space",
762               &PcieDebugConsole::CmdLsPci)
763STATIC_COMMAND("pciunplug",
764               "Force \"unplug\" the specified PCIe device",
765               &PcieDebugConsole::CmdPciUnplug)
766STATIC_COMMAND("pcireset",
767               "Initiate a Function Level Reset of the specified device.",
768               &PcieDebugConsole::CmdPciReset)
769STATIC_COMMAND("pcirescan",
770               "Force a rescan of the PCIe configuration space, matching drivers to unclaimed "
771               "devices as we go.  Then attempt to start all newly claimed devices.",
772               &PcieDebugConsole::CmdPciRescan)
773STATIC_COMMAND("pciregions",
774               "Dump information on present PCI address region allocations",
775               &PcieDebugConsole::CmdPciRegionDump)
776STATIC_COMMAND_END(pcie);
777