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(¶ms, 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, ¶ms); 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