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