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 <assert.h> 9#include <debug.h> 10#include <err.h> 11#include <string.h> 12#include <trace.h> 13#include <fbl/algorithm.h> 14#include <dev/pci_config.h> 15#include <dev/pcie_device.h> 16 17#include <fbl/alloc_checker.h> 18 19#define LOCAL_TRACE 0 20 21/* 22 * TODO(cja) Re-add the paranoid sanity checks on capability placement 23 * and size that was in the old code. Doing this sanely likely involves keeping 24 * the various C style structures for the capabilities in pcie_caps.h originally 25*/ 26 27static bool quirk_should_force_pcie(const PcieDevice& dev) { 28 static const struct { 29 uint16_t vendor_id; 30 uint16_t device_id; 31 } QUIRK_LIST[] = { 32 { .vendor_id = 0x8086, .device_id = 0x1616 }, // Wildcat Point GPU 33 }; 34 35 for (size_t i = 0; i < fbl::count_of(QUIRK_LIST); ++i) { 36 if ((QUIRK_LIST[i].vendor_id == dev.vendor_id()) && 37 (QUIRK_LIST[i].device_id == dev.device_id())) 38 return true; 39 } 40 41 return false; 42} 43 44 45/* 46 * Advanced Capabilities for Conventional PCI ECN 47 */ 48PciCapAdvFeatures::PciCapAdvFeatures(const PcieDevice& dev, uint16_t base, uint8_t id) 49 : PciStdCapability(dev, base, id) { 50 DEBUG_ASSERT(id == PCIE_CAP_ID_ADVANCED_FEATURES); 51 auto cfg = dev.config(); 52 53 length_ = PciReg8(static_cast<uint16_t>(base_ + kLengthOffset)); 54 af_caps_ = PciReg8(static_cast<uint16_t>(base_ + kAFCapsOffset)); 55 af_ctrl_ = PciReg8(static_cast<uint16_t>(base_ + kAFControlOffset)); 56 af_status_ = PciReg8(static_cast<uint16_t>(base_ + kAFStatusOffset)); 57 58 uint8_t caps = cfg->Read(af_caps_); 59 has_flr_ = PCS_ADVCAPS_CAP_HAS_FUNC_LEVEL_RESET(caps); 60 has_tp_ = PCS_ADVCAPS_CAP_HAS_TRANS_PENDING(caps); 61 62 uint8_t length = cfg->Read(length_); 63 if (length != PCS_ADVCAPS_LENGTH) { 64 TRACEF("Length of %u does not match the spec length of %u!\n", length, PCS_ADVCAPS_LENGTH); 65 return; 66 } 67 68 is_valid_ = true; 69} 70 71/* 72 * PCI Express Base Specification 1.1 Section 7.8 (version 1) 73 * PCI Express Base Specification 3.1a Section 7.8 (version 2) 74 */ 75PciCapPcie::PciCapPcie(const PcieDevice& dev, uint16_t base, uint8_t id) 76 : PciStdCapability(dev, base, id) { 77 DEBUG_ASSERT(id == PCIE_CAP_ID_PCI_EXPRESS); 78 auto cfg = dev.config(); 79 80 /* Have we already initialized PCIE? */ 81 if (is_valid_) { 82 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has more than one PCI " 83 "Express capability structure!\n", 84 dev.bus_id(), dev.dev_id(), dev.func_id(), 85 dev.vendor_id(), dev.device_id()); 86 return; 87 } 88 89 caps_ = PciReg16(static_cast<uint16_t>(base_ + kPcieCapsOffset)); 90 auto cap_val = cfg->Read(caps_); 91 version_ = PCS_CAPS_VERSION(cap_val); 92 devtype_ = PCS_CAPS_DEVTYPE(cap_val); 93 94 /* 95 * Set up all the offsets for the various chunks in the device. Some may 96 * not be supported, but regardless of whether they are there the final 97 * structure will be the same. 98 */ 99 device.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kDeviceOffset))); 100 device.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kDeviceOffset))); 101 device.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kDeviceOffset))); 102 103 link.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kLinkOffset))); 104 link.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kLinkOffset))); 105 link.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kLinkOffset))); 106 107 slot.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kSlotOffset))); 108 slot.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kSlotOffset))); 109 slot.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kSlotOffset))); 110 111 root.caps_ = PciReg16(static_cast<uint16_t>(base_ + kRootCapsOffset)); 112 root.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kRootControlOffset)); 113 root.status_ = PciReg32(static_cast<uint16_t>(base_ + kRootStatusOffset)); 114 115 device2.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kDevice2Offset))); 116 device2.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kDevice2Offset))); 117 device2.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kDevice2Offset))); 118 119 link2.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kLinkOffset))); 120 link2.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kLinkOffset))); 121 link2.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kLinkOffset))); 122 123 slot2.caps_ = PciReg32(static_cast<uint16_t>(base_ + kCapsOffset(kSlotOffset))); 124 slot2.ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset(kSlotOffset))); 125 slot2.status_ = PciReg16(static_cast<uint16_t>(base_ + kStatusOffset(kSlotOffset))); 126 127 /* Sanity check the device/port type */ 128 switch (devtype_) { 129 // Type 0 config header types 130 case PCIE_DEVTYPE_PCIE_ENDPOINT: 131 case PCIE_DEVTYPE_LEGACY_PCIE_ENDPOINT: 132 case PCIE_DEVTYPE_RC_INTEGRATED_ENDPOINT: 133 case PCIE_DEVTYPE_RC_EVENT_COLLECTOR: 134 if (dev.is_bridge()) { 135 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has a Type 0 PCIe " 136 "device type (0x%x) in PCIe capabilties structure, but " 137 "does not have a Type 0 config header.\n", 138 dev.bus_id(), dev.dev_id(), dev.func_id(), 139 dev.vendor_id(), dev.device_id(), 140 devtype_); 141 return; 142 } 143 break; 144 145 // Type 1 config header types 146 case PCIE_DEVTYPE_RC_ROOT_PORT: 147 case PCIE_DEVTYPE_SWITCH_UPSTREAM_PORT: 148 case PCIE_DEVTYPE_SWITCH_DOWNSTREAM_PORT: 149 case PCIE_DEVTYPE_PCIE_TO_PCI_BRIDGE: 150 case PCIE_DEVTYPE_PCI_TO_PCIE_BRIDGE: 151 if (!dev.is_bridge()) { 152 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has a Type 1 PCIe " 153 "device type (0x%x) in PCIe capabilties structure, but " 154 "does not have a Type 1 config header.\n", 155 dev.bus_id(), dev.dev_id(), dev.func_id(), 156 dev.vendor_id(), dev.device_id(), 157 devtype_); 158 return; 159 } 160 break; 161 162 default: 163 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has an illegal PCIe " 164 "device type (0x%x) in PCIe capabilties structure.\n", 165 dev.bus_id(), dev.dev_id(), dev.func_id(), 166 dev.vendor_id(), dev.device_id(), 167 devtype_); 168 return; 169 } 170 171 /* TODO(johngro): remember to read the MSI/MSI-X interrupt message number 172 * field when setting up for MSI/MSI-X. We almost certainly need to hook 173 * this IRQ in order to be aware of any changes to the extended 174 * capabilities. It is unclear whether or not we should allow this IRQ to 175 * be passed thru to the device driver or not. 176 */ 177 178 /* Check device capabilities to see if we support function level reset or 179 * not */ 180 uint32_t devcaps = cfg->Read(device.caps()); 181 has_flr_ = (PCS_DEV_CAPS_FUNC_LEVEL_RESET(devcaps) != 0); 182 183 is_valid_ = true; 184} 185 186/* 187 * @see PCI Local Bus Specification 3.0 Section 6.8.1 188 */ 189PciCapMsi::PciCapMsi(const PcieDevice& dev, uint16_t base, uint8_t id) 190 : PciStdCapability(dev, base, id) { 191 DEBUG_ASSERT(id == PCIE_CAP_ID_MSI); 192 auto cfg = dev.config(); 193 194 // Set up the rest of the registers based on whether we're 64 bit or not. 195 ctrl_ = PciReg16(static_cast<uint16_t>(base_ + kControlOffset)); 196 addr_ = PciReg32(static_cast<uint16_t>(base_ + kAddrOffset)); 197 198 uint16_t ctrl = cfg->Read(ctrl_reg()); 199 has_pvm_ = PCIE_CAP_MSI_CTRL_PVM_SUPPORTED(ctrl); 200 is_64_bit_ = PCIE_CAP_MSI_CTRL_64BIT_SUPPORTED(ctrl); 201 msi_size_ = (has_pvm_ ? (is_64_bit_ ? k64BitPvmSize : k32BitPvmSize) 202 : (is_64_bit_ ? k64BitNoPvmSize : k32BitNoPvmSize)); 203 204 if (is_64_bit_) { 205 addr_upper_ = PciReg32(static_cast<uint16_t>(base_ + kAddrUpperOffset)); 206 data_ = PciReg16(static_cast<uint16_t>(base_ + kData64Offset)); 207 mask_bits_ = PciReg32(static_cast<uint16_t>(base_ + kMaskBits64Offset)); 208 pending_bits_ = PciReg32(static_cast<uint16_t>(base_ + kPendingBits64Offset)); 209 } else { 210 data_ = PciReg16(static_cast<uint16_t>(base_ + kData32Offset)); 211 mask_bits_ = PciReg32(static_cast<uint16_t>(base_ + kMaskBits32Offset)); 212 pending_bits_ = PciReg32(static_cast<uint16_t>(base_ + kPendingBits32Offset)); 213 } 214 215 memset(&irq_block_, 0, sizeof(irq_block_)); 216 uint16_t msi_end = static_cast<uint16_t>(base_ + msi_size_); 217 uint16_t cfgend = PCIE_BASE_CONFIG_SIZE; 218 219 if (msi_end >= cfgend) { 220 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has illegally positioned MSI " 221 "capability structure. Structure %s 64-bit addressing and %s " 222 "per-vector masking and should be %u bytes long, but the " 223 "structure ends at %u, %u bytes past the end of config " 224 "space\n", 225 dev.bus_id(), dev.dev_id(), dev.func_id(), 226 dev.vendor_id(), dev.device_id(), 227 is_64_bit_ ? "supports" : "does not support", 228 has_pvm_ ? "supports" : "does not support", 229 msi_size_, msi_end, static_cast<unsigned int>(cfgend - msi_end)); 230 return; 231 } 232 233 /* Sanity check the Multi-Message Capable field */ 234 max_irqs_ = 0x1u << PCIE_CAP_MSI_CTRL_GET_MMC(ctrl); 235 if (max_irqs_ > PCIE_MAX_MSI_IRQS) { 236 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has invalid Multi-Message " 237 "Capable value in MSI capability structure (%d). Structure " 238 "claims to support %u vectors, but %u is the maximum allowed.\n", 239 dev.bus_id(), dev.dev_id(), dev.func_id(), 240 dev.vendor_id(), dev.device_id(), 241 PCIE_CAP_MSI_CTRL_GET_MMC(ctrl), max_irqs_, PCIE_MAX_MSI_IRQS); 242 return; 243 } 244 245 /* Success! 246 * 247 * Make sure that MSI is disabled and that the Multi-Message Enable field is 248 * set to 1-vector (multi-message disabled). Then record our capabilities 249 * in the device's bookkeeping and we are done. 250 */ 251 cfg->Write(ctrl_reg(), PCIE_CAP_MSI_CTRL_SET_MME(0, 252 PCIE_CAP_MSI_CTRL_SET_ENB(0, ctrl))); 253 if (has_pvm_) 254 cfg->Write(mask_bits_reg(), 0xFFFFFFFF); 255 256 is_valid_ = true; 257} 258 259/* Catch quirks and invalid capability offsets we may see */ 260inline zx_status_t validate_capability_offset(uint8_t offset) { 261 if (offset == 0xFF 262 || offset < PCIE_CAP_PTR_MIN_VALID 263 || offset > PCIE_CAP_PTR_MAX_VALID) { 264 return ZX_ERR_INVALID_ARGS; 265 } 266 267 return ZX_OK; 268} 269 270/* 271 * TODO(cja): It may be worth moving to table based solution like we had before 272 * where we have a single parse function and a function table for it to use, 273 * but it involves a bit more worrying about ownership of capabilities and 274 * std / ext attributes. 275 */ 276 277zx_status_t PcieDevice::ParseStdCapabilitiesLocked() { 278 zx_status_t res = ZX_OK; 279 uint8_t cap_offset = cfg_->Read(PciConfig::kCapabilitiesPtr); 280 uint8_t caps_found = 0; 281 fbl::AllocChecker ac; 282 283 /* 284 * Walk the pointer list for the standard capabilities table. As a safety, 285 * keep track of how many capabilities we've looked at to prevent potential 286 * cycles from walking forever. Any supported capability will be parsed 287 * by their object in the PcieDevice, and are additionally stored in a list 288 * for reference later. 289 */ 290 LTRACEF("Scanning for capabilities at %02x:%02x.%01x (%04hx:%04hx)\n", 291 bus_id(), dev_id(), func_id(), vendor_id(), device_id()); 292 while (cap_offset != PCIE_CAP_PTR_NULL && caps_found < PCIE_MAX_CAPABILITIES) { 293 if ((res = validate_capability_offset(cap_offset)) != ZX_OK) { 294 TRACEF("Device %02x:%02x.%01x (%04hx:%04hx) has invalid cptr (%#02x)\n", 295 bus_id(), dev_id(), func_id(), 296 vendor_id(), device_id(), cap_offset); 297 break; 298 } 299 300 uint8_t id = cfg_->Read(PciReg8(cap_offset)); 301 302 LTRACEF("Found capability (#%u, id = 0x%02x) for device %02x:%02x.%01x (%04hx:%04hx)\n", 303 caps_found, id, 304 bus_id(), dev_id(), func_id(), 305 vendor_id(), device_id()); 306 /* 307 * Depending on the capability found we allocate a structure of the appropriate type 308 * and add it to the bookkeeping tree. For important things like MSI/PCIE we cache a raw 309 * pointer to it for fast access, but otherwise everything is found via the capability list. 310 * 311 * TODO(cja): if we make this a two stage allocation/initialization in the future we can do 312 * away with is_valid() style checks that are done in additional checking if pcie_/msi_ are 313 * valid pointers. 314 */ 315 PciStdCapability* cap; 316 switch(id) { 317 case PCIE_CAP_ID_MSI: 318 cap = irq_.msi = new (&ac) PciCapMsi(*this, cap_offset, id); break; 319 case PCIE_CAP_ID_PCI_EXPRESS: 320 cap = pcie_ = new (&ac) PciCapPcie(*this, cap_offset, id); break; 321 case PCIE_CAP_ID_ADVANCED_FEATURES: 322 cap = pci_af_ = new (&ac) PciCapAdvFeatures(*this, cap_offset, id); break; 323 324 default: 325 cap = new (&ac) PciStdCapability(*this, cap_offset, id); break; 326 } 327 328 if (!ac.check()) { 329 TRACEF("Could not allocate memory fori capability 0x%02x\n", id); 330 return ZX_ERR_NO_MEMORY; 331 } 332 333 caps_.detected.push_front(fbl::unique_ptr<PciStdCapability>(cap)); 334 cap_offset = cfg_->Read(PciReg8(static_cast<uint16_t>(cap_offset + 0x1))) & 0xFC; 335 caps_found++; 336 } 337 338 return res; 339} 340 341zx_status_t PcieDevice::ParseExtCapabilitiesLocked() { 342 /* 343 * TODO(cja): Since ExtCaps are a no-op right now (we had nothing in the table for 344 * supported extended capabilities) this is a stub for now. 345 */ 346 return ZX_OK; 347} 348 349// Parse PCI Standard Capabilities starting with the pointer in the PCI 350// config structure. 351zx_status_t PcieDevice::ProbeCapabilitiesLocked() { 352 zx_status_t ret = ParseStdCapabilitiesLocked(); 353 if (ret != ZX_OK) { 354 return ret; 355 } 356 357 /* If this device is PCIe device, the parse the extended configuration 358 * section of the PCI config looking for extended capabilities. Based on 359 * the spec, we should only need to look for a PCI Express Capability 360 * Structure in the standard config section to make the determination that 361 * this device is a legit PCIe device. 362 * 363 * This said, I have encountered at least one device (the graphics 364 * controller in the Wildcat Point PCH) which clearly is PCIe and clearly 365 * has extended capabilities, but which is not spec compliant and does not 366 * contain a proper PCI Express Capability Structure. Because of this, we 367 * maintain a quirks list of non compliant devices which are actually PCIe, 368 * but do not appear to be so at first glance. */ 369 if ((is_pcie() || quirk_should_force_pcie(*this)) && pcie_->is_valid()) { 370 ret = ParseExtCapabilitiesLocked(); 371 } 372 373 return ret; 374} 375