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
quirk_should_force_pcie(const PcieDevice & dev)27 static 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 */
PciCapAdvFeatures(const PcieDevice & dev,uint16_t base,uint8_t id)48 PciCapAdvFeatures::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 */
PciCapPcie(const PcieDevice & dev,uint16_t base,uint8_t id)75 PciCapPcie::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 capabilities 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 capabilities 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 capabilities 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 */
PciCapMsi(const PcieDevice & dev,uint16_t base,uint8_t id)189 PciCapMsi::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 */
validate_capability_offset(uint8_t offset)260 inline 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
ParseStdCapabilitiesLocked()277 zx_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(ktl::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
ParseExtCapabilitiesLocked()341 zx_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.
ProbeCapabilitiesLocked()351 zx_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