xref: /illumos-gate/usr/src/uts/common/io/pciex/pcie.c (revision ead3c390)
1f8d2de6bSjchu /*
2f8d2de6bSjchu  * CDDL HEADER START
3f8d2de6bSjchu  *
4f8d2de6bSjchu  * The contents of this file are subject to the terms of the
527255037Spjha  * Common Development and Distribution License (the "License").
627255037Spjha  * You may not use this file except in compliance with the License.
7f8d2de6bSjchu  *
8f8d2de6bSjchu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f8d2de6bSjchu  * or http://www.opensolaris.org/os/licensing.
10f8d2de6bSjchu  * See the License for the specific language governing permissions
11f8d2de6bSjchu  * and limitations under the License.
12f8d2de6bSjchu  *
13f8d2de6bSjchu  * When distributing Covered Code, include this CDDL HEADER in each
14f8d2de6bSjchu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f8d2de6bSjchu  * If applicable, add the following below this CDDL HEADER, with the
16f8d2de6bSjchu  * fields enclosed by brackets "[]" replaced with your own identifying
17f8d2de6bSjchu  * information: Portions Copyright [yyyy] [name of copyright owner]
18f8d2de6bSjchu  *
19f8d2de6bSjchu  * CDDL HEADER END
20f8d2de6bSjchu  */
219187c210SAlan Adamson, SD OSSD 
22f8d2de6bSjchu /*
2383e6495bSDaniel Ice  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24b3d69c05SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
25*ead3c390SKeith M Wesolowski  * Copyright 2024 Oxide Computer Company
26f8d2de6bSjchu  */
27f8d2de6bSjchu 
285b2c4190SRobert Mustacchi /*
295b2c4190SRobert Mustacchi  * PCIe Initialization
305b2c4190SRobert Mustacchi  * -------------------
315b2c4190SRobert Mustacchi  *
325b2c4190SRobert Mustacchi  * The PCIe subsystem is split about and initializes itself in a couple of
335b2c4190SRobert Mustacchi  * different places. This is due to the platform-specific nature of initializing
345b2c4190SRobert Mustacchi  * resources and the nature of the SPARC PROM and how that influenced the
355b2c4190SRobert Mustacchi  * subsystem. Note that traditional PCI (mostly seen these days in Virtual
365b2c4190SRobert Mustacchi  * Machines) follows most of the same basic path outlined here, but skips a
375b2c4190SRobert Mustacchi  * large chunk of PCIe-specific initialization.
385b2c4190SRobert Mustacchi  *
395b2c4190SRobert Mustacchi  * First, there is an initial device discovery phase that is taken care of by
405b2c4190SRobert Mustacchi  * the platform. This is where we discover the set of devices that are present
415b2c4190SRobert Mustacchi  * at system power on. These devices may or may not be hot-pluggable. In
425b2c4190SRobert Mustacchi  * particular, this happens in a platform-specific way right now. In general, we
435b2c4190SRobert Mustacchi  * expect most discovery to be driven by scanning each bus, device, and
445b2c4190SRobert Mustacchi  * function, and seeing what actually exists and responds to configuration space
455b2c4190SRobert Mustacchi  * reads. This is driven via pci_boot.c on x86. This may be seeded by something
465b2c4190SRobert Mustacchi  * like device tree, a PROM, supplemented with ACPI, or by knowledge that the
475b2c4190SRobert Mustacchi  * underlying platform has.
485b2c4190SRobert Mustacchi  *
495b2c4190SRobert Mustacchi  * As a part of this discovery process, the full set of resources that exist in
505b2c4190SRobert Mustacchi  * the system for PCIe are:
515b2c4190SRobert Mustacchi  *
525b2c4190SRobert Mustacchi  *   o PCI buses
535b2c4190SRobert Mustacchi  *   o Prefetchable Memory
545b2c4190SRobert Mustacchi  *   o Non-prefetchable memory
555b2c4190SRobert Mustacchi  *   o I/O ports
565b2c4190SRobert Mustacchi  *
575b2c4190SRobert Mustacchi  * This process is driven by a platform's PCI platform Resource Discovery (PRD)
585b2c4190SRobert Mustacchi  * module. The PRD definitions can be found in <sys/plat/pci_prd.h> and are used
595b2c4190SRobert Mustacchi  * to discover these resources, which will be converted into the initial set of
605b2c4190SRobert Mustacchi  * the standard properties in the system: 'regs', 'available', 'ranges', etc.
615b2c4190SRobert Mustacchi  * Currently it is up to platform-specific code (which should ideally be
625b2c4190SRobert Mustacchi  * consolidated at some point) to set up all these properties.
635b2c4190SRobert Mustacchi  *
645b2c4190SRobert Mustacchi  * As a part of the discovery process, the platform code will create a device
655b2c4190SRobert Mustacchi  * node (dev_info_t) for each discovered function and will create a PCIe nexus
665b2c4190SRobert Mustacchi  * for each overall root complex that exists in the system. Most root complexes
675b2c4190SRobert Mustacchi  * will have multiple root ports, each of which is the foundation of an
685b2c4190SRobert Mustacchi  * independent PCIe bus due to the point-to-point nature of PCIe. When a root
695b2c4190SRobert Mustacchi  * complex is found, a nexus driver such as npe (Nexus for PCIe Express) is
705b2c4190SRobert Mustacchi  * attached. In the case of a non-PCIe-capable system this is where the older
715b2c4190SRobert Mustacchi  * pci nexus driver would be used instead.
725b2c4190SRobert Mustacchi  *
735b2c4190SRobert Mustacchi  * To track data about a given device on a bus, a 'pcie_bus_t' structure is
745b2c4190SRobert Mustacchi  * created for and assigned to every PCIe-based dev_info_t. This can be used to
755b2c4190SRobert Mustacchi  * find the root port and get basic information about the device, its faults,
765b2c4190SRobert Mustacchi  * and related information. This contains pointers to the corresponding root
775b2c4190SRobert Mustacchi  * port as well.
785b2c4190SRobert Mustacchi  *
795b2c4190SRobert Mustacchi  * A root complex has its pcie_bus_t initialized as part of the device discovery
805b2c4190SRobert Mustacchi  * process. That is, because we're trying to bootstrap the actual tree and most
815b2c4190SRobert Mustacchi  * platforms don't have a representation for this that's explicitly
825b2c4190SRobert Mustacchi  * discoverable, this is created manually. See callers of pcie_rc_init_bus().
835b2c4190SRobert Mustacchi  *
845b2c4190SRobert Mustacchi  * For other devices, bridges, and switches, the process is split into two.
855b2c4190SRobert Mustacchi  * There is an initial pcie_bus_t that is created which will exist before we go
865b2c4190SRobert Mustacchi  * through the actual driver attachment process. For example, on x86 this is
875b2c4190SRobert Mustacchi  * done as part of the device and function discovery. The second pass of
885b2c4190SRobert Mustacchi  * initialization is done only after the nexus driver actually is attached and
895b2c4190SRobert Mustacchi  * it goes through and finishes processing all of its children.
905b2c4190SRobert Mustacchi  *
915b2c4190SRobert Mustacchi  * Child Initialization
925b2c4190SRobert Mustacchi  * --------------------
935b2c4190SRobert Mustacchi  *
945b2c4190SRobert Mustacchi  * Generally speaking, the platform will first enumerate all PCIe devices that
955b2c4190SRobert Mustacchi  * are in the sytem before it actually creates a device tree. This is part of
965b2c4190SRobert Mustacchi  * the bus/device/function scanning that is performed and from that dev_info_t
975b2c4190SRobert Mustacchi  * nodes are created for each discovered device and are inserted into the
985b2c4190SRobert Mustacchi  * broader device tree. Later in boot, the actual device tree is walked and the
995b2c4190SRobert Mustacchi  * nodes go through the standard dev_info_t initialization process (DS_PROTO,
1005b2c4190SRobert Mustacchi  * DS_LINKED, DS_BOUND, etc.).
1015b2c4190SRobert Mustacchi  *
1025b2c4190SRobert Mustacchi  * PCIe-specific initialization can roughly be broken into the following pieces:
1035b2c4190SRobert Mustacchi  *
1045b2c4190SRobert Mustacchi  *   1. Platform initial discovery and resource assignment
1055b2c4190SRobert Mustacchi  *   2. The pcie_bus_t initialization
1065b2c4190SRobert Mustacchi  *   3. Nexus driver child initialization
1075b2c4190SRobert Mustacchi  *   4. Fabric initialization
1085b2c4190SRobert Mustacchi  *   5. Device driver-specific initialization
1095b2c4190SRobert Mustacchi  *
1105b2c4190SRobert Mustacchi  * The first part of this (1) and (2) are discussed in the previous section.
1115b2c4190SRobert Mustacchi  * Part (1) in particular is a combination of the PRD (platform resource
1125b2c4190SRobert Mustacchi  * discovery) and general device initialization. After this, because we have a
1135b2c4190SRobert Mustacchi  * device tree, most of the standard nexus initialization happens.
1145b2c4190SRobert Mustacchi  *
1155b2c4190SRobert Mustacchi  * (5) is somewhat simple, so let's get into it before we discuss (3) and (4).
1165b2c4190SRobert Mustacchi  * This is the last thing that is called and that happens after all of the
1175b2c4190SRobert Mustacchi  * others are done. This is the logic that occurs in a driver's attach(9E) entry
1185b2c4190SRobert Mustacchi  * point. This is always device-specific and generally speaking should not be
1195b2c4190SRobert Mustacchi  * manipulating standard PCIe registers directly on their own. For example, the
1205b2c4190SRobert Mustacchi  * MSI/MSI-X, AER, Serial Number, etc. capabilities will be automatically dealt
1215b2c4190SRobert Mustacchi  * with by the framework in (3) and (4) below. In many cases, particularly
1225b2c4190SRobert Mustacchi  * things that are part of (4), adjusting them in the individual driver is not
1235b2c4190SRobert Mustacchi  * safe.
1245b2c4190SRobert Mustacchi  *
1255b2c4190SRobert Mustacchi  * Finally, let's talk about (3) and (4) as these are related. The NDI provides
1265b2c4190SRobert Mustacchi  * for a standard hook for a nexus to initialize its children. In our platforms,
1275b2c4190SRobert Mustacchi  * there are basically two possible PCIe nexus drivers: there is the generic
1285b2c4190SRobert Mustacchi  * pcieb -- PCIe bridge -- driver which is used for standard root ports,
1295b2c4190SRobert Mustacchi  * switches, etc. Then there is the platform-specific primary nexus driver,
1305b2c4190SRobert Mustacchi  * which is being slowly consolidated into a single one where it makes sense. An
1315b2c4190SRobert Mustacchi  * example of this is npe.
1325b2c4190SRobert Mustacchi  *
1335b2c4190SRobert Mustacchi  * Each of these has a child initialization function which is called from their
1345b2c4190SRobert Mustacchi  * DDI_CTLOPS_INITCHILD operation on the bus_ctl function pointer. This goes
1355b2c4190SRobert Mustacchi  * through and initializes a large number of different pieces of PCIe-based
1365b2c4190SRobert Mustacchi  * settings through the common pcie_initchild() function. This takes care of
1375b2c4190SRobert Mustacchi  * things like:
1385b2c4190SRobert Mustacchi  *
1395b2c4190SRobert Mustacchi  *   o Advanced Error Reporting
1405b2c4190SRobert Mustacchi  *   o Alternative Routing
1415b2c4190SRobert Mustacchi  *   o Capturing information around link speed, width, serial numbers, etc.
1425b2c4190SRobert Mustacchi  *   o Setting common properties around aborts
1435b2c4190SRobert Mustacchi  *
1445b2c4190SRobert Mustacchi  * There are a few caveats with this that need to be kept in mind:
1455b2c4190SRobert Mustacchi  *
1465b2c4190SRobert Mustacchi  *   o A dev_info_t indicates a specific function. This means that a
1475b2c4190SRobert Mustacchi  *     multi-function device will not all be initialized at the same time and
1485b2c4190SRobert Mustacchi  *     there is no guarantee that all children will be initialized before one of
1495b2c4190SRobert Mustacchi  *     them is attached.
1505b2c4190SRobert Mustacchi  *   o A child is only initialized if we have found a driver that matches an
1515b2c4190SRobert Mustacchi  *     alias in the dev_info_t's compatible array property.  While a lot of
1525b2c4190SRobert Mustacchi  *     multi-function devices are often multiple instances of the same thing
1535b2c4190SRobert Mustacchi  *     (e.g. a multi-port NIC with a function / NIC), this is not always the
1545b2c4190SRobert Mustacchi  *     case and one cannot make any assumptions here.
1555b2c4190SRobert Mustacchi  *
1565b2c4190SRobert Mustacchi  * This in turn leads to the next form of initialization that takes place in the
1575b2c4190SRobert Mustacchi  * case of (4). This is where we take care of things that need to be consistent
1585b2c4190SRobert Mustacchi  * across either entire devices or more generally across an entire root port and
1595b2c4190SRobert Mustacchi  * all of its children. There are a few different examples of this:
1605b2c4190SRobert Mustacchi  *
1615b2c4190SRobert Mustacchi  *   o Setting the maximum packet size
1625b2c4190SRobert Mustacchi  *   o Determining the tag width
1635b2c4190SRobert Mustacchi  *
1645b2c4190SRobert Mustacchi  * Note that features which are only based on function 0, such as ASPM (Active
1655b2c4190SRobert Mustacchi  * State Power Management), hardware autonomous width disable, etc. ultimately
1665b2c4190SRobert Mustacchi  * do not go through this path today. There are some implications here in that
1675b2c4190SRobert Mustacchi  * today several of these things are captured on functions which may not have
1685b2c4190SRobert Mustacchi  * any control here. This is an area of needed improvement.
1695b2c4190SRobert Mustacchi  *
1705b2c4190SRobert Mustacchi  * The settings in (4) are initialized in a common way, via
1715b2c4190SRobert Mustacchi  * pcie_fabric_setup(). This is called into from two different parts of
1725b2c4190SRobert Mustacchi  * the stack:
1735b2c4190SRobert Mustacchi  *
1745b2c4190SRobert Mustacchi  *   1. When we attach a root port, which is driven by pcieb.
1755b2c4190SRobert Mustacchi  *   2. When we have a hotplug event that adds a device.
1765b2c4190SRobert Mustacchi  *
1775b2c4190SRobert Mustacchi  * In general here we are going to use the term 'fabric' to refer to everything
1785b2c4190SRobert Mustacchi  * that is downstream of a root port. This corresponds to what the PCIe
1795b2c4190SRobert Mustacchi  * specification calls a 'hierarchy domain'. Strictly speaking, this is fine
1805b2c4190SRobert Mustacchi  * until peer-to-peer requests begin to happen that cause you to need to forward
1815b2c4190SRobert Mustacchi  * things across root ports. At that point the scope of the fabric increases and
1825b2c4190SRobert Mustacchi  * these settings become more complicated. We currently optimize for the much
1835b2c4190SRobert Mustacchi  * more common case, which is that each root port is effectively independent
1845b2c4190SRobert Mustacchi  * from a PCIe transaction routing perspective.
1855b2c4190SRobert Mustacchi  *
1865b2c4190SRobert Mustacchi  * Put differently, we use the term 'fabric' to refer to a set of PCIe devices
1875b2c4190SRobert Mustacchi  * that can route transactions to one another, which is generally constrained to
1885b2c4190SRobert Mustacchi  * everything under a root port and that root ports are independent. If this
1895b2c4190SRobert Mustacchi  * constraint changes, then all one needs to do is replace the discussion of the
1905b2c4190SRobert Mustacchi  * root port below with the broader root complex and system.
1915b2c4190SRobert Mustacchi  *
1925b2c4190SRobert Mustacchi  * A challenge with these settings is that once they're set and devices are
1935b2c4190SRobert Mustacchi  * actively making requests, we cannot really change them without resetting the
1945b2c4190SRobert Mustacchi  * links and cancelling all outstanding transactions via device resets. Because
1955b2c4190SRobert Mustacchi  * this is not something that we want to do, we instead look at how and when we
1965b2c4190SRobert Mustacchi  * set this to constrain what's going on.
1975b2c4190SRobert Mustacchi  *
1985b2c4190SRobert Mustacchi  * Because of this we basically say that if a given fabric has more than one
1995b2c4190SRobert Mustacchi  * hot-plug capable device that's encountered, then we have to use safe defaults
2005b2c4190SRobert Mustacchi  * (which we can allow an operator to tune eventually via pcieadm). If we have a
2015b2c4190SRobert Mustacchi  * mix of non-hotpluggable slots with downstream endpoints present and
2025b2c4190SRobert Mustacchi  * hot-pluggable slots, then we're in this case. If we don't have hot-pluggable
2035b2c4190SRobert Mustacchi  * slots, then we can have an arbitrarily complex setup. Let's look at a few of
2045b2c4190SRobert Mustacchi  * these visually:
2055b2c4190SRobert Mustacchi  *
2065b2c4190SRobert Mustacchi  * In the following diagrams, RP stands for Root Port, EP stands for Endpoint.
2075b2c4190SRobert Mustacchi  * If something is hot-pluggable, then we label it with (HP).
2085b2c4190SRobert Mustacchi  *
2095b2c4190SRobert Mustacchi  *   (1) RP --> EP
2105b2c4190SRobert Mustacchi  *   (2) RP --> Switch --> EP
2115b2c4190SRobert Mustacchi  *                    +--> EP
2125b2c4190SRobert Mustacchi  *                    +--> EP
2135b2c4190SRobert Mustacchi  *
2145b2c4190SRobert Mustacchi  *   (3) RP --> Switch --> EP
2155b2c4190SRobert Mustacchi  *                    +--> EP
2165b2c4190SRobert Mustacchi  *                    +--> Switch --> EP
2175b2c4190SRobert Mustacchi  *                               +--> EP
2185b2c4190SRobert Mustacchi  *                    +--> EP
2195b2c4190SRobert Mustacchi  *
2205b2c4190SRobert Mustacchi  *
2215b2c4190SRobert Mustacchi  *   (4) RP (HP) --> EP
2225b2c4190SRobert Mustacchi  *   (5) RP (HP) --> Switch --> EP
2235b2c4190SRobert Mustacchi  *                         +--> EP
2245b2c4190SRobert Mustacchi  *                         +--> EP
2255b2c4190SRobert Mustacchi  *
2265b2c4190SRobert Mustacchi  *   (6) RP --> Switch (HP) --> EP
2275b2c4190SRobert Mustacchi  *   (7) RP (HP) --> Switch (HP) --> EP
2285b2c4190SRobert Mustacchi  *
2295b2c4190SRobert Mustacchi  * If we look at all of these, these are all cases where it's safe for us to set
2305b2c4190SRobert Mustacchi  * things based on all devices. (1), (2), and (3) are straightforward because
2315b2c4190SRobert Mustacchi  * they have no hot-pluggable elements. This means that nothing should come/go
2325b2c4190SRobert Mustacchi  * on the system and we can set up fabric-wide properties as part of the root
2335b2c4190SRobert Mustacchi  * port.
2345b2c4190SRobert Mustacchi  *
2355b2c4190SRobert Mustacchi  * Case (4) is the most standard one that we encounter for hot-plug. Here you
2365b2c4190SRobert Mustacchi  * have a root port directly connected to an endpoint. The most common example
2375b2c4190SRobert Mustacchi  * would be an NVMe device plugged into a root port. Case (5) is interesting to
2385b2c4190SRobert Mustacchi  * highlight. While there is a switch and multiple endpoints there, they are
2395b2c4190SRobert Mustacchi  * showing up as a unit. This ends up being a weirder variant of (4), but it is
2405b2c4190SRobert Mustacchi  * safe for us to set advanced properties because we can figure out what the
2415b2c4190SRobert Mustacchi  * total set should be.
2425b2c4190SRobert Mustacchi  *
2435b2c4190SRobert Mustacchi  * Now, the more interesting bits here are (6) and (7). The reason that (6)
2445b2c4190SRobert Mustacchi  * works is that ultimately there is only a single down-stream port here that is
2455b2c4190SRobert Mustacchi  * hot-pluggable and all non-hotpluggable ports do not have a device present,
2465b2c4190SRobert Mustacchi  * which suggests that they will never have a device present. (7) also could be
2475b2c4190SRobert Mustacchi  * made to work by making the observation that if there's truly only one
2485b2c4190SRobert Mustacchi  * endpoint in a fabric, it doesn't matter how many switches there are that are
2495b2c4190SRobert Mustacchi  * hot-pluggable. This would only hold if we can assume for some reason that no
2505b2c4190SRobert Mustacchi  * other endpoints could be added.
2515b2c4190SRobert Mustacchi  *
2525b2c4190SRobert Mustacchi  * In turn, let's look at several cases that we believe aren't safe:
2535b2c4190SRobert Mustacchi  *
2545b2c4190SRobert Mustacchi  *   (8) RP --> Switch --> EP
2555b2c4190SRobert Mustacchi  *                    +--> EP
2565b2c4190SRobert Mustacchi  *               (HP) +--> EP
2575b2c4190SRobert Mustacchi  *
2585b2c4190SRobert Mustacchi  *   (9) RP --> Switch (HP) +--> EP
2595b2c4190SRobert Mustacchi  *                     (HP) +--> EP
2605b2c4190SRobert Mustacchi  *
2615b2c4190SRobert Mustacchi  *   (10) RP (HP) --> Switch (HP) +--> EP
2625b2c4190SRobert Mustacchi  *                           (HP) +--> EP
2635b2c4190SRobert Mustacchi  *
2645b2c4190SRobert Mustacchi  * All of these are situations where it's much more explicitly unsafe. Let's
2655b2c4190SRobert Mustacchi  * take (8). The problem here is that the devices on the non-hotpluggable
2665b2c4190SRobert Mustacchi  * downstream switches are always there and we should assume all device drivers
2675b2c4190SRobert Mustacchi  * will be active and performing I/O when the hot-pluggable slot changes. If the
2685b2c4190SRobert Mustacchi  * hot-pluggable slot has a lower max payload size, then we're mostly out of
2695b2c4190SRobert Mustacchi  * luck. The case of (9) is very similar to (8), just that we have more hot-plug
2705b2c4190SRobert Mustacchi  * capable slots.
2715b2c4190SRobert Mustacchi  *
2725b2c4190SRobert Mustacchi  * Finally (10) is a case of multiple instances of hotplug. (9) and (10) are the
2735b2c4190SRobert Mustacchi  * more general case of (6) and (7). While we can try to detect (6) and (7) more
2745b2c4190SRobert Mustacchi  * generally or try to make it safe, we're going to start with a simpler form of
2755b2c4190SRobert Mustacchi  * detection for this, which roughly follows the following rules:
2765b2c4190SRobert Mustacchi  *
2775b2c4190SRobert Mustacchi  *   o If there are no hot-pluggable slots in an entire fabric, then we can set
2785b2c4190SRobert Mustacchi  *     all fabric properties based on device capabilities.
2795b2c4190SRobert Mustacchi  *   o If we encounter a hot-pluggable slot, we can only set fabric properties
2805b2c4190SRobert Mustacchi  *     based on device capabilities if:
2815b2c4190SRobert Mustacchi  *
2825b2c4190SRobert Mustacchi  *       1. The hotpluggable slot is a root port.
2835b2c4190SRobert Mustacchi  *       2. There are no other hotpluggable devices downstream of it.
2845b2c4190SRobert Mustacchi  *
2855b2c4190SRobert Mustacchi  * Otherwise, if neither of the above is true, then we must use the basic PCIe
2865b2c4190SRobert Mustacchi  * defaults for various fabric-wide properties (discussed below). Even in these
2875b2c4190SRobert Mustacchi  * more complicated cases, device-specific properties such as the configuration
2885b2c4190SRobert Mustacchi  * of AERs, ASPM, etc. are still handled in the general pcie_init_bus() and
2895b2c4190SRobert Mustacchi  * related discussed earlier here.
2905b2c4190SRobert Mustacchi  *
2915b2c4190SRobert Mustacchi  * Because the only fabrics that we'll change are those that correspond to root
2925b2c4190SRobert Mustacchi  * ports, we will only call into the actual fabric feature setup when one of
2935b2c4190SRobert Mustacchi  * those changes. This has the side effect of simplifying locking. When we make
2945b2c4190SRobert Mustacchi  * changes here we need to be able to hold the entire device tree under the root
2955b2c4190SRobert Mustacchi  * port (including the root port and its parent). This is much harder to do
2965b2c4190SRobert Mustacchi  * safely when starting in the middle of the tree.
2975b2c4190SRobert Mustacchi  *
2985b2c4190SRobert Mustacchi  * Handling of Specific Properties
2995b2c4190SRobert Mustacchi  * -------------------------------
3005b2c4190SRobert Mustacchi  *
3015b2c4190SRobert Mustacchi  * This section goes into the rationale behind how we initialize and program
3025b2c4190SRobert Mustacchi  * various parts of the PCIe stack.
3035b2c4190SRobert Mustacchi  *
3045b2c4190SRobert Mustacchi  * 5-, 8-, 10- AND 14-BIT TAGS
3055b2c4190SRobert Mustacchi  *
3065b2c4190SRobert Mustacchi  * Tags are part of PCIe transactions and when combined with a device identifier
3075b2c4190SRobert Mustacchi  * are used to uniquely identify a transaction. In PCIe parlance, a Requester
3085b2c4190SRobert Mustacchi  * (someone who initiates a PCIe request) sets a unique tag in the request and
3095b2c4190SRobert Mustacchi  * the Completer (someone who processes and responds to a PCIe request) echoes
3105b2c4190SRobert Mustacchi  * the tag back. This means that a requester generally is responsible for
3115b2c4190SRobert Mustacchi  * ensuring that they don't reuse a tag between transactions.
3125b2c4190SRobert Mustacchi  *
3135b2c4190SRobert Mustacchi  * Thus the number of tags that a device has relates to the number of
3145b2c4190SRobert Mustacchi  * outstanding transactions that it can have, which are usually tied to the
3155b2c4190SRobert Mustacchi  * number of outstanding DMA transfers. The size of these transactions is also
3165b2c4190SRobert Mustacchi  * then scoped by the handling of the Maximum Packet Payload.
3175b2c4190SRobert Mustacchi  *
3185b2c4190SRobert Mustacchi  * In PCIe 1.0, devices default to a 5-bit tag. There was also an option to
3195b2c4190SRobert Mustacchi  * support an 8-bit tag. The 8-bit extended tag did not distinguish between a
3205b2c4190SRobert Mustacchi  * Requester or Completer. There was a bit to indicate device support of 8-bit
3215b2c4190SRobert Mustacchi  * tags in the Device Capabilities Register of the PCIe Capability and a
3225b2c4190SRobert Mustacchi  * separate bit to enable it in the Device Control Register of the PCIe
3235b2c4190SRobert Mustacchi  * Capability.
3245b2c4190SRobert Mustacchi  *
3255b2c4190SRobert Mustacchi  * In PCIe 4.0, support for a 10-bit tag was added. The specification broke
3265b2c4190SRobert Mustacchi  * apart the support bit into multiple pieces. In particular, in the Device
3275b2c4190SRobert Mustacchi  * Capabilities 2 register of the PCIe Capability there is a separate bit to
3285b2c4190SRobert Mustacchi  * indicate whether the device supports 10-bit completions and 10-bit requests.
3295b2c4190SRobert Mustacchi  * All PCIe 4.0 compliant devices are required to support 10-bit tags if they
3305b2c4190SRobert Mustacchi  * operate at 16.0 GT/s speed (a PCIe Gen 4 compliant device does not have to
3315b2c4190SRobert Mustacchi  * operate at Gen 4 speeds).
3325b2c4190SRobert Mustacchi  *
3335b2c4190SRobert Mustacchi  * This allows a device to support 10-bit completions but not 10-bit requests.
3345b2c4190SRobert Mustacchi  * A device that supports 10-bit requests is required to support 10-bit
3355b2c4190SRobert Mustacchi  * completions. There is no ability to enable or disable 10-bit completion
3365b2c4190SRobert Mustacchi  * support in the Device Capabilities 2 register. There is only a bit to enable
3375b2c4190SRobert Mustacchi  * 10-bit requests. This distinction makes our life easier as this means that as
3385b2c4190SRobert Mustacchi  * long as the entire fabric supports 10-bit completions, it doesn't matter if
3395b2c4190SRobert Mustacchi  * not all devices support 10-bit requests and we can enable them as required.
3405b2c4190SRobert Mustacchi  * More on this in a bit.
3415b2c4190SRobert Mustacchi  *
3425b2c4190SRobert Mustacchi  * In PCIe 6.0, another set of bits was added for 14-bit tags. These follow the
3435b2c4190SRobert Mustacchi  * same pattern as the 10-bit tags. The biggest difference is that the
3445b2c4190SRobert Mustacchi  * capabilities and control for these are found in the Device Capabilities 3
3455b2c4190SRobert Mustacchi  * and Device Control 3 register of the Device 3 Extended Capability. Similar to
3465b2c4190SRobert Mustacchi  * what we see with 10-bit tags, requesters are required to support the
3475b2c4190SRobert Mustacchi  * completer capability. The only control bit is for whether or not they enable
3485b2c4190SRobert Mustacchi  * a 14-bit requester.
3495b2c4190SRobert Mustacchi  *
3505b2c4190SRobert Mustacchi  * PCIe switches which sit between root ports and endpoints and show up to
3515b2c4190SRobert Mustacchi  * software as a set of bridges. Bridges generally don't have to know about tags
3525b2c4190SRobert Mustacchi  * as they are usually neither requesters or completers (unless directly talking
3535b2c4190SRobert Mustacchi  * to the bridge instance). That is they are generally required to forward
3545b2c4190SRobert Mustacchi  * packets without modifying them. This works until we deal with switch error
3555b2c4190SRobert Mustacchi  * handling. At that point, the switch may try to interpret the transaction and
3565b2c4190SRobert Mustacchi  * if it doesn't understand the tagging scheme in use, return the transaction to
3575b2c4190SRobert Mustacchi  * with the wrong tag and also an incorrectly diagnosed error (usually a
3585b2c4190SRobert Mustacchi  * malformed TLP).
3595b2c4190SRobert Mustacchi  *
3605b2c4190SRobert Mustacchi  * With all this, we construct a somewhat simple policy of how and when we
3615b2c4190SRobert Mustacchi  * enable extended tags:
3625b2c4190SRobert Mustacchi  *
3635b2c4190SRobert Mustacchi  *    o If we have a complex hotplug-capable fabric (based on the discussion
3645b2c4190SRobert Mustacchi  *      earlier in fabric-specific settings), then we cannot enable any of the
3655b2c4190SRobert Mustacchi  *      8-bit, 10-bit, and 14-bit tagging features. This is due to the issues
3665b2c4190SRobert Mustacchi  *      with intermediate PCIe switches and related.
3675b2c4190SRobert Mustacchi  *
3685b2c4190SRobert Mustacchi  *    o If every device supports 8-bit capable tags, then we will go through and
3695b2c4190SRobert Mustacchi  *      enable those everywhere.
3705b2c4190SRobert Mustacchi  *
3715b2c4190SRobert Mustacchi  *    o If every device supports 10-bit capable completions, then we will enable
3725b2c4190SRobert Mustacchi  *      10-bit requester on every device that supports it.
3735b2c4190SRobert Mustacchi  *
3745b2c4190SRobert Mustacchi  *    o If every device supports 14-bit capable completions, then we will enable
3755b2c4190SRobert Mustacchi  *      14-bit requesters on every device that supports it.
3765b2c4190SRobert Mustacchi  *
3775b2c4190SRobert Mustacchi  * This is the simpler end of the policy and one that is relatively easy to
3785b2c4190SRobert Mustacchi  * implement. While we could attempt to relax the constraint that every device
3795b2c4190SRobert Mustacchi  * in the fabric implement these features by making assumptions about peer-to-
3805b2c4190SRobert Mustacchi  * peer requests (that is devices at the same layer in the tree won't talk to
3815b2c4190SRobert Mustacchi  * one another), that is a lot of complexity. For now, we leave such an
3825b2c4190SRobert Mustacchi  * implementation to those who need it in the future.
3835b2c4190SRobert Mustacchi  *
3845b2c4190SRobert Mustacchi  * MAX PAYLOAD SIZE
3855b2c4190SRobert Mustacchi  *
3865b2c4190SRobert Mustacchi  * When performing transactions on the PCIe bus, a given transaction has a
3875b2c4190SRobert Mustacchi  * maximum allowed size. This size is called the MPS or 'Maximum Payload Size'.
3885b2c4190SRobert Mustacchi  * A given device reports its maximum supported size in the Device Capabilities
3895b2c4190SRobert Mustacchi  * register of the PCIe Capability. It is then set in the Device Control
3905b2c4190SRobert Mustacchi  * register.
3915b2c4190SRobert Mustacchi  *
3925b2c4190SRobert Mustacchi  * One of the challenges with this value is that different functions of a device
3935b2c4190SRobert Mustacchi  * have independent values, but strictly speaking are required to actually have
3945b2c4190SRobert Mustacchi  * the same value programmed in all of them lest device behavior goes awry. When
3955b2c4190SRobert Mustacchi  * a device has the ARI (alternative routing ID) capability enabled, then only
3965b2c4190SRobert Mustacchi  * function 0 controls the actual payload size.
3975b2c4190SRobert Mustacchi  *
3985b2c4190SRobert Mustacchi  * The settings for this need to be consistent throughout the fabric. A
3995b2c4190SRobert Mustacchi  * Transmitter is not allowed to create a TLP that exceeds its maximum packet
4005b2c4190SRobert Mustacchi  * size and a Receiver is not allowed to receive a packet that exceeds its
4015b2c4190SRobert Mustacchi  * maximum packet size. In all of these cases, this would result in something
4025b2c4190SRobert Mustacchi  * like a malformed TLP error.
4035b2c4190SRobert Mustacchi  *
4045b2c4190SRobert Mustacchi  * Effectively, this means that everything on a given fabric must have the same
4055b2c4190SRobert Mustacchi  * value programmed in its Device Control register for this value. While in the
4065b2c4190SRobert Mustacchi  * case of tags, switches generally weren't completers or requesters, here every
4075b2c4190SRobert Mustacchi  * device along the path is subject to this. This makes the actual value that we
4085b2c4190SRobert Mustacchi  * set throughout the fabric even more important and the constraints of hotplug
4095b2c4190SRobert Mustacchi  * even worse to deal with.
4105b2c4190SRobert Mustacchi  *
4115b2c4190SRobert Mustacchi  * Because a hotplug device can be inserted with any packet size, if we hit
4125b2c4190SRobert Mustacchi  * anything other than the simple hotplug cases discussed in the fabric-specific
4135b2c4190SRobert Mustacchi  * settings section, then we must use the smallest size of 128 byte payloads.
4145b2c4190SRobert Mustacchi  * This is because a device could be plugged in that supports something smaller
4155b2c4190SRobert Mustacchi  * than we had otherwise set. If there are other active devices, those could not
4165b2c4190SRobert Mustacchi  * be changed without quiescing the entire fabric. As such our algorithm is as
4175b2c4190SRobert Mustacchi  * follows:
4185b2c4190SRobert Mustacchi  *
4195b2c4190SRobert Mustacchi  *     1. Scan the entire fabric, keeping track of the smallest seen MPS in the
4205b2c4190SRobert Mustacchi  *        Device Capabilities Register.
4215b2c4190SRobert Mustacchi  *     2. If we have a complex fabric, program each Device Control register with
4225b2c4190SRobert Mustacchi  *        a 128 byte maximum payload size, otherwise, program it with the
4235b2c4190SRobert Mustacchi  *        discovered value.
4245b2c4190SRobert Mustacchi  *
4255b2c4190SRobert Mustacchi  *
4265b2c4190SRobert Mustacchi  * MAX READ REQUEST SIZE
4275b2c4190SRobert Mustacchi  *
4285b2c4190SRobert Mustacchi  * The maximum read request size (mrrs) is a much more confusing thing when
4295b2c4190SRobert Mustacchi  * compared to the maximum payload size counterpart. The maximum payload size
4305b2c4190SRobert Mustacchi  * (MPS) above is what restricts the actual size of a TLP. The mrrs value
4315b2c4190SRobert Mustacchi  * is used to control part of the behavior of Memory Read Request, which is not
4325b2c4190SRobert Mustacchi  * strictly speaking subject to the MPS. A PCIe device is allowed to respond to
4335b2c4190SRobert Mustacchi  * a Memory Read Request with less bytes than were actually requested in a
4345b2c4190SRobert Mustacchi  * single completion. In general, the default size that a root complex and its
4355b2c4190SRobert Mustacchi  * root port will reply to are based around the length of a cache line.
4365b2c4190SRobert Mustacchi  *
4375b2c4190SRobert Mustacchi  * What this ultimately controls is the number of requests that the Requester
4385b2c4190SRobert Mustacchi  * has to make and trades off bandwidth, bus sharing, and related here. For
4395b2c4190SRobert Mustacchi  * example, if the maximum read request size is 4 KiB, then the requester would
4405b2c4190SRobert Mustacchi  * only issue a single read request asking for 4 KiB. It would still receive
4415b2c4190SRobert Mustacchi  * these as multiple packets in units of the MPS. If however, the maximum read
4425b2c4190SRobert Mustacchi  * request was only say 512 B, then it would need to make 8 separate requests,
4435b2c4190SRobert Mustacchi  * potentially increasing latency. On the other hand, if systems are relying on
4445b2c4190SRobert Mustacchi  * total requests for QoS, then it's important to set it to something that's
4455b2c4190SRobert Mustacchi  * closer to the actual MPS.
4465b2c4190SRobert Mustacchi  *
4475b2c4190SRobert Mustacchi  * Traditionally, the OS has not been the most straightforward about this. It's
4485b2c4190SRobert Mustacchi  * important to remember that setting this up is also somewhat in the realm of
4495b2c4190SRobert Mustacchi  * system firmware. Due to the PCI Firmware specification, the firmware may have
4505b2c4190SRobert Mustacchi  * set up a value for not just the MRRS but also the MPS. As such, our logic
4515b2c4190SRobert Mustacchi  * basically left the MRRS alone and used whatever the device had there as long
4525b2c4190SRobert Mustacchi  * as we weren't shrinking the device's MPS. If we were, then we'd set it to the
4535b2c4190SRobert Mustacchi  * MPS. If the device was a root port, then it was just left at a system wide
4545b2c4190SRobert Mustacchi  * and PCIe default of 512 bytes.
4555b2c4190SRobert Mustacchi  *
4565b2c4190SRobert Mustacchi  * If we survey firmware (which isn't easy due to its nature), we have seen most
4575b2c4190SRobert Mustacchi  * cases where the firmware just doesn't do anything and leaves it to the
4585b2c4190SRobert Mustacchi  * device's default, which is basically just the PCIe default, unless it has a
4595b2c4190SRobert Mustacchi  * specific knowledge of something like say wanting to do something for an NVMe
4605b2c4190SRobert Mustacchi  * device. The same is generally true of other systems, leaving it at its
4615b2c4190SRobert Mustacchi  * default unless otherwise set by a device driver.
4625b2c4190SRobert Mustacchi  *
4635b2c4190SRobert Mustacchi  * Because this value doesn't really have the same constraints as other fabric
4645b2c4190SRobert Mustacchi  * properties, this becomes much simpler and we instead opt to set it as part of
4655b2c4190SRobert Mustacchi  * the device node initialization. In addition, there are no real rules about
4665b2c4190SRobert Mustacchi  * different functions having different values here as it doesn't really impact
4675b2c4190SRobert Mustacchi  * the TLP processing the same way that the MPS does.
4685b2c4190SRobert Mustacchi  *
4695b2c4190SRobert Mustacchi  * While we should add a fuller way of setting this and allowing operator
4705b2c4190SRobert Mustacchi  * override of the MRRS based on things like device class, etc. that is driven
4715b2c4190SRobert Mustacchi  * by pcieadm, that is left to the future. For now we opt to that all devices
4725b2c4190SRobert Mustacchi  * are kept at their default (512 bytes or whatever firmware left behind) and we
4735b2c4190SRobert Mustacchi  * ensure that root ports always have the mrrs set to 512.
4745b2c4190SRobert Mustacchi  */
4755b2c4190SRobert Mustacchi 
476f8d2de6bSjchu #include <sys/sysmacros.h>
477f8d2de6bSjchu #include <sys/types.h>
478f8d2de6bSjchu #include <sys/kmem.h>
479f8d2de6bSjchu #include <sys/modctl.h>
480f8d2de6bSjchu #include <sys/ddi.h>
481f8d2de6bSjchu #include <sys/sunddi.h>
482f8d2de6bSjchu #include <sys/sunndi.h>
483bf8fc234Set #include <sys/fm/protocol.h>
484bf8fc234Set #include <sys/fm/util.h>
485bf8fc234Set #include <sys/promif.h>
486bf8fc234Set #include <sys/disp.h>
48726947304SEvan Yan #include <sys/stat.h>
48826947304SEvan Yan #include <sys/file.h>
48927255037Spjha #include <sys/pci_cap.h>
49026947304SEvan Yan #include <sys/pci_impl.h>
491f8d2de6bSjchu #include <sys/pcie_impl.h>
49226947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
49370f83219SEvan Yan #include <sys/hotplug/pci/pciehpc.h>
49470f83219SEvan Yan #include <sys/hotplug/pci/pcishpc.h>
49526947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h>
496c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
497b3d69c05SRobert Mustacchi #include <sys/sysevent.h>
498b3d69c05SRobert Mustacchi #include <sys/sysevent/eventdefs.h>
499b3d69c05SRobert Mustacchi #include <sys/sysevent/pcie.h>
500f8d2de6bSjchu 
50126947304SEvan Yan /* Local functions prototypes */
502eae2e508Skrishnae static void pcie_init_pfd(dev_info_t *);
503eae2e508Skrishnae static void pcie_fini_pfd(dev_info_t *);
504f8d2de6bSjchu 
505fc51f9bbSKrishna Elango #ifdef DEBUG
506f8d2de6bSjchu uint_t pcie_debug_flags = 0;
507eae2e508Skrishnae static void pcie_print_bus(pcie_bus_t *bus_p);
50826947304SEvan Yan void pcie_dbg(char *fmt, ...);
509fc51f9bbSKrishna Elango #endif /* DEBUG */
510f8d2de6bSjchu 
511f8d2de6bSjchu /* Variable to control default PCI-Express config settings */
512eae2e508Skrishnae ushort_t pcie_command_default =
513eae2e508Skrishnae     PCI_COMM_SERR_ENABLE |
514eae2e508Skrishnae     PCI_COMM_WAIT_CYC_ENAB |
515eae2e508Skrishnae     PCI_COMM_PARITY_DETECT |
516eae2e508Skrishnae     PCI_COMM_ME |
517eae2e508Skrishnae     PCI_COMM_MAE |
518eae2e508Skrishnae     PCI_COMM_IO;
519eae2e508Skrishnae 
520eae2e508Skrishnae /* xxx_fw are bits that are controlled by FW and should not be modified */
521eae2e508Skrishnae ushort_t pcie_command_default_fw =
522eae2e508Skrishnae     PCI_COMM_SPEC_CYC |
523eae2e508Skrishnae     PCI_COMM_MEMWR_INVAL |
524eae2e508Skrishnae     PCI_COMM_PALETTE_SNOOP |
525eae2e508Skrishnae     PCI_COMM_WAIT_CYC_ENAB |
526eae2e508Skrishnae     0xF800; /* Reserved Bits */
527eae2e508Skrishnae 
528eae2e508Skrishnae ushort_t pcie_bdg_command_default_fw =
529eae2e508Skrishnae     PCI_BCNF_BCNTRL_ISA_ENABLE |
530eae2e508Skrishnae     PCI_BCNF_BCNTRL_VGA_ENABLE |
531eae2e508Skrishnae     0xF000; /* Reserved Bits */
532eae2e508Skrishnae 
533eae2e508Skrishnae /* PCI-Express Base error defaults */
534eae2e508Skrishnae ushort_t pcie_base_err_default =
535eae2e508Skrishnae     PCIE_DEVCTL_CE_REPORTING_EN |
536eae2e508Skrishnae     PCIE_DEVCTL_NFE_REPORTING_EN |
537eae2e508Skrishnae     PCIE_DEVCTL_FE_REPORTING_EN |
538eae2e508Skrishnae     PCIE_DEVCTL_UR_REPORTING_EN;
539eae2e508Skrishnae 
540eae2e508Skrishnae /* PCI-Express Device Control Register */
5410114761dSAlan Adamson, SD OSSD uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
542eae2e508Skrishnae     PCIE_DEVCTL_MAX_READ_REQ_512;
543eae2e508Skrishnae 
544eae2e508Skrishnae /* PCI-Express AER Root Control Register */
545eae2e508Skrishnae #define	PCIE_ROOT_SYS_ERR	(PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
546eae2e508Skrishnae 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
547eae2e508Skrishnae 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
548eae2e508Skrishnae 
549eae2e508Skrishnae ushort_t pcie_root_ctrl_default =
550eae2e508Skrishnae     PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
551eae2e508Skrishnae     PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
552eae2e508Skrishnae     PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
553eae2e508Skrishnae 
554eae2e508Skrishnae /* PCI-Express Root Error Command Register */
555eae2e508Skrishnae ushort_t pcie_root_error_cmd_default =
556eae2e508Skrishnae     PCIE_AER_RE_CMD_CE_REP_EN |
557eae2e508Skrishnae     PCIE_AER_RE_CMD_NFE_REP_EN |
558eae2e508Skrishnae     PCIE_AER_RE_CMD_FE_REP_EN;
559eae2e508Skrishnae 
560eae2e508Skrishnae /* ECRC settings in the PCIe AER Control Register */
561eae2e508Skrishnae uint32_t pcie_ecrc_value =
562eae2e508Skrishnae     PCIE_AER_CTL_ECRC_GEN_ENA |
563eae2e508Skrishnae     PCIE_AER_CTL_ECRC_CHECK_ENA;
564eae2e508Skrishnae 
565eae2e508Skrishnae /*
566eae2e508Skrishnae  * If a particular platform wants to disable certain errors such as UR/MA,
567eae2e508Skrishnae  * instead of using #defines have the platform's PCIe Root Complex driver set
568eae2e508Skrishnae  * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions.  For
56926947304SEvan Yan  * x86 the closest thing to a PCIe root complex driver is NPE.	For SPARC the
570eae2e508Skrishnae  * closest PCIe root complex driver is PX.
571eae2e508Skrishnae  *
572eae2e508Skrishnae  * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
573eae2e508Skrishnae  * systems may want to disable SERR in general.  For root ports, enabling SERR
574eae2e508Skrishnae  * causes NMIs which are not handled and results in a watchdog timeout error.
575eae2e508Skrishnae  */
576eae2e508Skrishnae uint32_t pcie_aer_uce_mask = 0;		/* AER UE Mask */
577eae2e508Skrishnae uint32_t pcie_aer_ce_mask = 0;		/* AER CE Mask */
578eae2e508Skrishnae uint32_t pcie_aer_suce_mask = 0;	/* AER Secondary UE Mask */
579eae2e508Skrishnae uint32_t pcie_serr_disable_flag = 0;	/* Disable SERR */
580eae2e508Skrishnae 
581eae2e508Skrishnae /* Default severities needed for eversholt.  Error handling doesn't care */
582eae2e508Skrishnae uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
583eae2e508Skrishnae     PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
584eae2e508Skrishnae     PCIE_AER_UCE_TRAINING;
585eae2e508Skrishnae uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
586eae2e508Skrishnae     PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
587eae2e508Skrishnae     PCIE_AER_SUCE_USC_MSG_DATA_ERR;
588f8d2de6bSjchu 
58926947304SEvan Yan int pcie_disable_ari = 0;
5900114761dSAlan Adamson, SD OSSD 
591f7afc1fdSRobert Mustacchi /*
592f7afc1fdSRobert Mustacchi  * On some platforms, such as the AMD B450 chipset, we've seen an odd
593f7afc1fdSRobert Mustacchi  * relationship between enabling link bandwidth notifications and AERs about
594f7afc1fdSRobert Mustacchi  * ECRC errors. This provides a mechanism to disable it.
595f7afc1fdSRobert Mustacchi  */
596f7afc1fdSRobert Mustacchi int pcie_disable_lbw = 0;
597f7afc1fdSRobert Mustacchi 
598b3d69c05SRobert Mustacchi /*
599b3d69c05SRobert Mustacchi  * Amount of time to wait for an in-progress retraining. The default is to try
600b3d69c05SRobert Mustacchi  * 500 times in 10ms chunks, thus a total of 5s.
601b3d69c05SRobert Mustacchi  */
602b3d69c05SRobert Mustacchi uint32_t pcie_link_retrain_count = 500;
603b3d69c05SRobert Mustacchi uint32_t pcie_link_retrain_delay_ms = 10;
604b3d69c05SRobert Mustacchi 
605b3d69c05SRobert Mustacchi taskq_t *pcie_link_tq;
606b3d69c05SRobert Mustacchi kmutex_t pcie_link_tq_mutex;
607b3d69c05SRobert Mustacchi 
608b3d69c05SRobert Mustacchi static int pcie_link_bw_intr(dev_info_t *);
609b3d69c05SRobert Mustacchi static void pcie_capture_speeds(dev_info_t *);
6100114761dSAlan Adamson, SD OSSD 
611c0da6274SZhi-Jun Robin Fu dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
612c0da6274SZhi-Jun Robin Fu 
613f8d2de6bSjchu /*
614f8d2de6bSjchu  * modload support
615f8d2de6bSjchu  */
616e8ed0869SJohn Beck 
617e8ed0869SJohn Beck static struct modlmisc modlmisc	= {
618f8d2de6bSjchu 	&mod_miscops,	/* Type	of module */
61926947304SEvan Yan 	"PCI Express Framework Module"
620f8d2de6bSjchu };
621f8d2de6bSjchu 
622e8ed0869SJohn Beck static struct modlinkage modlinkage = {
623f8d2de6bSjchu 	MODREV_1,
624f8d2de6bSjchu 	(void	*)&modlmisc,
625f8d2de6bSjchu 	NULL
626f8d2de6bSjchu };
627f8d2de6bSjchu 
628eae2e508Skrishnae /*
629eae2e508Skrishnae  * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
630eae2e508Skrishnae  * Currently used to send the pci.fabric ereports whose payload depends on the
631eae2e508Skrishnae  * type of PCI device it is being sent for.
632eae2e508Skrishnae  */
633eae2e508Skrishnae char		*pcie_nv_buf;
634eae2e508Skrishnae nv_alloc_t	*pcie_nvap;
635eae2e508Skrishnae nvlist_t	*pcie_nvl;
636eae2e508Skrishnae 
637f8d2de6bSjchu int
_init(void)638f8d2de6bSjchu _init(void)
639f8d2de6bSjchu {
640f8d2de6bSjchu 	int rval;
641f8d2de6bSjchu 
642eae2e508Skrishnae 	pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
643eae2e508Skrishnae 	pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
644eae2e508Skrishnae 	pcie_nvl = fm_nvlist_create(pcie_nvap);
645b3d69c05SRobert Mustacchi 	mutex_init(&pcie_link_tq_mutex, NULL, MUTEX_DRIVER, NULL);
646eae2e508Skrishnae 
647c92295a9SAn Bui 	if ((rval = mod_install(&modlinkage)) != 0) {
648b3d69c05SRobert Mustacchi 		mutex_destroy(&pcie_link_tq_mutex);
649c92295a9SAn Bui 		fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
650c92295a9SAn Bui 		fm_nva_xdestroy(pcie_nvap);
651c92295a9SAn Bui 		kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
652c92295a9SAn Bui 	}
653f8d2de6bSjchu 	return (rval);
654f8d2de6bSjchu }
655f8d2de6bSjchu 
656f8d2de6bSjchu int
_fini()657f8d2de6bSjchu _fini()
658f8d2de6bSjchu {
659f8d2de6bSjchu 	int		rval;
660f8d2de6bSjchu 
661c92295a9SAn Bui 	if ((rval = mod_remove(&modlinkage)) == 0) {
662b3d69c05SRobert Mustacchi 		if (pcie_link_tq != NULL) {
663b3d69c05SRobert Mustacchi 			taskq_destroy(pcie_link_tq);
664b3d69c05SRobert Mustacchi 		}
665b3d69c05SRobert Mustacchi 		mutex_destroy(&pcie_link_tq_mutex);
666c92295a9SAn Bui 		fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
667c92295a9SAn Bui 		fm_nva_xdestroy(pcie_nvap);
668c92295a9SAn Bui 		kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
669c92295a9SAn Bui 	}
670f8d2de6bSjchu 	return (rval);
671f8d2de6bSjchu }
672f8d2de6bSjchu 
673f8d2de6bSjchu int
_info(struct modinfo * modinfop)674f8d2de6bSjchu _info(struct modinfo *modinfop)
675f8d2de6bSjchu {
676f8d2de6bSjchu 	return (mod_info(&modlinkage, modinfop));
677f8d2de6bSjchu }
678f8d2de6bSjchu 
67926947304SEvan Yan /* ARGSUSED */
68026947304SEvan Yan int
pcie_init(dev_info_t * dip,caddr_t arg)68126947304SEvan Yan pcie_init(dev_info_t *dip, caddr_t arg)
68226947304SEvan Yan {
68326947304SEvan Yan 	int	ret = DDI_SUCCESS;
68426947304SEvan Yan 
685b3d69c05SRobert Mustacchi 	/*
686b3d69c05SRobert Mustacchi 	 * Our _init function is too early to create a taskq. Create the pcie
687b3d69c05SRobert Mustacchi 	 * link management taskq here now instead.
688b3d69c05SRobert Mustacchi 	 */
689b3d69c05SRobert Mustacchi 	mutex_enter(&pcie_link_tq_mutex);
690b3d69c05SRobert Mustacchi 	if (pcie_link_tq == NULL) {
691b3d69c05SRobert Mustacchi 		pcie_link_tq = taskq_create("pcie_link", 1, minclsyspri, 0, 0,
692b3d69c05SRobert Mustacchi 		    0);
693b3d69c05SRobert Mustacchi 	}
694b3d69c05SRobert Mustacchi 	mutex_exit(&pcie_link_tq_mutex);
695b3d69c05SRobert Mustacchi 
696b3d69c05SRobert Mustacchi 
69726947304SEvan Yan 	/*
69826947304SEvan Yan 	 * Create a "devctl" minor node to support DEVCTL_DEVICE_*
69926947304SEvan Yan 	 * and DEVCTL_BUS_* ioctls to this bus.
70026947304SEvan Yan 	 */
70126947304SEvan Yan 	if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
70226947304SEvan Yan 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
70326947304SEvan Yan 	    DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
70426947304SEvan Yan 		PCIE_DBG("Failed to create devctl minor node for %s%d\n",
70526947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
70626947304SEvan Yan 
70726947304SEvan Yan 		return (ret);
70826947304SEvan Yan 	}
70926947304SEvan Yan 
71026947304SEvan Yan 	if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
71126947304SEvan Yan 		/*
712ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * On some x86 platforms, we observed unexpected hotplug
713ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * initialization failures in recent years. The known cause
714ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * is a hardware issue: while the problem PCI bridges have
715ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * the Hotplug Capable registers set, the machine actually
716ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * does not implement the expected ACPI object.
717ed11b501SColin Zou - Sun Microsystems - Beijing China 		 *
718ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * We don't want to stop PCI driver attach and system boot
719ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * just because of this hotplug initialization failure.
720ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * Continue with a debug message printed.
72126947304SEvan Yan 		 */
722ed11b501SColin Zou - Sun Microsystems - Beijing China 		PCIE_DBG("%s%d: Failed setting hotplug framework\n",
72326947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
72426947304SEvan Yan 
72526947304SEvan Yan #if defined(__sparc)
72626947304SEvan Yan 		ddi_remove_minor_node(dip, "devctl");
72726947304SEvan Yan 
72826947304SEvan Yan 		return (ret);
72926947304SEvan Yan #endif /* defined(__sparc) */
73026947304SEvan Yan 	}
73126947304SEvan Yan 
73226947304SEvan Yan 	return (DDI_SUCCESS);
73326947304SEvan Yan }
73426947304SEvan Yan 
73526947304SEvan Yan /* ARGSUSED */
73626947304SEvan Yan int
pcie_uninit(dev_info_t * dip)73726947304SEvan Yan pcie_uninit(dev_info_t *dip)
73826947304SEvan Yan {
73926947304SEvan Yan 	int	ret = DDI_SUCCESS;
74026947304SEvan Yan 
74126947304SEvan Yan 	if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
74226947304SEvan Yan 		(void) pcie_ari_disable(dip);
74326947304SEvan Yan 
74426947304SEvan Yan 	if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
74526947304SEvan Yan 		PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
74626947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
74726947304SEvan Yan 
74826947304SEvan Yan 		return (ret);
74926947304SEvan Yan 	}
75026947304SEvan Yan 
751b3d69c05SRobert Mustacchi 	if (pcie_link_bw_supported(dip)) {
752b3d69c05SRobert Mustacchi 		(void) pcie_link_bw_disable(dip);
753b3d69c05SRobert Mustacchi 	}
754b3d69c05SRobert Mustacchi 
75526947304SEvan Yan 	ddi_remove_minor_node(dip, "devctl");
75626947304SEvan Yan 
75726947304SEvan Yan 	return (ret);
75826947304SEvan Yan }
75926947304SEvan Yan 
76070f83219SEvan Yan /*
76170f83219SEvan Yan  * PCIe module interface for enabling hotplug interrupt.
76270f83219SEvan Yan  *
76370f83219SEvan Yan  * It should be called after pcie_init() is done and bus driver's
76470f83219SEvan Yan  * interrupt handlers have being attached.
76570f83219SEvan Yan  */
76670f83219SEvan Yan int
pcie_hpintr_enable(dev_info_t * dip)76770f83219SEvan Yan pcie_hpintr_enable(dev_info_t *dip)
76870f83219SEvan Yan {
76970f83219SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
77070f83219SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = PCIE_GET_HP_CTRL(dip);
77170f83219SEvan Yan 
77270f83219SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
77370f83219SEvan Yan 		(void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
77470f83219SEvan Yan 	} else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
77570f83219SEvan Yan 		(void) pcishpc_enable_irqs(ctrl_p);
77670f83219SEvan Yan 	}
77770f83219SEvan Yan 	return (DDI_SUCCESS);
77870f83219SEvan Yan }
77970f83219SEvan Yan 
78070f83219SEvan Yan /*
78170f83219SEvan Yan  * PCIe module interface for disabling hotplug interrupt.
78270f83219SEvan Yan  *
78370f83219SEvan Yan  * It should be called before pcie_uninit() is called and bus driver's
78470f83219SEvan Yan  * interrupt handlers is dettached.
78570f83219SEvan Yan  */
78670f83219SEvan Yan int
pcie_hpintr_disable(dev_info_t * dip)78770f83219SEvan Yan pcie_hpintr_disable(dev_info_t *dip)
78870f83219SEvan Yan {
78970f83219SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
79070f83219SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = PCIE_GET_HP_CTRL(dip);
79170f83219SEvan Yan 
79270f83219SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
79370f83219SEvan Yan 		(void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
79470f83219SEvan Yan 	} else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
79570f83219SEvan Yan 		(void) pcishpc_disable_irqs(ctrl_p);
79670f83219SEvan Yan 	}
79770f83219SEvan Yan 	return (DDI_SUCCESS);
79870f83219SEvan Yan }
79970f83219SEvan Yan 
80026947304SEvan Yan /* ARGSUSED */
80126947304SEvan Yan int
pcie_intr(dev_info_t * dip)80226947304SEvan Yan pcie_intr(dev_info_t *dip)
80326947304SEvan Yan {
804b3d69c05SRobert Mustacchi 	int hp, lbw;
805b3d69c05SRobert Mustacchi 
806b3d69c05SRobert Mustacchi 	hp = pcie_hp_intr(dip);
807b3d69c05SRobert Mustacchi 	lbw = pcie_link_bw_intr(dip);
808b3d69c05SRobert Mustacchi 
809b3d69c05SRobert Mustacchi 	if (hp == DDI_INTR_CLAIMED || lbw == DDI_INTR_CLAIMED) {
810b3d69c05SRobert Mustacchi 		return (DDI_INTR_CLAIMED);
811b3d69c05SRobert Mustacchi 	}
812b3d69c05SRobert Mustacchi 
813b3d69c05SRobert Mustacchi 	return (DDI_INTR_UNCLAIMED);
81426947304SEvan Yan }
81526947304SEvan Yan 
81626947304SEvan Yan /* ARGSUSED */
81726947304SEvan Yan int
pcie_open(dev_info_t * dip,dev_t * devp,int flags,int otyp,cred_t * credp)81826947304SEvan Yan pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
81926947304SEvan Yan {
82026947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
82126947304SEvan Yan 
82226947304SEvan Yan 	/*
82326947304SEvan Yan 	 * Make sure the open is for the right file type.
82426947304SEvan Yan 	 */
82526947304SEvan Yan 	if (otyp != OTYP_CHR)
82626947304SEvan Yan 		return (EINVAL);
82726947304SEvan Yan 
82826947304SEvan Yan 	/*
82926947304SEvan Yan 	 * Handle the open by tracking the device state.
83026947304SEvan Yan 	 */
83126947304SEvan Yan 	if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
83226947304SEvan Yan 	    ((flags & FEXCL) &&
83326947304SEvan Yan 	    (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
83426947304SEvan Yan 		return (EBUSY);
83526947304SEvan Yan 	}
83626947304SEvan Yan 
83726947304SEvan Yan 	if (flags & FEXCL)
83826947304SEvan Yan 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
83926947304SEvan Yan 	else
84026947304SEvan Yan 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
84126947304SEvan Yan 
84226947304SEvan Yan 	return (0);
84326947304SEvan Yan }
84426947304SEvan Yan 
84526947304SEvan Yan /* ARGSUSED */
84626947304SEvan Yan int
pcie_close(dev_info_t * dip,dev_t dev,int flags,int otyp,cred_t * credp)84726947304SEvan Yan pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
84826947304SEvan Yan {
84926947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
85026947304SEvan Yan 
85126947304SEvan Yan 	if (otyp != OTYP_CHR)
85226947304SEvan Yan 		return (EINVAL);
85326947304SEvan Yan 
85426947304SEvan Yan 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
85526947304SEvan Yan 
85626947304SEvan Yan 	return (0);
85726947304SEvan Yan }
85826947304SEvan Yan 
85926947304SEvan Yan /* ARGSUSED */
86026947304SEvan Yan int
pcie_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)86126947304SEvan Yan pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
86226947304SEvan Yan     cred_t *credp, int *rvalp)
86326947304SEvan Yan {
86426947304SEvan Yan 	struct devctl_iocdata	*dcp;
86526947304SEvan Yan 	uint_t			bus_state;
86626947304SEvan Yan 	int			rv = DDI_SUCCESS;
86726947304SEvan Yan 
86826947304SEvan Yan 	/*
86926947304SEvan Yan 	 * We can use the generic implementation for devctl ioctl
87026947304SEvan Yan 	 */
87126947304SEvan Yan 	switch (cmd) {
87226947304SEvan Yan 	case DEVCTL_DEVICE_GETSTATE:
87326947304SEvan Yan 	case DEVCTL_DEVICE_ONLINE:
87426947304SEvan Yan 	case DEVCTL_DEVICE_OFFLINE:
87526947304SEvan Yan 	case DEVCTL_BUS_GETSTATE:
87626947304SEvan Yan 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
87726947304SEvan Yan 	default:
87826947304SEvan Yan 		break;
87926947304SEvan Yan 	}
88026947304SEvan Yan 
88126947304SEvan Yan 	/*
88226947304SEvan Yan 	 * read devctl ioctl data
88326947304SEvan Yan 	 */
88426947304SEvan Yan 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
88526947304SEvan Yan 		return (EFAULT);
88626947304SEvan Yan 
88726947304SEvan Yan 	switch (cmd) {
88826947304SEvan Yan 	case DEVCTL_BUS_QUIESCE:
88926947304SEvan Yan 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
89026947304SEvan Yan 			if (bus_state == BUS_QUIESCED)
89126947304SEvan Yan 				break;
89226947304SEvan Yan 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
89326947304SEvan Yan 		break;
89426947304SEvan Yan 	case DEVCTL_BUS_UNQUIESCE:
89526947304SEvan Yan 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
89626947304SEvan Yan 			if (bus_state == BUS_ACTIVE)
89726947304SEvan Yan 				break;
89826947304SEvan Yan 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
89926947304SEvan Yan 		break;
90026947304SEvan Yan 	case DEVCTL_BUS_RESET:
90126947304SEvan Yan 	case DEVCTL_BUS_RESETALL:
90226947304SEvan Yan 	case DEVCTL_DEVICE_RESET:
90326947304SEvan Yan 		rv = ENOTSUP;
90426947304SEvan Yan 		break;
90526947304SEvan Yan 	default:
90626947304SEvan Yan 		rv = ENOTTY;
90726947304SEvan Yan 	}
90826947304SEvan Yan 
90926947304SEvan Yan 	ndi_dc_freehdl(dcp);
91026947304SEvan Yan 	return (rv);
91126947304SEvan Yan }
91226947304SEvan Yan 
91326947304SEvan Yan /* ARGSUSED */
91426947304SEvan Yan int
pcie_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)91526947304SEvan Yan pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
91626947304SEvan Yan     int flags, char *name, caddr_t valuep, int *lengthp)
91726947304SEvan Yan {
91826947304SEvan Yan 	if (dev == DDI_DEV_T_ANY)
91926947304SEvan Yan 		goto skip;
92026947304SEvan Yan 
92126947304SEvan Yan 	if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
92226947304SEvan Yan 	    strcmp(name, "pci-occupant") == 0) {
92326947304SEvan Yan 		int	pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
92426947304SEvan Yan 
92526947304SEvan Yan 		pcie_hp_create_occupant_props(dip, dev, pci_dev);
92626947304SEvan Yan 	}
92726947304SEvan Yan 
92826947304SEvan Yan skip:
92926947304SEvan Yan 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
93026947304SEvan Yan }
93126947304SEvan Yan 
932c0da6274SZhi-Jun Robin Fu int
pcie_init_cfghdl(dev_info_t * cdip)933c0da6274SZhi-Jun Robin Fu pcie_init_cfghdl(dev_info_t *cdip)
934c0da6274SZhi-Jun Robin Fu {
935c0da6274SZhi-Jun Robin Fu 	pcie_bus_t		*bus_p;
936c0da6274SZhi-Jun Robin Fu 	ddi_acc_handle_t	eh = NULL;
937c0da6274SZhi-Jun Robin Fu 
938c0da6274SZhi-Jun Robin Fu 	bus_p = PCIE_DIP2BUS(cdip);
939c0da6274SZhi-Jun Robin Fu 	if (bus_p == NULL)
940c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
941c0da6274SZhi-Jun Robin Fu 
942c0da6274SZhi-Jun Robin Fu 	/* Create an config access special to error handling */
943c0da6274SZhi-Jun Robin Fu 	if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
944c0da6274SZhi-Jun Robin Fu 		cmn_err(CE_WARN, "Cannot setup config access"
945c0da6274SZhi-Jun Robin Fu 		    " for BDF 0x%x\n", bus_p->bus_bdf);
946c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
947c0da6274SZhi-Jun Robin Fu 	}
948c0da6274SZhi-Jun Robin Fu 
949c0da6274SZhi-Jun Robin Fu 	bus_p->bus_cfg_hdl = eh;
950c0da6274SZhi-Jun Robin Fu 	return (DDI_SUCCESS);
951c0da6274SZhi-Jun Robin Fu }
952c0da6274SZhi-Jun Robin Fu 
953c0da6274SZhi-Jun Robin Fu void
pcie_fini_cfghdl(dev_info_t * cdip)954c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(dev_info_t *cdip)
955c0da6274SZhi-Jun Robin Fu {
956c0da6274SZhi-Jun Robin Fu 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(cdip);
957c0da6274SZhi-Jun Robin Fu 
958c0da6274SZhi-Jun Robin Fu 	pci_config_teardown(&bus_p->bus_cfg_hdl);
959c0da6274SZhi-Jun Robin Fu }
960c0da6274SZhi-Jun Robin Fu 
961826c0d1dSRobert Mustacchi void
pcie_determine_serial(dev_info_t * dip)962826c0d1dSRobert Mustacchi pcie_determine_serial(dev_info_t *dip)
963826c0d1dSRobert Mustacchi {
964826c0d1dSRobert Mustacchi 	pcie_bus_t		*bus_p = PCIE_DIP2BUS(dip);
965826c0d1dSRobert Mustacchi 	ddi_acc_handle_t	h;
966826c0d1dSRobert Mustacchi 	uint16_t		cap;
967826c0d1dSRobert Mustacchi 	uchar_t			serial[8];
968826c0d1dSRobert Mustacchi 	uint32_t		low, high;
969826c0d1dSRobert Mustacchi 
970826c0d1dSRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p))
971826c0d1dSRobert Mustacchi 		return;
972826c0d1dSRobert Mustacchi 
973826c0d1dSRobert Mustacchi 	h = bus_p->bus_cfg_hdl;
974826c0d1dSRobert Mustacchi 
975826c0d1dSRobert Mustacchi 	if ((PCI_CAP_LOCATE(h, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap)) ==
976826c0d1dSRobert Mustacchi 	    DDI_FAILURE)
977826c0d1dSRobert Mustacchi 		return;
978826c0d1dSRobert Mustacchi 
979826c0d1dSRobert Mustacchi 	high = PCI_XCAP_GET32(h, 0, cap, PCIE_SER_SID_UPPER_DW);
980826c0d1dSRobert Mustacchi 	low = PCI_XCAP_GET32(h, 0, cap, PCIE_SER_SID_LOWER_DW);
981826c0d1dSRobert Mustacchi 
982826c0d1dSRobert Mustacchi 	/*
983826c0d1dSRobert Mustacchi 	 * Here, we're trying to figure out if we had an invalid PCIe read. From
984826c0d1dSRobert Mustacchi 	 * looking at the contents of the value, it can be hard to tell the
985826c0d1dSRobert Mustacchi 	 * difference between a value that has all 1s correctly versus if we had
986826c0d1dSRobert Mustacchi 	 * an error. In this case, we only assume it's invalid if both register
987826c0d1dSRobert Mustacchi 	 * reads are invalid. We also only use 32-bit reads as we're not sure if
988826c0d1dSRobert Mustacchi 	 * all devices will support these as 64-bit reads, while we know that
989826c0d1dSRobert Mustacchi 	 * they'll support these as 32-bit reads.
990826c0d1dSRobert Mustacchi 	 */
991826c0d1dSRobert Mustacchi 	if (high == PCI_EINVAL32 && low == PCI_EINVAL32)
992826c0d1dSRobert Mustacchi 		return;
993826c0d1dSRobert Mustacchi 
994826c0d1dSRobert Mustacchi 	serial[0] = low & 0xff;
995826c0d1dSRobert Mustacchi 	serial[1] = (low >> 8) & 0xff;
996826c0d1dSRobert Mustacchi 	serial[2] = (low >> 16) & 0xff;
997826c0d1dSRobert Mustacchi 	serial[3] = (low >> 24) & 0xff;
998826c0d1dSRobert Mustacchi 	serial[4] = high & 0xff;
999826c0d1dSRobert Mustacchi 	serial[5] = (high >> 8) & 0xff;
1000826c0d1dSRobert Mustacchi 	serial[6] = (high >> 16) & 0xff;
1001826c0d1dSRobert Mustacchi 	serial[7] = (high >> 24) & 0xff;
1002826c0d1dSRobert Mustacchi 
1003826c0d1dSRobert Mustacchi 	(void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "pcie-serial",
1004826c0d1dSRobert Mustacchi 	    serial, sizeof (serial));
1005826c0d1dSRobert Mustacchi }
1006826c0d1dSRobert Mustacchi 
1007f7afc1fdSRobert Mustacchi static void
pcie_determine_aspm(dev_info_t * dip)1008f7afc1fdSRobert Mustacchi pcie_determine_aspm(dev_info_t *dip)
1009f7afc1fdSRobert Mustacchi {
1010f7afc1fdSRobert Mustacchi 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1011f7afc1fdSRobert Mustacchi 	uint32_t	linkcap;
1012f7afc1fdSRobert Mustacchi 	uint16_t	linkctl;
1013f7afc1fdSRobert Mustacchi 
1014f7afc1fdSRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p))
1015f7afc1fdSRobert Mustacchi 		return;
1016f7afc1fdSRobert Mustacchi 
1017f7afc1fdSRobert Mustacchi 	linkcap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
1018f7afc1fdSRobert Mustacchi 	linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
1019f7afc1fdSRobert Mustacchi 
1020f7afc1fdSRobert Mustacchi 	switch (linkcap & PCIE_LINKCAP_ASPM_SUP_MASK) {
1021f7afc1fdSRobert Mustacchi 	case PCIE_LINKCAP_ASPM_SUP_L0S:
1022f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1023f7afc1fdSRobert Mustacchi 		    "pcie-aspm-support", "l0s");
1024f7afc1fdSRobert Mustacchi 		break;
1025f7afc1fdSRobert Mustacchi 	case PCIE_LINKCAP_ASPM_SUP_L1:
1026f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1027f7afc1fdSRobert Mustacchi 		    "pcie-aspm-support", "l1");
1028f7afc1fdSRobert Mustacchi 		break;
1029f7afc1fdSRobert Mustacchi 	case PCIE_LINKCAP_ASPM_SUP_L0S_L1:
1030f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1031f7afc1fdSRobert Mustacchi 		    "pcie-aspm-support", "l0s,l1");
1032f7afc1fdSRobert Mustacchi 		break;
1033f7afc1fdSRobert Mustacchi 	default:
1034f7afc1fdSRobert Mustacchi 		return;
1035f7afc1fdSRobert Mustacchi 	}
1036f7afc1fdSRobert Mustacchi 
1037f7afc1fdSRobert Mustacchi 	switch (linkctl & PCIE_LINKCTL_ASPM_CTL_MASK) {
1038f7afc1fdSRobert Mustacchi 	case PCIE_LINKCTL_ASPM_CTL_DIS:
1039f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1040f7afc1fdSRobert Mustacchi 		    "pcie-aspm-state", "disabled");
1041f7afc1fdSRobert Mustacchi 		break;
1042f7afc1fdSRobert Mustacchi 	case PCIE_LINKCTL_ASPM_CTL_L0S:
1043f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1044f7afc1fdSRobert Mustacchi 		    "pcie-aspm-state", "l0s");
1045f7afc1fdSRobert Mustacchi 		break;
1046f7afc1fdSRobert Mustacchi 	case PCIE_LINKCTL_ASPM_CTL_L1:
1047f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1048f7afc1fdSRobert Mustacchi 		    "pcie-aspm-state", "l1");
1049f7afc1fdSRobert Mustacchi 		break;
1050f7afc1fdSRobert Mustacchi 	case PCIE_LINKCTL_ASPM_CTL_L0S_L1:
1051f7afc1fdSRobert Mustacchi 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1052f7afc1fdSRobert Mustacchi 		    "pcie-aspm-state", "l0s,l1");
1053f7afc1fdSRobert Mustacchi 		break;
1054f7afc1fdSRobert Mustacchi 	}
1055f7afc1fdSRobert Mustacchi }
1056f7afc1fdSRobert Mustacchi 
1057f8d2de6bSjchu /*
10585b2c4190SRobert Mustacchi  * PCI-Express child device initialization. Note, this only will be called on a
10595b2c4190SRobert Mustacchi  * device or function if we actually attach a device driver to it.
10605b2c4190SRobert Mustacchi  *
10615b2c4190SRobert Mustacchi  * This function enables generic pci-express interrupts and error handling.
10625b2c4190SRobert Mustacchi  * Note, tagging, the max packet size, and related are all set up before this
10635b2c4190SRobert Mustacchi  * point and is performed in pcie_fabric_setup().
1064f8d2de6bSjchu  *
1065f8d2de6bSjchu  * @param pdip		root dip (root nexus's dip)
1066f8d2de6bSjchu  * @param cdip		child's dip (device's dip)
1067f8d2de6bSjchu  * @return		DDI_SUCCESS or DDI_FAILURE
1068f8d2de6bSjchu  */
1069f8d2de6bSjchu /* ARGSUSED */
1070f8d2de6bSjchu int
pcie_initchild(dev_info_t * cdip)1071f8d2de6bSjchu pcie_initchild(dev_info_t *cdip)
1072f8d2de6bSjchu {
1073eae2e508Skrishnae 	uint16_t		tmp16, reg16;
1074eae2e508Skrishnae 	pcie_bus_t		*bus_p;
1075fc256490SJason Beloro 	uint32_t		devid, venid;
1076eae2e508Skrishnae 
1077eae2e508Skrishnae 	bus_p = PCIE_DIP2BUS(cdip);
1078eae2e508Skrishnae 	if (bus_p == NULL) {
1079eae2e508Skrishnae 		PCIE_DBG("%s: BUS not found.\n",
1080eae2e508Skrishnae 		    ddi_driver_name(cdip));
1081eae2e508Skrishnae 
1082f8d2de6bSjchu 		return (DDI_FAILURE);
1083eae2e508Skrishnae 	}
1084f8d2de6bSjchu 
1085c0da6274SZhi-Jun Robin Fu 	if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
1086c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
1087c0da6274SZhi-Jun Robin Fu 
1088fc256490SJason Beloro 	/*
1089fc256490SJason Beloro 	 * Update pcie_bus_t with real Vendor Id Device Id.
1090fc256490SJason Beloro 	 *
1091fc256490SJason Beloro 	 * For assigned devices in IOV environment, the OBP will return
1092fc256490SJason Beloro 	 * faked device id/vendor id on configration read and for both
1093fc256490SJason Beloro 	 * properties in root domain. translate_devid() function will
1094fc256490SJason Beloro 	 * update the properties with real device-id/vendor-id on such
1095fc256490SJason Beloro 	 * platforms, so that we can utilize the properties here to get
1096fc256490SJason Beloro 	 * real device-id/vendor-id and overwrite the faked ids.
1097fc256490SJason Beloro 	 *
1098fc256490SJason Beloro 	 * For unassigned devices or devices in non-IOV environment, the
1099fc256490SJason Beloro 	 * operation below won't make a difference.
1100fc256490SJason Beloro 	 *
1101fc256490SJason Beloro 	 * The IOV implementation only supports assignment of PCIE
1102fc256490SJason Beloro 	 * endpoint devices. Devices under pci-pci bridges don't need
1103fc256490SJason Beloro 	 * operation like this.
1104fc256490SJason Beloro 	 */
1105fc256490SJason Beloro 	devid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
1106fc256490SJason Beloro 	    "device-id", -1);
1107fc256490SJason Beloro 	venid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
1108fc256490SJason Beloro 	    "vendor-id", -1);
1109fc256490SJason Beloro 	bus_p->bus_dev_ven_id = (devid << 16) | (venid & 0xffff);
1110fc256490SJason Beloro 
1111eae2e508Skrishnae 	/* Clear the device's status register */
1112eae2e508Skrishnae 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
1113eae2e508Skrishnae 	PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
111444961713Sgirish 
1115eae2e508Skrishnae 	/* Setup the device's command register */
1116eae2e508Skrishnae 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
1117eae2e508Skrishnae 	tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
111846ad6a07Skrishnae 
1119eae2e508Skrishnae 	if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
1120eae2e508Skrishnae 		tmp16 &= ~PCI_COMM_SERR_ENABLE;
1121f8d2de6bSjchu 
1122eae2e508Skrishnae 	PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
1123eae2e508Skrishnae 	PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
1124f8d2de6bSjchu 
1125f8d2de6bSjchu 	/*
1126f8d2de6bSjchu 	 * If the device has a bus control register then program it
1127f8d2de6bSjchu 	 * based on the settings in the command register.
1128f8d2de6bSjchu 	 */
1129eae2e508Skrishnae 	if (PCIE_IS_BDG(bus_p)) {
1130eae2e508Skrishnae 		/* Clear the device's secondary status register */
1131eae2e508Skrishnae 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
1132eae2e508Skrishnae 		PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
1133eae2e508Skrishnae 
1134eae2e508Skrishnae 		/* Setup the device's secondary command register */
1135eae2e508Skrishnae 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
1136eae2e508Skrishnae 		tmp16 = (reg16 & pcie_bdg_command_default_fw);
113799bebb69Skrishnae 
11389a12e1bdSjveta 		tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
113999bebb69Skrishnae 		/*
114099bebb69Skrishnae 		 * Workaround for this Nvidia bridge. Don't enable the SERR
114199bebb69Skrishnae 		 * enable bit in the bridge control register as it could lead to
114299bebb69Skrishnae 		 * bogus NMIs.
114399bebb69Skrishnae 		 */
114499bebb69Skrishnae 		if (bus_p->bus_dev_ven_id == 0x037010DE)
114599bebb69Skrishnae 			tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
114699bebb69Skrishnae 
1147f8d2de6bSjchu 		if (pcie_command_default & PCI_COMM_PARITY_DETECT)
1148eae2e508Skrishnae 			tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
1149eae2e508Skrishnae 
1150eae2e508Skrishnae 		/*
1151eae2e508Skrishnae 		 * Enable Master Abort Mode only if URs have not been masked.
1152eae2e508Skrishnae 		 * For PCI and PCIe-PCI bridges, enabling this bit causes a
1153eae2e508Skrishnae 		 * Master Aborts/UR to be forwarded as a UR/TA or SERR.  If this
1154eae2e508Skrishnae 		 * bit is masked, posted requests are dropped and non-posted
1155eae2e508Skrishnae 		 * requests are returned with -1.
1156eae2e508Skrishnae 		 */
1157eae2e508Skrishnae 		if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
1158eae2e508Skrishnae 			tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
11599a12e1bdSjveta 		else
11609a12e1bdSjveta 			tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
1161eae2e508Skrishnae 		PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
1162eae2e508Skrishnae 		PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
1163eae2e508Skrishnae 		    reg16);
1164bf8fc234Set 	}
1165bf8fc234Set 
1166eae2e508Skrishnae 	if (PCIE_IS_PCIE(bus_p)) {
1167eae2e508Skrishnae 		/* Setup PCIe device control register */
1168eae2e508Skrishnae 		reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
116983e6495bSDaniel Ice 		/* note: MPS/MRRS are initialized in pcie_initchild_mps() */
117083e6495bSDaniel Ice 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
117183e6495bSDaniel Ice 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
117283e6495bSDaniel Ice 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
117383e6495bSDaniel Ice 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK));
1174eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
1175eae2e508Skrishnae 		PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
1176eae2e508Skrishnae 
1177eae2e508Skrishnae 		/* Enable PCIe errors */
1178eae2e508Skrishnae 		pcie_enable_errors(cdip);
1179826c0d1dSRobert Mustacchi 
1180826c0d1dSRobert Mustacchi 		pcie_determine_serial(cdip);
1181b3d69c05SRobert Mustacchi 
1182f7afc1fdSRobert Mustacchi 		pcie_determine_aspm(cdip);
1183f7afc1fdSRobert Mustacchi 
1184b3d69c05SRobert Mustacchi 		pcie_capture_speeds(cdip);
1185eae2e508Skrishnae 	}
1186bf8fc234Set 
118726947304SEvan Yan 	bus_p->bus_ari = B_FALSE;
118826947304SEvan Yan 	if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
118926947304SEvan Yan 	    == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
119026947304SEvan Yan 	    == PCIE_ARI_DEVICE)) {
119126947304SEvan Yan 		bus_p->bus_ari = B_TRUE;
119226947304SEvan Yan 	}
119326947304SEvan Yan 
1194bf8fc234Set 	return (DDI_SUCCESS);
1195bf8fc234Set }
1196bf8fc234Set 
1197eae2e508Skrishnae static void
pcie_init_pfd(dev_info_t * dip)1198eae2e508Skrishnae pcie_init_pfd(dev_info_t *dip)
1199eae2e508Skrishnae {
1200eae2e508Skrishnae 	pf_data_t	*pfd_p = PCIE_ZALLOC(pf_data_t);
1201eae2e508Skrishnae 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1202eae2e508Skrishnae 
1203eae2e508Skrishnae 	PCIE_DIP2PFD(dip) = pfd_p;
1204eae2e508Skrishnae 
1205eae2e508Skrishnae 	pfd_p->pe_bus_p = bus_p;
1206eae2e508Skrishnae 	pfd_p->pe_severity_flags = 0;
120779bed773SHans Rosenfeld 	pfd_p->pe_severity_mask = 0;
1208fc256490SJason Beloro 	pfd_p->pe_orig_severity_flags = 0;
1209eae2e508Skrishnae 	pfd_p->pe_lock = B_FALSE;
1210eae2e508Skrishnae 	pfd_p->pe_valid = B_FALSE;
1211eae2e508Skrishnae 
1212eae2e508Skrishnae 	/* Allocate the root fault struct for both RC and RP */
1213c85864d8SKrishna Elango 	if (PCIE_IS_ROOT(bus_p)) {
1214eae2e508Skrishnae 		PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
1215c85864d8SKrishna Elango 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
1216fc256490SJason Beloro 		PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
1217c85864d8SKrishna Elango 	}
1218eae2e508Skrishnae 
1219eae2e508Skrishnae 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
1220fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
1221fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
1222eae2e508Skrishnae 
1223eae2e508Skrishnae 	if (PCIE_IS_BDG(bus_p))
1224eae2e508Skrishnae 		PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
1225eae2e508Skrishnae 
1226eae2e508Skrishnae 	if (PCIE_IS_PCIE(bus_p)) {
1227eae2e508Skrishnae 		PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
1228eae2e508Skrishnae 
1229eae2e508Skrishnae 		if (PCIE_IS_RP(bus_p))
1230eae2e508Skrishnae 			PCIE_RP_REG(pfd_p) =
1231eae2e508Skrishnae 			    PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
1232eae2e508Skrishnae 
1233eae2e508Skrishnae 		PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
1234c85864d8SKrishna Elango 		PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
1235eae2e508Skrishnae 
1236c85864d8SKrishna Elango 		if (PCIE_IS_RP(bus_p)) {
1237eae2e508Skrishnae 			PCIE_ADV_RP_REG(pfd_p) =
1238eae2e508Skrishnae 			    PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
1239c85864d8SKrishna Elango 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
1240c85864d8SKrishna Elango 			    PCIE_INVALID_BDF;
1241c85864d8SKrishna Elango 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
1242c85864d8SKrishna Elango 			    PCIE_INVALID_BDF;
1243c85864d8SKrishna Elango 		} else if (PCIE_IS_PCIE_BDG(bus_p)) {
1244eae2e508Skrishnae 			PCIE_ADV_BDG_REG(pfd_p) =
1245eae2e508Skrishnae 			    PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
1246c85864d8SKrishna Elango 			PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
1247c85864d8SKrishna Elango 			    PCIE_INVALID_BDF;
1248c85864d8SKrishna Elango 		}
1249eae2e508Skrishnae 
1250eae2e508Skrishnae 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
1251eae2e508Skrishnae 			PCIX_BDG_ERR_REG(pfd_p) =
1252eae2e508Skrishnae 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
1253eae2e508Skrishnae 
1254eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1255eae2e508Skrishnae 				PCIX_BDG_ECC_REG(pfd_p, 0) =
1256eae2e508Skrishnae 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1257eae2e508Skrishnae 				PCIX_BDG_ECC_REG(pfd_p, 1) =
1258eae2e508Skrishnae 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1259eae2e508Skrishnae 			}
1260eae2e508Skrishnae 		}
1261ffb64830SJordan Paige Hendricks 
1262ffb64830SJordan Paige Hendricks 		PCIE_SLOT_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_slot_regs_t);
1263ffb64830SJordan Paige Hendricks 		PCIE_SLOT_REG(pfd_p)->pcie_slot_regs_valid = B_FALSE;
1264ffb64830SJordan Paige Hendricks 		PCIE_SLOT_REG(pfd_p)->pcie_slot_cap = 0;
1265ffb64830SJordan Paige Hendricks 		PCIE_SLOT_REG(pfd_p)->pcie_slot_control = 0;
1266ffb64830SJordan Paige Hendricks 		PCIE_SLOT_REG(pfd_p)->pcie_slot_status = 0;
1267ffb64830SJordan Paige Hendricks 
1268eae2e508Skrishnae 	} else if (PCIE_IS_PCIX(bus_p)) {
1269eae2e508Skrishnae 		if (PCIE_IS_BDG(bus_p)) {
1270eae2e508Skrishnae 			PCIX_BDG_ERR_REG(pfd_p) =
1271eae2e508Skrishnae 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
1272eae2e508Skrishnae 
1273eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1274eae2e508Skrishnae 				PCIX_BDG_ECC_REG(pfd_p, 0) =
1275eae2e508Skrishnae 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1276eae2e508Skrishnae 				PCIX_BDG_ECC_REG(pfd_p, 1) =
1277eae2e508Skrishnae 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1278eae2e508Skrishnae 			}
1279eae2e508Skrishnae 		} else {
1280eae2e508Skrishnae 			PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
1281eae2e508Skrishnae 
1282eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p))
1283eae2e508Skrishnae 				PCIX_ECC_REG(pfd_p) =
1284eae2e508Skrishnae 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1285eae2e508Skrishnae 		}
1286eae2e508Skrishnae 	}
1287eae2e508Skrishnae }
1288eae2e508Skrishnae 
1289eae2e508Skrishnae static void
pcie_fini_pfd(dev_info_t * dip)1290eae2e508Skrishnae pcie_fini_pfd(dev_info_t *dip)
1291bf8fc234Set {
1292eae2e508Skrishnae 	pf_data_t	*pfd_p = PCIE_DIP2PFD(dip);
1293eae2e508Skrishnae 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1294eae2e508Skrishnae 
1295eae2e508Skrishnae 	if (PCIE_IS_PCIE(bus_p)) {
1296eae2e508Skrishnae 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
1297eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1298eae2e508Skrishnae 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
1299eae2e508Skrishnae 				    sizeof (pf_pcix_ecc_regs_t));
1300eae2e508Skrishnae 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
1301eae2e508Skrishnae 				    sizeof (pf_pcix_ecc_regs_t));
1302eae2e508Skrishnae 			}
1303eae2e508Skrishnae 
1304eae2e508Skrishnae 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
1305eae2e508Skrishnae 			    sizeof (pf_pcix_bdg_err_regs_t));
1306eae2e508Skrishnae 		}
1307eae2e508Skrishnae 
1308eae2e508Skrishnae 		if (PCIE_IS_RP(bus_p))
1309eae2e508Skrishnae 			kmem_free(PCIE_ADV_RP_REG(pfd_p),
1310eae2e508Skrishnae 			    sizeof (pf_pcie_adv_rp_err_regs_t));
1311eae2e508Skrishnae 		else if (PCIE_IS_PCIE_BDG(bus_p))
1312eae2e508Skrishnae 			kmem_free(PCIE_ADV_BDG_REG(pfd_p),
1313eae2e508Skrishnae 			    sizeof (pf_pcie_adv_bdg_err_regs_t));
1314eae2e508Skrishnae 
1315eae2e508Skrishnae 		kmem_free(PCIE_ADV_REG(pfd_p),
1316eae2e508Skrishnae 		    sizeof (pf_pcie_adv_err_regs_t));
1317eae2e508Skrishnae 
1318eae2e508Skrishnae 		if (PCIE_IS_RP(bus_p))
1319eae2e508Skrishnae 			kmem_free(PCIE_RP_REG(pfd_p),
1320eae2e508Skrishnae 			    sizeof (pf_pcie_rp_err_regs_t));
1321eae2e508Skrishnae 
1322eae2e508Skrishnae 		kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
1323eae2e508Skrishnae 	} else if (PCIE_IS_PCIX(bus_p)) {
1324eae2e508Skrishnae 		if (PCIE_IS_BDG(bus_p)) {
1325eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1326eae2e508Skrishnae 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
1327eae2e508Skrishnae 				    sizeof (pf_pcix_ecc_regs_t));
1328eae2e508Skrishnae 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
1329eae2e508Skrishnae 				    sizeof (pf_pcix_ecc_regs_t));
1330eae2e508Skrishnae 			}
1331eae2e508Skrishnae 
1332eae2e508Skrishnae 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
1333eae2e508Skrishnae 			    sizeof (pf_pcix_bdg_err_regs_t));
1334eae2e508Skrishnae 		} else {
1335eae2e508Skrishnae 			if (PCIX_ECC_VERSION_CHECK(bus_p))
1336eae2e508Skrishnae 				kmem_free(PCIX_ECC_REG(pfd_p),
1337eae2e508Skrishnae 				    sizeof (pf_pcix_ecc_regs_t));
1338eae2e508Skrishnae 
1339eae2e508Skrishnae 			kmem_free(PCIX_ERR_REG(pfd_p),
1340eae2e508Skrishnae 			    sizeof (pf_pcix_err_regs_t));
1341eae2e508Skrishnae 		}
1342eae2e508Skrishnae 	}
1343eae2e508Skrishnae 
1344eae2e508Skrishnae 	if (PCIE_IS_BDG(bus_p))
1345eae2e508Skrishnae 		kmem_free(PCI_BDG_ERR_REG(pfd_p),
1346eae2e508Skrishnae 		    sizeof (pf_pci_bdg_err_regs_t));
1347eae2e508Skrishnae 
1348fc256490SJason Beloro 	kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
1349eae2e508Skrishnae 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
1350eae2e508Skrishnae 
1351fc256490SJason Beloro 	if (PCIE_IS_ROOT(bus_p)) {
1352eae2e508Skrishnae 		kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
1353fc256490SJason Beloro 		kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
1354fc256490SJason Beloro 	}
1355eae2e508Skrishnae 
1356eae2e508Skrishnae 	kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
1357eae2e508Skrishnae 
1358eae2e508Skrishnae 	PCIE_DIP2PFD(dip) = NULL;
1359eae2e508Skrishnae }
1360eae2e508Skrishnae 
1361eae2e508Skrishnae 
1362eae2e508Skrishnae /*
1363eae2e508Skrishnae  * Special functions to allocate pf_data_t's for PCIe root complexes.
1364eae2e508Skrishnae  * Note: Root Complex not Root Port
1365eae2e508Skrishnae  */
1366eae2e508Skrishnae void
pcie_rc_init_pfd(dev_info_t * dip,pf_data_t * pfd_p)1367eae2e508Skrishnae pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
1368eae2e508Skrishnae {
1369eae2e508Skrishnae 	pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
1370eae2e508Skrishnae 	pfd_p->pe_severity_flags = 0;
137179bed773SHans Rosenfeld 	pfd_p->pe_severity_mask = 0;
1372fc256490SJason Beloro 	pfd_p->pe_orig_severity_flags = 0;
1373eae2e508Skrishnae 	pfd_p->pe_lock = B_FALSE;
1374eae2e508Skrishnae 	pfd_p->pe_valid = B_FALSE;
1375eae2e508Skrishnae 
1376eae2e508Skrishnae 	PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
1377c85864d8SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
1378fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
1379eae2e508Skrishnae 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
1380fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
1381fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
1382eae2e508Skrishnae 	PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
1383eae2e508Skrishnae 	PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
1384eae2e508Skrishnae 	PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
1385eae2e508Skrishnae 	PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
1386eae2e508Skrishnae 	PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
1387fc256490SJason Beloro 	PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF;
1388fc256490SJason Beloro 	PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF;
1389eae2e508Skrishnae 
1390eae2e508Skrishnae 	PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
1391eae2e508Skrishnae }
1392eae2e508Skrishnae 
1393eae2e508Skrishnae void
pcie_rc_fini_pfd(pf_data_t * pfd_p)1394eae2e508Skrishnae pcie_rc_fini_pfd(pf_data_t *pfd_p)
1395eae2e508Skrishnae {
1396eae2e508Skrishnae 	kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
1397eae2e508Skrishnae 	kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
1398eae2e508Skrishnae 	kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
1399eae2e508Skrishnae 	kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
1400eae2e508Skrishnae 	kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
1401fc256490SJason Beloro 	kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
1402eae2e508Skrishnae 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
1403eae2e508Skrishnae 	kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
1404fc256490SJason Beloro 	kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
1405eae2e508Skrishnae }
1406eae2e508Skrishnae 
1407c0da6274SZhi-Jun Robin Fu /*
1408c0da6274SZhi-Jun Robin Fu  * init pcie_bus_t for root complex
1409c0da6274SZhi-Jun Robin Fu  *
1410c0da6274SZhi-Jun Robin Fu  * Only a few of the fields in bus_t is valid for root complex.
1411c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized in this routine:
1412c0da6274SZhi-Jun Robin Fu  *
1413c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_dip>
1414c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_rp_dip
1415c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
1416c0da6274SZhi-Jun Robin Fu  * uint_t		<bus_fm_flags>
1417c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_bdf
1418c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_rp_bdf
1419c0da6274SZhi-Jun Robin Fu  * uint32_t		bus_dev_ven_id
1420c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_rev_id
1421c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_hdr_type>
1422c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_dev_type>
1423c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_bdg_secbus
1424c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcie_off
1425c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_aer_off>
1426c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcix_off
1427c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_ecc_ver
1428c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	bus_bus_range
1429c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	bus_addr_ranges
1430c0da6274SZhi-Jun Robin Fu  * int			bus_addr_entries
1431c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	bus_assigned_addr
1432c0da6274SZhi-Jun Robin Fu  * int			bus_assigned_entries
1433c0da6274SZhi-Jun Robin Fu  * pf_data_t *		bus_pfd
1434fc256490SJason Beloro  * pcie_domain_t *	<bus_dom>
1435c0da6274SZhi-Jun Robin Fu  * int			bus_mps
1436c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
1437c0da6274SZhi-Jun Robin Fu  * void	*		bus_plat_private
1438c0da6274SZhi-Jun Robin Fu  */
1439eae2e508Skrishnae void
pcie_rc_init_bus(dev_info_t * dip)1440eae2e508Skrishnae pcie_rc_init_bus(dev_info_t *dip)
1441eae2e508Skrishnae {
1442eae2e508Skrishnae 	pcie_bus_t *bus_p;
1443eae2e508Skrishnae 
1444eae2e508Skrishnae 	bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
1445eae2e508Skrishnae 	bus_p->bus_dip = dip;
1446eae2e508Skrishnae 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
1447eae2e508Skrishnae 	bus_p->bus_hdr_type = PCI_HEADER_ONE;
1448eae2e508Skrishnae 
1449eae2e508Skrishnae 	/* Fake that there are AER logs */
1450eae2e508Skrishnae 	bus_p->bus_aer_off = (uint16_t)-1;
1451eae2e508Skrishnae 
1452eae2e508Skrishnae 	/* Needed only for handle lookup */
145379bed773SHans Rosenfeld 	atomic_or_uint(&bus_p->bus_fm_flags, PF_FM_READY);
1454eae2e508Skrishnae 
1455eae2e508Skrishnae 	ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
1456fc256490SJason Beloro 
1457fc256490SJason Beloro 	PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t);
1458eae2e508Skrishnae }
1459eae2e508Skrishnae 
1460eae2e508Skrishnae void
pcie_rc_fini_bus(dev_info_t * dip)1461eae2e508Skrishnae pcie_rc_fini_bus(dev_info_t *dip)
1462eae2e508Skrishnae {
1463c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
1464296f12dcSToomas Soome 	ndi_set_bus_private(dip, B_FALSE, 0, NULL);
1465fc256490SJason Beloro 	kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t));
1466eae2e508Skrishnae 	kmem_free(bus_p, sizeof (pcie_bus_t));
1467eae2e508Skrishnae }
1468eae2e508Skrishnae 
1469b3d69c05SRobert Mustacchi static int
pcie_width_to_int(pcie_link_width_t width)1470b3d69c05SRobert Mustacchi pcie_width_to_int(pcie_link_width_t width)
1471b3d69c05SRobert Mustacchi {
1472b3d69c05SRobert Mustacchi 	switch (width) {
1473b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X1:
1474b3d69c05SRobert Mustacchi 		return (1);
1475b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X2:
1476b3d69c05SRobert Mustacchi 		return (2);
1477b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X4:
1478b3d69c05SRobert Mustacchi 		return (4);
1479b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X8:
1480b3d69c05SRobert Mustacchi 		return (8);
1481b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X12:
1482b3d69c05SRobert Mustacchi 		return (12);
1483b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X16:
1484b3d69c05SRobert Mustacchi 		return (16);
1485b3d69c05SRobert Mustacchi 	case PCIE_LINK_WIDTH_X32:
1486b3d69c05SRobert Mustacchi 		return (32);
1487b3d69c05SRobert Mustacchi 	default:
1488b3d69c05SRobert Mustacchi 		return (0);
1489b3d69c05SRobert Mustacchi 	}
1490b3d69c05SRobert Mustacchi }
1491b3d69c05SRobert Mustacchi 
1492b3d69c05SRobert Mustacchi /*
1493b3d69c05SRobert Mustacchi  * Return the speed in Transfers / second. This is a signed quantity to match
1494b3d69c05SRobert Mustacchi  * the ndi/ddi property interfaces.
1495b3d69c05SRobert Mustacchi  */
1496b3d69c05SRobert Mustacchi static int64_t
pcie_speed_to_int(pcie_link_speed_t speed)1497b3d69c05SRobert Mustacchi pcie_speed_to_int(pcie_link_speed_t speed)
1498b3d69c05SRobert Mustacchi {
1499b3d69c05SRobert Mustacchi 	switch (speed) {
1500b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_2_5:
1501b3d69c05SRobert Mustacchi 		return (2500000000LL);
1502b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_5:
1503b3d69c05SRobert Mustacchi 		return (5000000000LL);
1504b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_8:
1505b3d69c05SRobert Mustacchi 		return (8000000000LL);
1506b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_16:
1507b3d69c05SRobert Mustacchi 		return (16000000000LL);
150889427192SRobert Mustacchi 	case PCIE_LINK_SPEED_32:
150989427192SRobert Mustacchi 		return (32000000000LL);
151089427192SRobert Mustacchi 	case PCIE_LINK_SPEED_64:
151189427192SRobert Mustacchi 		return (64000000000LL);
1512b3d69c05SRobert Mustacchi 	default:
1513b3d69c05SRobert Mustacchi 		return (0);
1514b3d69c05SRobert Mustacchi 	}
1515b3d69c05SRobert Mustacchi }
1516b3d69c05SRobert Mustacchi 
1517b3d69c05SRobert Mustacchi /*
1518b3d69c05SRobert Mustacchi  * Translate the recorded speed information into devinfo properties.
1519b3d69c05SRobert Mustacchi  */
1520b3d69c05SRobert Mustacchi static void
pcie_speeds_to_devinfo(dev_info_t * dip,pcie_bus_t * bus_p)1521b3d69c05SRobert Mustacchi pcie_speeds_to_devinfo(dev_info_t *dip, pcie_bus_t *bus_p)
1522b3d69c05SRobert Mustacchi {
1523b3d69c05SRobert Mustacchi 	if (bus_p->bus_max_width != PCIE_LINK_WIDTH_UNKNOWN) {
1524b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1525b3d69c05SRobert Mustacchi 		    "pcie-link-maximum-width",
1526b3d69c05SRobert Mustacchi 		    pcie_width_to_int(bus_p->bus_max_width));
1527b3d69c05SRobert Mustacchi 	}
1528b3d69c05SRobert Mustacchi 
1529b3d69c05SRobert Mustacchi 	if (bus_p->bus_cur_width != PCIE_LINK_WIDTH_UNKNOWN) {
1530b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1531b3d69c05SRobert Mustacchi 		    "pcie-link-current-width",
1532b3d69c05SRobert Mustacchi 		    pcie_width_to_int(bus_p->bus_cur_width));
1533b3d69c05SRobert Mustacchi 	}
1534b3d69c05SRobert Mustacchi 
1535b3d69c05SRobert Mustacchi 	if (bus_p->bus_cur_speed != PCIE_LINK_SPEED_UNKNOWN) {
1536b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1537b3d69c05SRobert Mustacchi 		    "pcie-link-current-speed",
1538b3d69c05SRobert Mustacchi 		    pcie_speed_to_int(bus_p->bus_cur_speed));
1539b3d69c05SRobert Mustacchi 	}
1540b3d69c05SRobert Mustacchi 
1541b3d69c05SRobert Mustacchi 	if (bus_p->bus_max_speed != PCIE_LINK_SPEED_UNKNOWN) {
1542b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1543b3d69c05SRobert Mustacchi 		    "pcie-link-maximum-speed",
1544b3d69c05SRobert Mustacchi 		    pcie_speed_to_int(bus_p->bus_max_speed));
1545b3d69c05SRobert Mustacchi 	}
1546b3d69c05SRobert Mustacchi 
1547b3d69c05SRobert Mustacchi 	if (bus_p->bus_target_speed != PCIE_LINK_SPEED_UNKNOWN) {
1548b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1549b3d69c05SRobert Mustacchi 		    "pcie-link-target-speed",
1550b3d69c05SRobert Mustacchi 		    pcie_speed_to_int(bus_p->bus_target_speed));
1551b3d69c05SRobert Mustacchi 	}
1552b3d69c05SRobert Mustacchi 
1553b3d69c05SRobert Mustacchi 	if ((bus_p->bus_speed_flags & PCIE_LINK_F_ADMIN_TARGET) != 0) {
1554b3d69c05SRobert Mustacchi 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1555b3d69c05SRobert Mustacchi 		    "pcie-link-admin-target-speed");
1556b3d69c05SRobert Mustacchi 	}
1557b3d69c05SRobert Mustacchi 
1558b3d69c05SRobert Mustacchi 	if (bus_p->bus_sup_speed != PCIE_LINK_SPEED_UNKNOWN) {
155989427192SRobert Mustacchi 		int64_t speeds[PCIE_NSPEEDS];
1560b3d69c05SRobert Mustacchi 		uint_t nspeeds = 0;
1561b3d69c05SRobert Mustacchi 
1562b3d69c05SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_2_5) {
1563b3d69c05SRobert Mustacchi 			speeds[nspeeds++] =
1564b3d69c05SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_2_5);
1565b3d69c05SRobert Mustacchi 		}
1566b3d69c05SRobert Mustacchi 
1567b3d69c05SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_5) {
1568b3d69c05SRobert Mustacchi 			speeds[nspeeds++] =
1569b3d69c05SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_5);
1570b3d69c05SRobert Mustacchi 		}
1571b3d69c05SRobert Mustacchi 
1572b3d69c05SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_8) {
1573b3d69c05SRobert Mustacchi 			speeds[nspeeds++] =
1574b3d69c05SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_8);
1575b3d69c05SRobert Mustacchi 		}
1576b3d69c05SRobert Mustacchi 
1577b3d69c05SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_16) {
1578b3d69c05SRobert Mustacchi 			speeds[nspeeds++] =
1579b3d69c05SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_16);
1580b3d69c05SRobert Mustacchi 		}
1581b3d69c05SRobert Mustacchi 
158289427192SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_32) {
158389427192SRobert Mustacchi 			speeds[nspeeds++] =
158489427192SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_32);
158589427192SRobert Mustacchi 		}
158689427192SRobert Mustacchi 
158789427192SRobert Mustacchi 		if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_64) {
158889427192SRobert Mustacchi 			speeds[nspeeds++] =
158989427192SRobert Mustacchi 			    pcie_speed_to_int(PCIE_LINK_SPEED_64);
159089427192SRobert Mustacchi 		}
159189427192SRobert Mustacchi 
1592b3d69c05SRobert Mustacchi 		(void) ndi_prop_update_int64_array(DDI_DEV_T_NONE, dip,
1593b3d69c05SRobert Mustacchi 		    "pcie-link-supported-speeds", speeds, nspeeds);
1594b3d69c05SRobert Mustacchi 	}
1595b3d69c05SRobert Mustacchi }
1596b3d69c05SRobert Mustacchi 
1597662dc8a5SRobert Mustacchi /*
1598662dc8a5SRobert Mustacchi  * We need to capture the supported, maximum, and current device speed and
1599662dc8a5SRobert Mustacchi  * width. The way that this has been done has changed over time.
1600662dc8a5SRobert Mustacchi  *
1601662dc8a5SRobert Mustacchi  * Prior to PCIe Gen 3, there were only current and supported speed fields.
1602662dc8a5SRobert Mustacchi  * These were found in the link status and link capabilities registers of the
1603662dc8a5SRobert Mustacchi  * PCI express capability. With the change to PCIe Gen 3, the information in the
1604662dc8a5SRobert Mustacchi  * link capabilities changed to the maximum value. The supported speeds vector
1605662dc8a5SRobert Mustacchi  * was moved to the link capabilities 2 register.
1606662dc8a5SRobert Mustacchi  *
1607662dc8a5SRobert Mustacchi  * Now, a device may not implement some of these registers. To determine whether
1608662dc8a5SRobert Mustacchi  * or not it's here, we have to do the following. First, we need to check the
1609662dc8a5SRobert Mustacchi  * revision of the PCI express capability. The link capabilities 2 register did
1610b3d69c05SRobert Mustacchi  * not exist prior to version 2 of this capability. If a modern device does not
1611b3d69c05SRobert Mustacchi  * implement it, it is supposed to return zero for the register.
1612662dc8a5SRobert Mustacchi  */
1613662dc8a5SRobert Mustacchi static void
pcie_capture_speeds(dev_info_t * dip)1614b3d69c05SRobert Mustacchi pcie_capture_speeds(dev_info_t *dip)
1615662dc8a5SRobert Mustacchi {
1616662dc8a5SRobert Mustacchi 	uint16_t	vers, status;
1617b3d69c05SRobert Mustacchi 	uint32_t	cap, cap2, ctl2;
1618b3d69c05SRobert Mustacchi 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
16197687d0d8SRobert Mustacchi 	dev_info_t	*rcdip;
1620662dc8a5SRobert Mustacchi 
1621662dc8a5SRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p))
1622662dc8a5SRobert Mustacchi 		return;
1623662dc8a5SRobert Mustacchi 
16247687d0d8SRobert Mustacchi 	rcdip = pcie_get_rc_dip(dip);
16257687d0d8SRobert Mustacchi 	if (bus_p->bus_cfg_hdl == NULL) {
16267687d0d8SRobert Mustacchi 		vers = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16277687d0d8SRobert Mustacchi 		    bus_p->bus_pcie_off + PCIE_PCIECAP);
16287687d0d8SRobert Mustacchi 	} else {
16297687d0d8SRobert Mustacchi 		vers = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
16307687d0d8SRobert Mustacchi 	}
1631662dc8a5SRobert Mustacchi 	if (vers == PCI_EINVAL16)
1632662dc8a5SRobert Mustacchi 		return;
1633662dc8a5SRobert Mustacchi 	vers &= PCIE_PCIECAP_VER_MASK;
1634662dc8a5SRobert Mustacchi 
1635662dc8a5SRobert Mustacchi 	/*
1636662dc8a5SRobert Mustacchi 	 * Verify the capability's version.
1637662dc8a5SRobert Mustacchi 	 */
1638662dc8a5SRobert Mustacchi 	switch (vers) {
1639662dc8a5SRobert Mustacchi 	case PCIE_PCIECAP_VER_1_0:
1640662dc8a5SRobert Mustacchi 		cap2 = 0;
1641b3d69c05SRobert Mustacchi 		ctl2 = 0;
1642662dc8a5SRobert Mustacchi 		break;
1643662dc8a5SRobert Mustacchi 	case PCIE_PCIECAP_VER_2_0:
16447687d0d8SRobert Mustacchi 		if (bus_p->bus_cfg_hdl == NULL) {
16457687d0d8SRobert Mustacchi 			cap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
16467687d0d8SRobert Mustacchi 			    bus_p->bus_pcie_off + PCIE_LINKCAP2);
16477687d0d8SRobert Mustacchi 			ctl2 = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16487687d0d8SRobert Mustacchi 			    bus_p->bus_pcie_off + PCIE_LINKCTL2);
16497687d0d8SRobert Mustacchi 		} else {
16507687d0d8SRobert Mustacchi 			cap2 = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP2);
16517687d0d8SRobert Mustacchi 			ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
16527687d0d8SRobert Mustacchi 		}
1653662dc8a5SRobert Mustacchi 		if (cap2 == PCI_EINVAL32)
1654662dc8a5SRobert Mustacchi 			cap2 = 0;
1655b3d69c05SRobert Mustacchi 		if (ctl2 == PCI_EINVAL16)
1656b3d69c05SRobert Mustacchi 			ctl2 = 0;
1657662dc8a5SRobert Mustacchi 		break;
1658662dc8a5SRobert Mustacchi 	default:
1659662dc8a5SRobert Mustacchi 		/* Don't try and handle an unknown version */
1660662dc8a5SRobert Mustacchi 		return;
1661662dc8a5SRobert Mustacchi 	}
1662662dc8a5SRobert Mustacchi 
16637687d0d8SRobert Mustacchi 	if (bus_p->bus_cfg_hdl == NULL) {
16647687d0d8SRobert Mustacchi 		status = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16657687d0d8SRobert Mustacchi 		    bus_p->bus_pcie_off + PCIE_LINKSTS);
16667687d0d8SRobert Mustacchi 		cap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
16677687d0d8SRobert Mustacchi 		    bus_p->bus_pcie_off + PCIE_LINKCAP);
16687687d0d8SRobert Mustacchi 	} else {
16697687d0d8SRobert Mustacchi 		status = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
16707687d0d8SRobert Mustacchi 		cap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
16717687d0d8SRobert Mustacchi 	}
1672662dc8a5SRobert Mustacchi 	if (status == PCI_EINVAL16 || cap == PCI_EINVAL32)
1673662dc8a5SRobert Mustacchi 		return;
1674662dc8a5SRobert Mustacchi 
1675b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_speed_mutex);
1676b3d69c05SRobert Mustacchi 
1677662dc8a5SRobert Mustacchi 	switch (status & PCIE_LINKSTS_SPEED_MASK) {
1678662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_2_5:
1679662dc8a5SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_2_5;
1680662dc8a5SRobert Mustacchi 		break;
1681662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_5:
1682662dc8a5SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_5;
1683662dc8a5SRobert Mustacchi 		break;
1684662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_8:
1685662dc8a5SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_8;
1686662dc8a5SRobert Mustacchi 		break;
168733756ae2SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_16:
168833756ae2SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_16;
168933756ae2SRobert Mustacchi 		break;
169089427192SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_32:
169189427192SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_32;
169289427192SRobert Mustacchi 		break;
169389427192SRobert Mustacchi 	case PCIE_LINKSTS_SPEED_64:
169489427192SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_64;
169589427192SRobert Mustacchi 		break;
1696662dc8a5SRobert Mustacchi 	default:
1697662dc8a5SRobert Mustacchi 		bus_p->bus_cur_speed = PCIE_LINK_SPEED_UNKNOWN;
1698662dc8a5SRobert Mustacchi 		break;
1699662dc8a5SRobert Mustacchi 	}
1700662dc8a5SRobert Mustacchi 
1701662dc8a5SRobert Mustacchi 	switch (status & PCIE_LINKSTS_NEG_WIDTH_MASK) {
1702662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X1:
1703662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X1;
1704662dc8a5SRobert Mustacchi 		break;
1705662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X2:
1706662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X2;
1707662dc8a5SRobert Mustacchi 		break;
1708662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X4:
1709662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X4;
1710662dc8a5SRobert Mustacchi 		break;
1711662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X8:
1712662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X8;
1713662dc8a5SRobert Mustacchi 		break;
1714662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X12:
1715662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X12;
1716662dc8a5SRobert Mustacchi 		break;
1717662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X16:
1718662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X16;
1719662dc8a5SRobert Mustacchi 		break;
1720662dc8a5SRobert Mustacchi 	case PCIE_LINKSTS_NEG_WIDTH_X32:
1721662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_X32;
1722662dc8a5SRobert Mustacchi 		break;
1723662dc8a5SRobert Mustacchi 	default:
1724662dc8a5SRobert Mustacchi 		bus_p->bus_cur_width = PCIE_LINK_WIDTH_UNKNOWN;
1725662dc8a5SRobert Mustacchi 		break;
1726662dc8a5SRobert Mustacchi 	}
1727662dc8a5SRobert Mustacchi 
1728662dc8a5SRobert Mustacchi 	switch (cap & PCIE_LINKCAP_MAX_WIDTH_MASK) {
1729662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X1:
1730662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X1;
1731662dc8a5SRobert Mustacchi 		break;
1732662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X2:
1733662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X2;
1734662dc8a5SRobert Mustacchi 		break;
1735662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X4:
1736662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X4;
1737662dc8a5SRobert Mustacchi 		break;
1738662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X8:
1739662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X8;
1740662dc8a5SRobert Mustacchi 		break;
1741662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X12:
1742662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X12;
1743662dc8a5SRobert Mustacchi 		break;
1744662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X16:
1745662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X16;
1746662dc8a5SRobert Mustacchi 		break;
1747662dc8a5SRobert Mustacchi 	case PCIE_LINKCAP_MAX_WIDTH_X32:
1748662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_X32;
1749662dc8a5SRobert Mustacchi 		break;
1750662dc8a5SRobert Mustacchi 	default:
1751662dc8a5SRobert Mustacchi 		bus_p->bus_max_width = PCIE_LINK_WIDTH_UNKNOWN;
1752662dc8a5SRobert Mustacchi 		break;
1753662dc8a5SRobert Mustacchi 	}
1754662dc8a5SRobert Mustacchi 
1755662dc8a5SRobert Mustacchi 	/*
1756662dc8a5SRobert Mustacchi 	 * If we have the Link Capabilities 2, then we can get the supported
1757662dc8a5SRobert Mustacchi 	 * speeds from it and treat the bits in Link Capabilities 1 as the
1758662dc8a5SRobert Mustacchi 	 * maximum. If we don't, then we need to follow the Implementation Note
1759662dc8a5SRobert Mustacchi 	 * in the standard under Link Capabilities 2. Effectively, this means
1760662dc8a5SRobert Mustacchi 	 * that if the value of 10b is set in Link Capabilities register, that
1761662dc8a5SRobert Mustacchi 	 * it supports both 2.5 and 5 GT/s speeds.
1762662dc8a5SRobert Mustacchi 	 */
1763662dc8a5SRobert Mustacchi 	if (cap2 != 0) {
1764662dc8a5SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_2_5)
1765662dc8a5SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_2_5;
1766662dc8a5SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_5)
1767662dc8a5SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_5;
1768662dc8a5SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_8)
1769662dc8a5SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_8;
177033756ae2SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_16)
177133756ae2SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_16;
177289427192SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_32)
177389427192SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_32;
177489427192SRobert Mustacchi 		if (cap2 & PCIE_LINKCAP2_SPEED_64)
177589427192SRobert Mustacchi 			bus_p->bus_sup_speed |= PCIE_LINK_SPEED_64;
1776662dc8a5SRobert Mustacchi 
1777662dc8a5SRobert Mustacchi 		switch (cap & PCIE_LINKCAP_MAX_SPEED_MASK) {
1778662dc8a5SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_2_5:
1779662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_2_5;
1780662dc8a5SRobert Mustacchi 			break;
1781662dc8a5SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_5:
1782662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_5;
1783662dc8a5SRobert Mustacchi 			break;
1784662dc8a5SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_8:
1785662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_8;
1786662dc8a5SRobert Mustacchi 			break;
178733756ae2SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_16:
178833756ae2SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_16;
178933756ae2SRobert Mustacchi 			break;
179089427192SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_32:
179189427192SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_32;
179289427192SRobert Mustacchi 			break;
179389427192SRobert Mustacchi 		case PCIE_LINKCAP_MAX_SPEED_64:
179489427192SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_64;
179589427192SRobert Mustacchi 			break;
1796662dc8a5SRobert Mustacchi 		default:
1797662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_UNKNOWN;
1798662dc8a5SRobert Mustacchi 			break;
1799662dc8a5SRobert Mustacchi 		}
1800662dc8a5SRobert Mustacchi 	} else {
1801662dc8a5SRobert Mustacchi 		if (cap & PCIE_LINKCAP_MAX_SPEED_5) {
1802662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_5;
1803662dc8a5SRobert Mustacchi 			bus_p->bus_sup_speed = PCIE_LINK_SPEED_2_5 |
1804662dc8a5SRobert Mustacchi 			    PCIE_LINK_SPEED_5;
1805b3d69c05SRobert Mustacchi 		} else if (cap & PCIE_LINKCAP_MAX_SPEED_2_5) {
1806662dc8a5SRobert Mustacchi 			bus_p->bus_max_speed = PCIE_LINK_SPEED_2_5;
1807662dc8a5SRobert Mustacchi 			bus_p->bus_sup_speed = PCIE_LINK_SPEED_2_5;
1808662dc8a5SRobert Mustacchi 		}
1809662dc8a5SRobert Mustacchi 	}
1810b3d69c05SRobert Mustacchi 
1811b3d69c05SRobert Mustacchi 	switch (ctl2 & PCIE_LINKCTL2_TARGET_SPEED_MASK) {
1812b3d69c05SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_2_5:
1813b3d69c05SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_2_5;
1814b3d69c05SRobert Mustacchi 		break;
1815b3d69c05SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_5:
1816b3d69c05SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_5;
1817b3d69c05SRobert Mustacchi 		break;
1818b3d69c05SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_8:
1819b3d69c05SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_8;
1820b3d69c05SRobert Mustacchi 		break;
1821b3d69c05SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_16:
1822b3d69c05SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_16;
1823b3d69c05SRobert Mustacchi 		break;
182489427192SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_32:
182589427192SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_32;
182689427192SRobert Mustacchi 		break;
182789427192SRobert Mustacchi 	case PCIE_LINKCTL2_TARGET_SPEED_64:
182889427192SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_64;
182989427192SRobert Mustacchi 		break;
1830b3d69c05SRobert Mustacchi 	default:
1831b3d69c05SRobert Mustacchi 		bus_p->bus_target_speed = PCIE_LINK_SPEED_UNKNOWN;
1832b3d69c05SRobert Mustacchi 		break;
1833b3d69c05SRobert Mustacchi 	}
1834b3d69c05SRobert Mustacchi 
1835b3d69c05SRobert Mustacchi 	pcie_speeds_to_devinfo(dip, bus_p);
1836b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_speed_mutex);
1837662dc8a5SRobert Mustacchi }
1838662dc8a5SRobert Mustacchi 
1839eae2e508Skrishnae /*
1840c0da6274SZhi-Jun Robin Fu  * partially init pcie_bus_t for device (dip,bdf) for accessing pci
1841c0da6274SZhi-Jun Robin Fu  * config space
1842c0da6274SZhi-Jun Robin Fu  *
1843c0da6274SZhi-Jun Robin Fu  * This routine is invoked during boot, either after creating a devinfo node
1844c0da6274SZhi-Jun Robin Fu  * (x86 case) or during px driver attach (sparc case); it is also invoked
1845c0da6274SZhi-Jun Robin Fu  * in hotplug context after a devinfo node is created.
1846c0da6274SZhi-Jun Robin Fu  *
1847c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
1848c0da6274SZhi-Jun Robin Fu  * is set:
1849c0da6274SZhi-Jun Robin Fu  *
1850c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_dip>
1851c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_rp_dip>
1852c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
1853c0da6274SZhi-Jun Robin Fu  * uint_t		bus_fm_flags
1854c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	<bus_bdf>
1855c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	<bus_rp_bdf>
1856c0da6274SZhi-Jun Robin Fu  * uint32_t		<bus_dev_ven_id>
1857c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_rev_id>
1858c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_hdr_type>
1859c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_dev_type>
1860c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_bdg_secbus
1861c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_pcie_off>
1862c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_aer_off>
1863c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_pcix_off>
1864c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_ecc_ver>
1865c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	bus_bus_range
1866c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	bus_addr_ranges
1867c0da6274SZhi-Jun Robin Fu  * int			bus_addr_entries
1868c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	bus_assigned_addr
1869c0da6274SZhi-Jun Robin Fu  * int			bus_assigned_entries
1870c0da6274SZhi-Jun Robin Fu  * pf_data_t *		bus_pfd
1871fc256490SJason Beloro  * pcie_domain_t *	bus_dom
1872c0da6274SZhi-Jun Robin Fu  * int			bus_mps
1873c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
1874c0da6274SZhi-Jun Robin Fu  * void	*		bus_plat_private
1875eae2e508Skrishnae  *
1876c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
1877c0da6274SZhi-Jun Robin Fu  * is set:
1878c0da6274SZhi-Jun Robin Fu  *
1879c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_dip
1880c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_rp_dip
1881c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
1882c0da6274SZhi-Jun Robin Fu  * uint_t		bus_fm_flags
1883c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_bdf
1884c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_rp_bdf
1885c0da6274SZhi-Jun Robin Fu  * uint32_t		bus_dev_ven_id
1886c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_rev_id
1887c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_hdr_type
1888c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_dev_type
1889c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_bdg_secbus>
1890c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcie_off
1891c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_aer_off
1892c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcix_off
1893c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_ecc_ver
1894c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	<bus_bus_range>
1895c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	<bus_addr_ranges>
1896c0da6274SZhi-Jun Robin Fu  * int			<bus_addr_entries>
1897c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	<bus_assigned_addr>
1898c0da6274SZhi-Jun Robin Fu  * int			<bus_assigned_entries>
1899c0da6274SZhi-Jun Robin Fu  * pf_data_t *		<bus_pfd>
1900fc256490SJason Beloro  * pcie_domain_t *	bus_dom
1901c0da6274SZhi-Jun Robin Fu  * int			bus_mps
1902c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
1903c0da6274SZhi-Jun Robin Fu  * void	*		<bus_plat_private>
1904eae2e508Skrishnae  */
1905c0da6274SZhi-Jun Robin Fu 
1906eae2e508Skrishnae pcie_bus_t *
pcie_init_bus(dev_info_t * dip,pcie_req_id_t bdf,uint8_t flags)1907c0da6274SZhi-Jun Robin Fu pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
1908eae2e508Skrishnae {
1909c0da6274SZhi-Jun Robin Fu 	uint16_t	status, base, baseptr, num_cap;
1910c0da6274SZhi-Jun Robin Fu 	uint32_t	capid;
1911c0da6274SZhi-Jun Robin Fu 	int		range_size;
1912b3d69c05SRobert Mustacchi 	pcie_bus_t	*bus_p = NULL;
1913c0da6274SZhi-Jun Robin Fu 	dev_info_t	*rcdip;
1914c0da6274SZhi-Jun Robin Fu 	dev_info_t	*pdip;
1915c0da6274SZhi-Jun Robin Fu 	const char	*errstr = NULL;
1916eae2e508Skrishnae 
1917c0da6274SZhi-Jun Robin Fu 	if (!(flags & PCIE_BUS_INITIAL))
1918c0da6274SZhi-Jun Robin Fu 		goto initial_done;
1919eae2e508Skrishnae 
1920eae2e508Skrishnae 	bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
1921bf8fc234Set 
1922c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dip = dip;
1923c0da6274SZhi-Jun Robin Fu 	bus_p->bus_bdf = bdf;
1924bf8fc234Set 
1925c0da6274SZhi-Jun Robin Fu 	rcdip = pcie_get_rc_dip(dip);
1926c0da6274SZhi-Jun Robin Fu 	ASSERT(rcdip != NULL);
192726947304SEvan Yan 
1928c0da6274SZhi-Jun Robin Fu 	/* Save the Vendor ID, Device ID and revision ID */
1929c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
1930c0da6274SZhi-Jun Robin Fu 	bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
1931c0da6274SZhi-Jun Robin Fu 	/* Save the Header Type */
1932c0da6274SZhi-Jun Robin Fu 	bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
1933c0da6274SZhi-Jun Robin Fu 	bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
1934bf8fc234Set 
1935c0da6274SZhi-Jun Robin Fu 	/*
1936c0da6274SZhi-Jun Robin Fu 	 * Figure out the device type and all the relavant capability offsets
1937c0da6274SZhi-Jun Robin Fu 	 */
1938c0da6274SZhi-Jun Robin Fu 	/* set default value */
1939c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
1940bf8fc234Set 
1941c0da6274SZhi-Jun Robin Fu 	status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
1942c0da6274SZhi-Jun Robin Fu 	if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
1943c0da6274SZhi-Jun Robin Fu 		goto caps_done; /* capability not supported */
1944bf8fc234Set 
1945c0da6274SZhi-Jun Robin Fu 	/* Relevant conventional capabilities first */
1946bf8fc234Set 
1947c0da6274SZhi-Jun Robin Fu 	/* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
1948c0da6274SZhi-Jun Robin Fu 	num_cap = 2;
1949c0da6274SZhi-Jun Robin Fu 
1950c0da6274SZhi-Jun Robin Fu 	switch (bus_p->bus_hdr_type) {
1951c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_ZERO:
1952c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_CONF_CAP_PTR;
1953c0da6274SZhi-Jun Robin Fu 		break;
1954c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_PPB:
1955c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_BCNF_CAP_PTR;
1956c0da6274SZhi-Jun Robin Fu 		break;
1957c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_CARDBUS:
1958c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_CBUS_CAP_PTR;
1959c0da6274SZhi-Jun Robin Fu 		break;
1960c0da6274SZhi-Jun Robin Fu 	default:
1961c0da6274SZhi-Jun Robin Fu 		cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
1962c0da6274SZhi-Jun Robin Fu 		    __func__, bus_p->bus_hdr_type);
1963c0da6274SZhi-Jun Robin Fu 		goto caps_done;
1964eae2e508Skrishnae 	}
1965eae2e508Skrishnae 
1966c0da6274SZhi-Jun Robin Fu 	base = baseptr;
1967c0da6274SZhi-Jun Robin Fu 	for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
1968c0da6274SZhi-Jun Robin Fu 	    base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
1969c0da6274SZhi-Jun Robin Fu 		capid = pci_cfgacc_get8(rcdip, bdf, base);
19705b2c4190SRobert Mustacchi 		uint16_t pcap;
19715b2c4190SRobert Mustacchi 
1972c0da6274SZhi-Jun Robin Fu 		switch (capid) {
1973c0da6274SZhi-Jun Robin Fu 		case PCI_CAP_ID_PCI_E:
1974c0da6274SZhi-Jun Robin Fu 			bus_p->bus_pcie_off = base;
19755b2c4190SRobert Mustacchi 			pcap = pci_cfgacc_get16(rcdip, bdf, base +
19765b2c4190SRobert Mustacchi 			    PCIE_PCIECAP);
19775b2c4190SRobert Mustacchi 			bus_p->bus_dev_type = pcap & PCIE_PCIECAP_DEV_TYPE_MASK;
19785b2c4190SRobert Mustacchi 			bus_p->bus_pcie_vers = pcap & PCIE_PCIECAP_VER_MASK;
1979c0da6274SZhi-Jun Robin Fu 
1980c0da6274SZhi-Jun Robin Fu 			/* Check and save PCIe hotplug capability information */
1981c0da6274SZhi-Jun Robin Fu 			if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
1982c0da6274SZhi-Jun Robin Fu 			    (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
1983c0da6274SZhi-Jun Robin Fu 			    & PCIE_PCIECAP_SLOT_IMPL) &&
1984c0da6274SZhi-Jun Robin Fu 			    (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
1985c0da6274SZhi-Jun Robin Fu 			    & PCIE_SLOTCAP_HP_CAPABLE))
1986c0da6274SZhi-Jun Robin Fu 				bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
1987c0da6274SZhi-Jun Robin Fu 
1988c0da6274SZhi-Jun Robin Fu 			num_cap--;
1989c0da6274SZhi-Jun Robin Fu 			break;
1990c0da6274SZhi-Jun Robin Fu 		case PCI_CAP_ID_PCIX:
1991c0da6274SZhi-Jun Robin Fu 			bus_p->bus_pcix_off = base;
1992c0da6274SZhi-Jun Robin Fu 			if (PCIE_IS_BDG(bus_p))
1993c0da6274SZhi-Jun Robin Fu 				bus_p->bus_ecc_ver =
1994c0da6274SZhi-Jun Robin Fu 				    pci_cfgacc_get16(rcdip, bdf, base +
1995c0da6274SZhi-Jun Robin Fu 				    PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
1996c0da6274SZhi-Jun Robin Fu 			else
1997c0da6274SZhi-Jun Robin Fu 				bus_p->bus_ecc_ver =
1998c0da6274SZhi-Jun Robin Fu 				    pci_cfgacc_get16(rcdip, bdf, base +
1999c0da6274SZhi-Jun Robin Fu 				    PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
2000c0da6274SZhi-Jun Robin Fu 			num_cap--;
2001c0da6274SZhi-Jun Robin Fu 			break;
2002c0da6274SZhi-Jun Robin Fu 		default:
2003c0da6274SZhi-Jun Robin Fu 			break;
2004c0da6274SZhi-Jun Robin Fu 		}
2005eae2e508Skrishnae 	}
2006eae2e508Skrishnae 
2007c0da6274SZhi-Jun Robin Fu 	/* Check and save PCI hotplug (SHPC) capability information */
2008eae2e508Skrishnae 	if (PCIE_IS_BDG(bus_p)) {
2009c0da6274SZhi-Jun Robin Fu 		base = baseptr;
2010c0da6274SZhi-Jun Robin Fu 		for (base = pci_cfgacc_get8(rcdip, bdf, base);
2011c0da6274SZhi-Jun Robin Fu 		    base; base = pci_cfgacc_get8(rcdip, bdf,
2012c0da6274SZhi-Jun Robin Fu 		    base + PCI_CAP_NEXT_PTR)) {
2013c0da6274SZhi-Jun Robin Fu 			capid = pci_cfgacc_get8(rcdip, bdf, base);
2014c0da6274SZhi-Jun Robin Fu 			if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
2015c0da6274SZhi-Jun Robin Fu 				bus_p->bus_pci_hp_off = base;
2016c0da6274SZhi-Jun Robin Fu 				bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
2017c0da6274SZhi-Jun Robin Fu 				break;
2018c0da6274SZhi-Jun Robin Fu 			}
20193f9ec228SZhi-Jun Robin Fu 		}
2020c0da6274SZhi-Jun Robin Fu 	}
2021bf8fc234Set 
2022c0da6274SZhi-Jun Robin Fu 	/* Then, relevant extended capabilities */
2023bf8fc234Set 
2024c0da6274SZhi-Jun Robin Fu 	if (!PCIE_IS_PCIE(bus_p))
2025c0da6274SZhi-Jun Robin Fu 		goto caps_done;
2026bf8fc234Set 
2027c0da6274SZhi-Jun Robin Fu 	/* Extended caps: PCIE_EXT_CAP_ID_AER */
2028c0da6274SZhi-Jun Robin Fu 	for (base = PCIE_EXT_CAP; base; base = (capid >>
2029c0da6274SZhi-Jun Robin Fu 	    PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
2030c0da6274SZhi-Jun Robin Fu 		capid = pci_cfgacc_get32(rcdip, bdf, base);
2031c0da6274SZhi-Jun Robin Fu 		if (capid == PCI_CAP_EINVAL32)
2032c0da6274SZhi-Jun Robin Fu 			break;
20335b2c4190SRobert Mustacchi 		switch ((capid >> PCIE_EXT_CAP_ID_SHIFT) &
20345b2c4190SRobert Mustacchi 		    PCIE_EXT_CAP_ID_MASK) {
20355b2c4190SRobert Mustacchi 		case PCIE_EXT_CAP_ID_AER:
2036c0da6274SZhi-Jun Robin Fu 			bus_p->bus_aer_off = base;
2037c0da6274SZhi-Jun Robin Fu 			break;
20385b2c4190SRobert Mustacchi 		case PCIE_EXT_CAP_ID_DEV3:
20395b2c4190SRobert Mustacchi 			bus_p->bus_dev3_off = base;
20405b2c4190SRobert Mustacchi 			break;
2041c0da6274SZhi-Jun Robin Fu 		}
2042c0da6274SZhi-Jun Robin Fu 	}
2043f8d2de6bSjchu 
2044c0da6274SZhi-Jun Robin Fu caps_done:
2045eae2e508Skrishnae 	/* save RP dip and RP bdf */
2046eae2e508Skrishnae 	if (PCIE_IS_RP(bus_p)) {
2047c0da6274SZhi-Jun Robin Fu 		bus_p->bus_rp_dip = dip;
2048eae2e508Skrishnae 		bus_p->bus_rp_bdf = bus_p->bus_bdf;
20495b2c4190SRobert Mustacchi 
20505b2c4190SRobert Mustacchi 		bus_p->bus_fab = PCIE_ZALLOC(pcie_fabric_data_t);
2051bf8fc234Set 	} else {
2052c0da6274SZhi-Jun Robin Fu 		for (pdip = ddi_get_parent(dip); pdip;
2053eae2e508Skrishnae 		    pdip = ddi_get_parent(pdip)) {
2054eae2e508Skrishnae 			pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
2055eae2e508Skrishnae 
2056c0da6274SZhi-Jun Robin Fu 			/*
2057c0da6274SZhi-Jun Robin Fu 			 * If RP dip and RP bdf in parent's bus_t have
2058c0da6274SZhi-Jun Robin Fu 			 * been initialized, simply use these instead of
2059c0da6274SZhi-Jun Robin Fu 			 * continuing up to the RC.
2060c0da6274SZhi-Jun Robin Fu 			 */
2061c0da6274SZhi-Jun Robin Fu 			if (parent_bus_p->bus_rp_dip != NULL) {
2062c0da6274SZhi-Jun Robin Fu 				bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
2063c0da6274SZhi-Jun Robin Fu 				bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
2064c0da6274SZhi-Jun Robin Fu 				break;
2065c0da6274SZhi-Jun Robin Fu 			}
2066c0da6274SZhi-Jun Robin Fu 
2067eae2e508Skrishnae 			/*
2068eae2e508Skrishnae 			 * When debugging be aware that some NVIDIA x86
2069eae2e508Skrishnae 			 * architectures have 2 nodes for each RP, One at Bus
2070eae2e508Skrishnae 			 * 0x0 and one at Bus 0x80.  The requester is from Bus
2071eae2e508Skrishnae 			 * 0x80
2072eae2e508Skrishnae 			 */
2073eae2e508Skrishnae 			if (PCIE_IS_ROOT(parent_bus_p)) {
2074eae2e508Skrishnae 				bus_p->bus_rp_dip = pdip;
2075eae2e508Skrishnae 				bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
2076eae2e508Skrishnae 				break;
2077eae2e508Skrishnae 			}
2078eae2e508Skrishnae 		}
207944961713Sgirish 	}
2080c9f965e3Set 
2081c0da6274SZhi-Jun Robin Fu 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
208279bed773SHans Rosenfeld 	(void) atomic_swap_uint(&bus_p->bus_fm_flags, 0);
2083c0da6274SZhi-Jun Robin Fu 
2084c0da6274SZhi-Jun Robin Fu 	ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
2085eae2e508Skrishnae 
2086c0da6274SZhi-Jun Robin Fu 	if (PCIE_IS_HOTPLUG_CAPABLE(dip))
2087c0da6274SZhi-Jun Robin Fu 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
208826947304SEvan Yan 		    "hotplug-capable");
208926947304SEvan Yan 
2090c0da6274SZhi-Jun Robin Fu initial_done:
2091c0da6274SZhi-Jun Robin Fu 	if (!(flags & PCIE_BUS_FINAL))
2092c0da6274SZhi-Jun Robin Fu 		goto final_done;
2093bf8fc234Set 
2094c0da6274SZhi-Jun Robin Fu 	/* already initialized? */
2095c0da6274SZhi-Jun Robin Fu 	bus_p = PCIE_DIP2BUS(dip);
2096c0da6274SZhi-Jun Robin Fu 
2097c0da6274SZhi-Jun Robin Fu 	/* Save the Range information if device is a switch/bridge */
2098c0da6274SZhi-Jun Robin Fu 	if (PCIE_IS_BDG(bus_p)) {
2099c0da6274SZhi-Jun Robin Fu 		/* get "bus_range" property */
2100c0da6274SZhi-Jun Robin Fu 		range_size = sizeof (pci_bus_range_t);
2101c0da6274SZhi-Jun Robin Fu 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2102c0da6274SZhi-Jun Robin Fu 		    "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
2103c0da6274SZhi-Jun Robin Fu 		    != DDI_PROP_SUCCESS) {
2104c0da6274SZhi-Jun Robin Fu 			errstr = "Cannot find \"bus-range\" property";
2105c0da6274SZhi-Jun Robin Fu 			cmn_err(CE_WARN,
2106c0da6274SZhi-Jun Robin Fu 			    "PCIE init err info failed BDF 0x%x:%s\n",
2107c0da6274SZhi-Jun Robin Fu 			    bus_p->bus_bdf, errstr);
2108c0da6274SZhi-Jun Robin Fu 		}
2109c0da6274SZhi-Jun Robin Fu 
2110c0da6274SZhi-Jun Robin Fu 		/* get secondary bus number */
2111c0da6274SZhi-Jun Robin Fu 		rcdip = pcie_get_rc_dip(dip);
2112c0da6274SZhi-Jun Robin Fu 		ASSERT(rcdip != NULL);
2113c0da6274SZhi-Jun Robin Fu 
2114c0da6274SZhi-Jun Robin Fu 		bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
2115c0da6274SZhi-Jun Robin Fu 		    bus_p->bus_bdf, PCI_BCNF_SECBUS);
2116c0da6274SZhi-Jun Robin Fu 
2117c0da6274SZhi-Jun Robin Fu 		/* Get "ranges" property */
2118c0da6274SZhi-Jun Robin Fu 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2119c0da6274SZhi-Jun Robin Fu 		    "ranges", (caddr_t)&bus_p->bus_addr_ranges,
2120c0da6274SZhi-Jun Robin Fu 		    &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
2121c0da6274SZhi-Jun Robin Fu 			bus_p->bus_addr_entries = 0;
2122c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
2123c0da6274SZhi-Jun Robin Fu 	}
2124c0da6274SZhi-Jun Robin Fu 
2125c0da6274SZhi-Jun Robin Fu 	/* save "assigned-addresses" property array, ignore failues */
2126c0da6274SZhi-Jun Robin Fu 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2127c0da6274SZhi-Jun Robin Fu 	    "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
2128c0da6274SZhi-Jun Robin Fu 	    &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
2129c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
2130c0da6274SZhi-Jun Robin Fu 	else
2131c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries = 0;
2132c0da6274SZhi-Jun Robin Fu 
2133c0da6274SZhi-Jun Robin Fu 	pcie_init_pfd(dip);
21340114761dSAlan Adamson, SD OSSD 
2135c0da6274SZhi-Jun Robin Fu 	pcie_init_plat(dip);
2136c0da6274SZhi-Jun Robin Fu 
21377687d0d8SRobert Mustacchi 	pcie_capture_speeds(dip);
21387687d0d8SRobert Mustacchi 
2139c0da6274SZhi-Jun Robin Fu final_done:
2140fc51f9bbSKrishna Elango 
2141bf8fc234Set 	PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
2142c0da6274SZhi-Jun Robin Fu 	    ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
2143eae2e508Skrishnae 	    bus_p->bus_bdg_secbus);
2144eae2e508Skrishnae #ifdef DEBUG
2145b3d69c05SRobert Mustacchi 	if (bus_p != NULL) {
2146b3d69c05SRobert Mustacchi 		pcie_print_bus(bus_p);
2147b3d69c05SRobert Mustacchi 	}
2148eae2e508Skrishnae #endif
2149bf8fc234Set 
2150eae2e508Skrishnae 	return (bus_p);
2151c0da6274SZhi-Jun Robin Fu }
2152c0da6274SZhi-Jun Robin Fu 
2153c0da6274SZhi-Jun Robin Fu /*
2154c0da6274SZhi-Jun Robin Fu  * Invoked before destroying devinfo node, mostly during hotplug
2155c0da6274SZhi-Jun Robin Fu  * operation to free pcie_bus_t data structure
2156c0da6274SZhi-Jun Robin Fu  */
2157c0da6274SZhi-Jun Robin Fu /* ARGSUSED */
2158c0da6274SZhi-Jun Robin Fu void
pcie_fini_bus(dev_info_t * dip,uint8_t flags)2159c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dev_info_t *dip, uint8_t flags)
2160c0da6274SZhi-Jun Robin Fu {
2161c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2162c0da6274SZhi-Jun Robin Fu 	ASSERT(bus_p);
2163c0da6274SZhi-Jun Robin Fu 
2164c0da6274SZhi-Jun Robin Fu 	if (flags & PCIE_BUS_INITIAL) {
2165c0da6274SZhi-Jun Robin Fu 		pcie_fini_plat(dip);
2166c0da6274SZhi-Jun Robin Fu 		pcie_fini_pfd(dip);
2167c0da6274SZhi-Jun Robin Fu 
21685b2c4190SRobert Mustacchi 		if (PCIE_IS_RP(bus_p)) {
21695b2c4190SRobert Mustacchi 			kmem_free(bus_p->bus_fab, sizeof (pcie_fabric_data_t));
21705b2c4190SRobert Mustacchi 			bus_p->bus_fab = NULL;
21715b2c4190SRobert Mustacchi 		}
21725b2c4190SRobert Mustacchi 
2173c0da6274SZhi-Jun Robin Fu 		kmem_free(bus_p->bus_assigned_addr,
2174c0da6274SZhi-Jun Robin Fu 		    (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
2175c0da6274SZhi-Jun Robin Fu 		kmem_free(bus_p->bus_addr_ranges,
2176c0da6274SZhi-Jun Robin Fu 		    (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
2177c0da6274SZhi-Jun Robin Fu 		/* zero out the fields that have been destroyed */
2178c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_addr = NULL;
2179c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_ranges = NULL;
2180c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries = 0;
2181c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_entries = 0;
2182c0da6274SZhi-Jun Robin Fu 	}
2183c0da6274SZhi-Jun Robin Fu 
2184c0da6274SZhi-Jun Robin Fu 	if (flags & PCIE_BUS_FINAL) {
2185c0da6274SZhi-Jun Robin Fu 		if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
2186c0da6274SZhi-Jun Robin Fu 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
2187c0da6274SZhi-Jun Robin Fu 			    "hotplug-capable");
2188c0da6274SZhi-Jun Robin Fu 		}
2189c0da6274SZhi-Jun Robin Fu 
2190296f12dcSToomas Soome 		ndi_set_bus_private(dip, B_TRUE, 0, NULL);
2191c0da6274SZhi-Jun Robin Fu 		kmem_free(bus_p, sizeof (pcie_bus_t));
2192c0da6274SZhi-Jun Robin Fu 	}
2193f8d2de6bSjchu }
2194f8d2de6bSjchu 
219513683ea2Skrishnae int
pcie_postattach_child(dev_info_t * cdip)2196eae2e508Skrishnae pcie_postattach_child(dev_info_t *cdip)
219713683ea2Skrishnae {
2198eae2e508Skrishnae 	pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
219913683ea2Skrishnae 
2200eae2e508Skrishnae 	if (!bus_p)
220113683ea2Skrishnae 		return (DDI_FAILURE);
220213683ea2Skrishnae 
2203eae2e508Skrishnae 	return (pcie_enable_ce(cdip));
220413683ea2Skrishnae }
2205f8d2de6bSjchu 
2206f8d2de6bSjchu /*
2207f8d2de6bSjchu  * PCI-Express child device de-initialization.
2208f8d2de6bSjchu  * This function disables generic pci-express interrupts and error
2209f8d2de6bSjchu  * handling.
2210f8d2de6bSjchu  */
2211f8d2de6bSjchu void
pcie_uninitchild(dev_info_t * cdip)2212f8d2de6bSjchu pcie_uninitchild(dev_info_t *cdip)
2213f8d2de6bSjchu {
2214eae2e508Skrishnae 	pcie_disable_errors(cdip);
2215c0da6274SZhi-Jun Robin Fu 	pcie_fini_cfghdl(cdip);
2216fc256490SJason Beloro 	pcie_fini_dom(cdip);
2217c0da6274SZhi-Jun Robin Fu }
2218c0da6274SZhi-Jun Robin Fu 
2219c0da6274SZhi-Jun Robin Fu /*
2220c0da6274SZhi-Jun Robin Fu  * find the root complex dip
2221c0da6274SZhi-Jun Robin Fu  */
2222c0da6274SZhi-Jun Robin Fu dev_info_t *
pcie_get_rc_dip(dev_info_t * dip)2223c0da6274SZhi-Jun Robin Fu pcie_get_rc_dip(dev_info_t *dip)
2224c0da6274SZhi-Jun Robin Fu {
2225c0da6274SZhi-Jun Robin Fu 	dev_info_t *rcdip;
2226c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *rc_bus_p;
2227c0da6274SZhi-Jun Robin Fu 
2228c0da6274SZhi-Jun Robin Fu 	for (rcdip = ddi_get_parent(dip); rcdip;
2229c0da6274SZhi-Jun Robin Fu 	    rcdip = ddi_get_parent(rcdip)) {
2230c0da6274SZhi-Jun Robin Fu 		rc_bus_p = PCIE_DIP2BUS(rcdip);
2231c0da6274SZhi-Jun Robin Fu 		if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
2232c0da6274SZhi-Jun Robin Fu 			break;
2233c0da6274SZhi-Jun Robin Fu 	}
2234c0da6274SZhi-Jun Robin Fu 
2235c0da6274SZhi-Jun Robin Fu 	return (rcdip);
2236c0da6274SZhi-Jun Robin Fu }
2237c0da6274SZhi-Jun Robin Fu 
22389b3f4fe3SHans Rosenfeld boolean_t
pcie_is_pci_device(dev_info_t * dip)2239c0da6274SZhi-Jun Robin Fu pcie_is_pci_device(dev_info_t *dip)
2240c0da6274SZhi-Jun Robin Fu {
2241c0da6274SZhi-Jun Robin Fu 	dev_info_t	*pdip;
2242c0da6274SZhi-Jun Robin Fu 	char		*device_type;
2243c0da6274SZhi-Jun Robin Fu 
2244c0da6274SZhi-Jun Robin Fu 	pdip = ddi_get_parent(dip);
22459b3f4fe3SHans Rosenfeld 	if (pdip == NULL)
22469b3f4fe3SHans Rosenfeld 		return (B_FALSE);
2247c0da6274SZhi-Jun Robin Fu 
2248c0da6274SZhi-Jun Robin Fu 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
2249c0da6274SZhi-Jun Robin Fu 	    "device_type", &device_type) != DDI_PROP_SUCCESS)
2250c0da6274SZhi-Jun Robin Fu 		return (B_FALSE);
2251c0da6274SZhi-Jun Robin Fu 
2252c0da6274SZhi-Jun Robin Fu 	if (strcmp(device_type, "pciex") != 0 &&
2253c0da6274SZhi-Jun Robin Fu 	    strcmp(device_type, "pci") != 0) {
2254c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(device_type);
2255c0da6274SZhi-Jun Robin Fu 		return (B_FALSE);
2256c0da6274SZhi-Jun Robin Fu 	}
2257c0da6274SZhi-Jun Robin Fu 
2258c0da6274SZhi-Jun Robin Fu 	ddi_prop_free(device_type);
2259c0da6274SZhi-Jun Robin Fu 	return (B_TRUE);
2260c0da6274SZhi-Jun Robin Fu }
2261c0da6274SZhi-Jun Robin Fu 
2262c0da6274SZhi-Jun Robin Fu typedef struct {
2263c0da6274SZhi-Jun Robin Fu 	boolean_t	init;
2264c0da6274SZhi-Jun Robin Fu 	uint8_t		flags;
2265c0da6274SZhi-Jun Robin Fu } pcie_bus_arg_t;
2266c0da6274SZhi-Jun Robin Fu 
2267c0da6274SZhi-Jun Robin Fu /*ARGSUSED*/
2268c0da6274SZhi-Jun Robin Fu static int
pcie_fab_do_init_fini(dev_info_t * dip,void * arg)2269c0da6274SZhi-Jun Robin Fu pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
2270c0da6274SZhi-Jun Robin Fu {
2271c0da6274SZhi-Jun Robin Fu 	pcie_req_id_t	bdf;
2272c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	*bus_arg = (pcie_bus_arg_t *)arg;
2273c0da6274SZhi-Jun Robin Fu 
2274c0da6274SZhi-Jun Robin Fu 	if (!pcie_is_pci_device(dip))
2275c0da6274SZhi-Jun Robin Fu 		goto out;
2276c0da6274SZhi-Jun Robin Fu 
2277c0da6274SZhi-Jun Robin Fu 	if (bus_arg->init) {
2278c0da6274SZhi-Jun Robin Fu 		if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
2279c0da6274SZhi-Jun Robin Fu 			goto out;
2280c0da6274SZhi-Jun Robin Fu 
2281c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(dip, bdf, bus_arg->flags);
2282c0da6274SZhi-Jun Robin Fu 	} else {
2283c0da6274SZhi-Jun Robin Fu 		(void) pcie_fini_bus(dip, bus_arg->flags);
2284c0da6274SZhi-Jun Robin Fu 	}
2285c0da6274SZhi-Jun Robin Fu 
2286c0da6274SZhi-Jun Robin Fu 	return (DDI_WALK_CONTINUE);
2287c0da6274SZhi-Jun Robin Fu 
2288c0da6274SZhi-Jun Robin Fu out:
2289c0da6274SZhi-Jun Robin Fu 	return (DDI_WALK_PRUNECHILD);
2290bf8fc234Set }
2291e51949e6Sdduvall 
2292bf8fc234Set void
pcie_fab_init_bus(dev_info_t * rcdip,uint8_t flags)2293c0da6274SZhi-Jun Robin Fu pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
2294bf8fc234Set {
2295c0da6274SZhi-Jun Robin Fu 	dev_info_t	*dip = ddi_get_child(rcdip);
2296c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	arg;
22978bc7d88aSet 
2298c0da6274SZhi-Jun Robin Fu 	arg.init = B_TRUE;
2299c0da6274SZhi-Jun Robin Fu 	arg.flags = flags;
23008bc7d88aSet 
23013fe80ca4SDan Cross 	ndi_devi_enter(rcdip);
2302c0da6274SZhi-Jun Robin Fu 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
23033fe80ca4SDan Cross 	ndi_devi_exit(rcdip);
2304c0da6274SZhi-Jun Robin Fu }
230526947304SEvan Yan 
2306c0da6274SZhi-Jun Robin Fu void
pcie_fab_fini_bus(dev_info_t * rcdip,uint8_t flags)2307c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
2308c0da6274SZhi-Jun Robin Fu {
2309c0da6274SZhi-Jun Robin Fu 	dev_info_t	*dip = ddi_get_child(rcdip);
2310c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	arg;
231126947304SEvan Yan 
2312c0da6274SZhi-Jun Robin Fu 	arg.init = B_FALSE;
2313c0da6274SZhi-Jun Robin Fu 	arg.flags = flags;
2314c333dd99Sdm 
23153fe80ca4SDan Cross 	ndi_devi_enter(rcdip);
2316c0da6274SZhi-Jun Robin Fu 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
23173fe80ca4SDan Cross 	ndi_devi_exit(rcdip);
2318c333dd99Sdm }
2319f41150baSkrishnae 
2320c333dd99Sdm void
pcie_enable_errors(dev_info_t * dip)2321eae2e508Skrishnae pcie_enable_errors(dev_info_t *dip)
2322c333dd99Sdm {
2323eae2e508Skrishnae 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
2324eae2e508Skrishnae 	uint16_t	reg16, tmp16;
2325eae2e508Skrishnae 	uint32_t	reg32, tmp32;
2326eae2e508Skrishnae 
2327eae2e508Skrishnae 	ASSERT(bus_p);
232827255037Spjha 
23298bc7d88aSet 	/*
23308bc7d88aSet 	 * Clear any pending errors
23318bc7d88aSet 	 */
2332eae2e508Skrishnae 	pcie_clear_errors(dip);
23338bc7d88aSet 
2334eae2e508Skrishnae 	if (!PCIE_IS_PCIE(bus_p))
2335ba640a72Sjj 		return;
2336ba640a72Sjj 
2337f8d2de6bSjchu 	/*
233813683ea2Skrishnae 	 * Enable Baseline Error Handling but leave CE reporting off (poweron
233913683ea2Skrishnae 	 * default).
2340f8d2de6bSjchu 	 */
2341eae2e508Skrishnae 	if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
2342eae2e508Skrishnae 	    PCI_CAP_EINVAL16) {
23430114761dSAlan Adamson, SD OSSD 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
23440114761dSAlan Adamson, SD OSSD 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
23450114761dSAlan Adamson, SD OSSD 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
23460114761dSAlan Adamson, SD OSSD 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
23470114761dSAlan Adamson, SD OSSD 		    (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
23480114761dSAlan Adamson, SD OSSD 
2349eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
2350eae2e508Skrishnae 		PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
2351eae2e508Skrishnae 	}
2352eae2e508Skrishnae 
2353eae2e508Skrishnae 	/* Enable Root Port Baseline Error Receiving */
2354eae2e508Skrishnae 	if (PCIE_IS_ROOT(bus_p) &&
2355eae2e508Skrishnae 	    (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
2356eae2e508Skrishnae 	    PCI_CAP_EINVAL16) {
2357eae2e508Skrishnae 
2358eae2e508Skrishnae 		tmp16 = pcie_serr_disable_flag ?
2359eae2e508Skrishnae 		    (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
2360eae2e508Skrishnae 		    pcie_root_ctrl_default;
2361eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
2362eae2e508Skrishnae 		PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
2363eae2e508Skrishnae 		    reg16);
236427255037Spjha 	}
2365f8d2de6bSjchu 
2366f8d2de6bSjchu 	/*
2367f8d2de6bSjchu 	 * Enable PCI-Express Advanced Error Handling if Exists
2368f8d2de6bSjchu 	 */
2369eae2e508Skrishnae 	if (!PCIE_HAS_AER(bus_p))
2370f8d2de6bSjchu 		return;
2371eae2e508Skrishnae 
2372eae2e508Skrishnae 	/* Set Uncorrectable Severity */
2373eae2e508Skrishnae 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
2374eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
2375eae2e508Skrishnae 		tmp32 = pcie_aer_uce_severity;
2376eae2e508Skrishnae 
2377eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
2378eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
2379eae2e508Skrishnae 		    reg32);
2380f8d2de6bSjchu 	}
2381f8d2de6bSjchu 
2382f8d2de6bSjchu 	/* Enable Uncorrectable errors */
2383eae2e508Skrishnae 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
2384eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
2385eae2e508Skrishnae 		tmp32 = pcie_aer_uce_mask;
2386eae2e508Skrishnae 
2387eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
2388eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
2389eae2e508Skrishnae 		    reg32);
239027255037Spjha 	}
2391f8d2de6bSjchu 
23924eacc763Sjj 	/* Enable ECRC generation and checking */
2393eae2e508Skrishnae 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
2394eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
2395eae2e508Skrishnae 		tmp32 = reg32 | pcie_ecrc_value;
2396eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
2397eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
2398eae2e508Skrishnae 	}
2399eae2e508Skrishnae 
2400eae2e508Skrishnae 	/* Enable Secondary Uncorrectable errors if this is a bridge */
2401eae2e508Skrishnae 	if (!PCIE_IS_PCIE_BDG(bus_p))
2402eae2e508Skrishnae 		goto root;
2403eae2e508Skrishnae 
2404eae2e508Skrishnae 	/* Set Uncorrectable Severity */
2405eae2e508Skrishnae 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
2406eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
2407eae2e508Skrishnae 		tmp32 = pcie_aer_suce_severity;
24084eacc763Sjj 
2409eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
2410eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
2411eae2e508Skrishnae 		    reg32);
2412f41150baSkrishnae 	}
2413f41150baSkrishnae 
2414eae2e508Skrishnae 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
2415eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
2416eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
2417eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
2418eae2e508Skrishnae 		    PCIE_AER_SUCE_MASK, reg32);
2419eae2e508Skrishnae 	}
2420eae2e508Skrishnae 
2421eae2e508Skrishnae root:
2422f8d2de6bSjchu 	/*
2423eae2e508Skrishnae 	 * Enable Root Control this is a Root device
2424f8d2de6bSjchu 	 */
2425eae2e508Skrishnae 	if (!PCIE_IS_ROOT(bus_p))
2426f8d2de6bSjchu 		return;
2427f8d2de6bSjchu 
2428eae2e508Skrishnae 	if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
2429eae2e508Skrishnae 	    PCI_CAP_EINVAL16) {
2430eae2e508Skrishnae 		PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
2431eae2e508Skrishnae 		    pcie_root_error_cmd_default);
2432eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
2433eae2e508Skrishnae 		    PCIE_AER_RE_CMD, reg16);
243427255037Spjha 	}
2435f8d2de6bSjchu }
2436f8d2de6bSjchu 
243713683ea2Skrishnae /*
243813683ea2Skrishnae  * This function is used for enabling CE reporting and setting the AER CE mask.
243913683ea2Skrishnae  * When called from outside the pcie module it should always be preceded by
244013683ea2Skrishnae  * a call to pcie_enable_errors.
244113683ea2Skrishnae  */
244213683ea2Skrishnae int
pcie_enable_ce(dev_info_t * dip)2443eae2e508Skrishnae pcie_enable_ce(dev_info_t *dip)
244413683ea2Skrishnae {
2445eae2e508Skrishnae 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
2446eae2e508Skrishnae 	uint16_t	device_sts, device_ctl;
244713683ea2Skrishnae 	uint32_t	tmp_pcie_aer_ce_mask;
244813683ea2Skrishnae 
2449eae2e508Skrishnae 	if (!PCIE_IS_PCIE(bus_p))
2450eae2e508Skrishnae 		return (DDI_SUCCESS);
245113683ea2Skrishnae 
245213683ea2Skrishnae 	/*
245313683ea2Skrishnae 	 * The "pcie_ce_mask" property is used to control both the CE reporting
245413683ea2Skrishnae 	 * enable field in the device control register and the AER CE mask. We
245513683ea2Skrishnae 	 * leave CE reporting disabled if pcie_ce_mask is set to -1.
245613683ea2Skrishnae 	 */
245713683ea2Skrishnae 
245813683ea2Skrishnae 	tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
245913683ea2Skrishnae 	    DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
246013683ea2Skrishnae 
2461eae2e508Skrishnae 	if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
246213683ea2Skrishnae 		/*
246313683ea2Skrishnae 		 * Nothing to do since CE reporting has already been disabled.
246413683ea2Skrishnae 		 */
246513683ea2Skrishnae 		return (DDI_SUCCESS);
246613683ea2Skrishnae 	}
246713683ea2Skrishnae 
2468eae2e508Skrishnae 	if (PCIE_HAS_AER(bus_p)) {
246913683ea2Skrishnae 		/* Enable AER CE */
2470eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
2471eae2e508Skrishnae 		PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
2472eae2e508Skrishnae 		    0);
247313683ea2Skrishnae 
247413683ea2Skrishnae 		/* Clear any pending AER CE errors */
2475eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
247613683ea2Skrishnae 	}
247713683ea2Skrishnae 
247813683ea2Skrishnae 	/* clear any pending CE errors */
2479eae2e508Skrishnae 	if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
2480eae2e508Skrishnae 	    PCI_CAP_EINVAL16)
2481eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
2482eae2e508Skrishnae 		    device_sts & (~PCIE_DEVSTS_CE_DETECTED));
248313683ea2Skrishnae 
248413683ea2Skrishnae 	/* Enable CE reporting */
2485eae2e508Skrishnae 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
2486eae2e508Skrishnae 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
2487eae2e508Skrishnae 	    (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
2488eae2e508Skrishnae 	PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
2489eae2e508Skrishnae 
249013683ea2Skrishnae 	return (DDI_SUCCESS);
249113683ea2Skrishnae }
249213683ea2Skrishnae 
2493f8d2de6bSjchu /* ARGSUSED */
2494c73ac1a6Sjchu void
pcie_disable_errors(dev_info_t * dip)2495eae2e508Skrishnae pcie_disable_errors(dev_info_t *dip)
2496f8d2de6bSjchu {
2497eae2e508Skrishnae 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
2498eae2e508Skrishnae 	uint16_t	device_ctl;
2499eae2e508Skrishnae 	uint32_t	aer_reg;
250027255037Spjha 
2501eae2e508Skrishnae 	if (!PCIE_IS_PCIE(bus_p))
2502ba640a72Sjj 		return;
2503ba640a72Sjj 
2504f8d2de6bSjchu 	/*
2505f8d2de6bSjchu 	 * Disable PCI-Express Baseline Error Handling
2506f8d2de6bSjchu 	 */
2507eae2e508Skrishnae 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
250895ad88f0Sraghuram 	device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
2509eae2e508Skrishnae 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
2510f8d2de6bSjchu 
2511f8d2de6bSjchu 	/*
2512f8d2de6bSjchu 	 * Disable PCI-Express Advanced Error Handling if Exists
2513f8d2de6bSjchu 	 */
2514eae2e508Skrishnae 	if (!PCIE_HAS_AER(bus_p))
2515eae2e508Skrishnae 		goto root;
2516f8d2de6bSjchu 
2517f8d2de6bSjchu 	/* Disable Uncorrectable errors */
2518eae2e508Skrishnae 	PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
2519f8d2de6bSjchu 
2520f8d2de6bSjchu 	/* Disable Correctable errors */
2521eae2e508Skrishnae 	PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
2522f8d2de6bSjchu 
25234eacc763Sjj 	/* Disable ECRC generation and checking */
2524eae2e508Skrishnae 	if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
2525eae2e508Skrishnae 	    PCI_CAP_EINVAL32) {
25264eacc763Sjj 		aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
25274eacc763Sjj 		    PCIE_AER_CTL_ECRC_CHECK_ENA);
25284eacc763Sjj 
2529eae2e508Skrishnae 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
25304eacc763Sjj 	}
2531f8d2de6bSjchu 	/*
2532f8d2de6bSjchu 	 * Disable Secondary Uncorrectable errors if this is a bridge
2533f8d2de6bSjchu 	 */
2534eae2e508Skrishnae 	if (!PCIE_IS_PCIE_BDG(bus_p))
2535eae2e508Skrishnae 		goto root;
2536eae2e508Skrishnae 
2537eae2e508Skrishnae 	PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
2538f8d2de6bSjchu 
2539eae2e508Skrishnae root:
2540f8d2de6bSjchu 	/*
2541eae2e508Skrishnae 	 * disable Root Control this is a Root device
2542f8d2de6bSjchu 	 */
2543eae2e508Skrishnae 	if (!PCIE_IS_ROOT(bus_p))
2544eae2e508Skrishnae 		return;
2545eae2e508Skrishnae 
2546eae2e508Skrishnae 	if (!pcie_serr_disable_flag) {
2547eae2e508Skrishnae 		device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
2548eae2e508Skrishnae 		device_ctl &= ~PCIE_ROOT_SYS_ERR;
2549eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
2550eae2e508Skrishnae 	}
2551eae2e508Skrishnae 
2552eae2e508Skrishnae 	if (!PCIE_HAS_AER(bus_p))
2553eae2e508Skrishnae 		return;
2554eae2e508Skrishnae 
2555eae2e508Skrishnae 	if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
2556eae2e508Skrishnae 	    PCI_CAP_EINVAL16) {
2557eae2e508Skrishnae 		device_ctl &= ~pcie_root_error_cmd_default;
2558eae2e508Skrishnae 		PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
2559eae2e508Skrishnae 	}
2560f8d2de6bSjchu }
2561f8d2de6bSjchu 
2562bf8fc234Set /*
2563bf8fc234Set  * Extract bdf from "reg" property.
2564bf8fc234Set  */
2565bf8fc234Set int
pcie_get_bdf_from_dip(dev_info_t * dip,pcie_req_id_t * bdf)2566bf8fc234Set pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
256744961713Sgirish {
256844961713Sgirish 	pci_regspec_t	*regspec;
256944961713Sgirish 	int		reglen;
257044961713Sgirish 
257144961713Sgirish 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
257244961713Sgirish 	    "reg", (int **)&regspec, (uint_t *)&reglen) != DDI_SUCCESS)
257344961713Sgirish 		return (DDI_FAILURE);
257444961713Sgirish 
257544961713Sgirish 	if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
257644961713Sgirish 		ddi_prop_free(regspec);
257744961713Sgirish 		return (DDI_FAILURE);
257844961713Sgirish 	}
257944961713Sgirish 
258044961713Sgirish 	/* Get phys_hi from first element.  All have same bdf. */
258144961713Sgirish 	*bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
258244961713Sgirish 
258344961713Sgirish 	ddi_prop_free(regspec);
258444961713Sgirish 	return (DDI_SUCCESS);
258544961713Sgirish }
258644961713Sgirish 
258744961713Sgirish dev_info_t *
pcie_get_my_childs_dip(dev_info_t * dip,dev_info_t * rdip)258844961713Sgirish pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
258944961713Sgirish {
259044961713Sgirish 	dev_info_t *cdip = rdip;
259144961713Sgirish 
259244961713Sgirish 	for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
259344961713Sgirish 		;
259444961713Sgirish 
259544961713Sgirish 	return (cdip);
259644961713Sgirish }
259744961713Sgirish 
25987c9e29aaSgovinda uint32_t
pcie_get_bdf_for_dma_xfer(dev_info_t * dip,dev_info_t * rdip)25997c9e29aaSgovinda pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
26007c9e29aaSgovinda {
26017c9e29aaSgovinda 	dev_info_t *cdip;
26027c9e29aaSgovinda 
26037c9e29aaSgovinda 	/*
26047c9e29aaSgovinda 	 * As part of the probing, the PCI fcode interpreter may setup a DMA
26057c9e29aaSgovinda 	 * request if a given card has a fcode on it using dip and rdip of the
260626947304SEvan Yan 	 * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
2607c85864d8SKrishna Elango 	 * case, return a invalid value for the bdf since we cannot get to the
2608c85864d8SKrishna Elango 	 * bdf value of the actual device which will be initiating this DMA.
26097c9e29aaSgovinda 	 */
26107c9e29aaSgovinda 	if (rdip == dip)
2611c85864d8SKrishna Elango 		return (PCIE_INVALID_BDF);
26127c9e29aaSgovinda 
26137c9e29aaSgovinda 	cdip = pcie_get_my_childs_dip(dip, rdip);
26147c9e29aaSgovinda 
26157c9e29aaSgovinda 	/*
2616d4bc0535SKrishna Elango 	 * For a given rdip, return the bdf value of dip's (px or pcieb)
26177c9e29aaSgovinda 	 * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
26183aa1cd26Sgovinda 	 *
2619c85864d8SKrishna Elango 	 * XXX - For now, return a invalid bdf value for all PCI and PCI-X
2620c85864d8SKrishna Elango 	 * devices since this needs more work.
26217c9e29aaSgovinda 	 */
2622c85864d8SKrishna Elango 	return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
2623c85864d8SKrishna Elango 	    PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
26247c9e29aaSgovinda }
26257c9e29aaSgovinda 
2626eae2e508Skrishnae uint32_t
pcie_get_aer_uce_mask()2627826c0d1dSRobert Mustacchi pcie_get_aer_uce_mask()
2628826c0d1dSRobert Mustacchi {
2629eae2e508Skrishnae 	return (pcie_aer_uce_mask);
2630eae2e508Skrishnae }
2631eae2e508Skrishnae uint32_t
pcie_get_aer_ce_mask()2632826c0d1dSRobert Mustacchi pcie_get_aer_ce_mask()
2633826c0d1dSRobert Mustacchi {
2634eae2e508Skrishnae 	return (pcie_aer_ce_mask);
2635eae2e508Skrishnae }
2636eae2e508Skrishnae uint32_t
pcie_get_aer_suce_mask()2637826c0d1dSRobert Mustacchi pcie_get_aer_suce_mask()
2638826c0d1dSRobert Mustacchi {
2639eae2e508Skrishnae 	return (pcie_aer_suce_mask);
2640eae2e508Skrishnae }
2641eae2e508Skrishnae uint32_t
pcie_get_serr_mask()2642826c0d1dSRobert Mustacchi pcie_get_serr_mask()
2643826c0d1dSRobert Mustacchi {
2644eae2e508Skrishnae 	return (pcie_serr_disable_flag);
2645eae2e508Skrishnae }
2646eae2e508Skrishnae 
2647eae2e508Skrishnae void
pcie_set_aer_uce_mask(uint32_t mask)2648826c0d1dSRobert Mustacchi pcie_set_aer_uce_mask(uint32_t mask)
2649826c0d1dSRobert Mustacchi {
2650eae2e508Skrishnae 	pcie_aer_uce_mask = mask;
2651eae2e508Skrishnae 	if (mask & PCIE_AER_UCE_UR)
2652eae2e508Skrishnae 		pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
2653eae2e508Skrishnae 	else
2654eae2e508Skrishnae 		pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
2655eae2e508Skrishnae 
2656eae2e508Skrishnae 	if (mask & PCIE_AER_UCE_ECRC)
2657eae2e508Skrishnae 		pcie_ecrc_value = 0;
2658eae2e508Skrishnae }
2659eae2e508Skrishnae 
2660eae2e508Skrishnae void
pcie_set_aer_ce_mask(uint32_t mask)2661826c0d1dSRobert Mustacchi pcie_set_aer_ce_mask(uint32_t mask)
2662826c0d1dSRobert Mustacchi {
2663eae2e508Skrishnae 	pcie_aer_ce_mask = mask;
2664eae2e508Skrishnae }
2665eae2e508Skrishnae void
pcie_set_aer_suce_mask(uint32_t mask)2666826c0d1dSRobert Mustacchi pcie_set_aer_suce_mask(uint32_t mask)
2667826c0d1dSRobert Mustacchi {
2668eae2e508Skrishnae 	pcie_aer_suce_mask = mask;
2669eae2e508Skrishnae }
2670eae2e508Skrishnae void
pcie_set_serr_mask(uint32_t mask)2671826c0d1dSRobert Mustacchi pcie_set_serr_mask(uint32_t mask)
2672826c0d1dSRobert Mustacchi {
2673eae2e508Skrishnae 	pcie_serr_disable_flag = mask;
2674bf8fc234Set }
2675bf8fc234Set 
2676bf8fc234Set /*
2677bf8fc234Set  * Is the rdip a child of dip.	Used for checking certain CTLOPS from bubbling
2678bf8fc234Set  * up erronously.  Ex.	ISA ctlops to a PCI-PCI Bridge.
2679bf8fc234Set  */
2680bf8fc234Set boolean_t
pcie_is_child(dev_info_t * dip,dev_info_t * rdip)2681bf8fc234Set pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
2682bf8fc234Set {
2683bf8fc234Set 	dev_info_t	*cdip = ddi_get_child(dip);
2684bf8fc234Set 	for (; cdip; cdip = ddi_get_next_sibling(cdip))
2685bf8fc234Set 		if (cdip == rdip)
2686bf8fc234Set 			break;
2687bf8fc234Set 	return (cdip != NULL);
2688bf8fc234Set }
2689bf8fc234Set 
2690eae2e508Skrishnae boolean_t
pcie_is_link_disabled(dev_info_t * dip)2691eae2e508Skrishnae pcie_is_link_disabled(dev_info_t *dip)
2692eae2e508Skrishnae {
2693eae2e508Skrishnae 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
2694eae2e508Skrishnae 
2695eae2e508Skrishnae 	if (PCIE_IS_PCIE(bus_p)) {
2696eae2e508Skrishnae 		if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
2697eae2e508Skrishnae 		    PCIE_LINKCTL_LINK_DISABLE)
2698eae2e508Skrishnae 			return (B_TRUE);
2699eae2e508Skrishnae 	}
2700eae2e508Skrishnae 	return (B_FALSE);
2701eae2e508Skrishnae }
2702eae2e508Skrishnae 
27030114761dSAlan Adamson, SD OSSD /*
27040114761dSAlan Adamson, SD OSSD  * Determines if there are any root ports attached to a root complex.
27050114761dSAlan Adamson, SD OSSD  *
27060114761dSAlan Adamson, SD OSSD  * dip - dip of root complex
27070114761dSAlan Adamson, SD OSSD  *
27080114761dSAlan Adamson, SD OSSD  * Returns - DDI_SUCCESS if there is at least one root port otherwise
270926947304SEvan Yan  *	     DDI_FAILURE.
27100114761dSAlan Adamson, SD OSSD  */
27110114761dSAlan Adamson, SD OSSD int
pcie_root_port(dev_info_t * dip)27120114761dSAlan Adamson, SD OSSD pcie_root_port(dev_info_t *dip)
27130114761dSAlan Adamson, SD OSSD {
27140114761dSAlan Adamson, SD OSSD 	int port_type;
27150114761dSAlan Adamson, SD OSSD 	uint16_t cap_ptr;
27160114761dSAlan Adamson, SD OSSD 	ddi_acc_handle_t config_handle;
27170114761dSAlan Adamson, SD OSSD 	dev_info_t *cdip = ddi_get_child(dip);
27180114761dSAlan Adamson, SD OSSD 
27190114761dSAlan Adamson, SD OSSD 	/*
27200114761dSAlan Adamson, SD OSSD 	 * Determine if any of the children of the passed in dip
27210114761dSAlan Adamson, SD OSSD 	 * are root ports.
27220114761dSAlan Adamson, SD OSSD 	 */
27230114761dSAlan Adamson, SD OSSD 	for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
27240114761dSAlan Adamson, SD OSSD 
27250114761dSAlan Adamson, SD OSSD 		if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
27260114761dSAlan Adamson, SD OSSD 			continue;
27270114761dSAlan Adamson, SD OSSD 
27280114761dSAlan Adamson, SD OSSD 		if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
27290114761dSAlan Adamson, SD OSSD 		    &cap_ptr)) == DDI_FAILURE) {
27300114761dSAlan Adamson, SD OSSD 			pci_config_teardown(&config_handle);
27310114761dSAlan Adamson, SD OSSD 			continue;
27320114761dSAlan Adamson, SD OSSD 		}
27330114761dSAlan Adamson, SD OSSD 
2734296f12dcSToomas Soome 		port_type = PCI_CAP_GET16(config_handle, 0, cap_ptr,
27350114761dSAlan Adamson, SD OSSD 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
27360114761dSAlan Adamson, SD OSSD 
27370114761dSAlan Adamson, SD OSSD 		pci_config_teardown(&config_handle);
27380114761dSAlan Adamson, SD OSSD 
27390114761dSAlan Adamson, SD OSSD 		if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
27400114761dSAlan Adamson, SD OSSD 			return (DDI_SUCCESS);
27410114761dSAlan Adamson, SD OSSD 	}
27420114761dSAlan Adamson, SD OSSD 
27430114761dSAlan Adamson, SD OSSD 	/* No root ports were found */
27440114761dSAlan Adamson, SD OSSD 
27450114761dSAlan Adamson, SD OSSD 	return (DDI_FAILURE);
27460114761dSAlan Adamson, SD OSSD }
27470114761dSAlan Adamson, SD OSSD 
27480114761dSAlan Adamson, SD OSSD /*
27490114761dSAlan Adamson, SD OSSD  * Function that determines if a device a PCIe device.
27500114761dSAlan Adamson, SD OSSD  *
27510114761dSAlan Adamson, SD OSSD  * dip - dip of device.
27520114761dSAlan Adamson, SD OSSD  *
27530114761dSAlan Adamson, SD OSSD  * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
27540114761dSAlan Adamson, SD OSSD  */
27550114761dSAlan Adamson, SD OSSD int
pcie_dev(dev_info_t * dip)27560114761dSAlan Adamson, SD OSSD pcie_dev(dev_info_t *dip)
27570114761dSAlan Adamson, SD OSSD {
27580114761dSAlan Adamson, SD OSSD 	/* get parent device's device_type property */
27590114761dSAlan Adamson, SD OSSD 	char *device_type;
27600114761dSAlan Adamson, SD OSSD 	int rc = DDI_FAILURE;
27610114761dSAlan Adamson, SD OSSD 	dev_info_t *pdip = ddi_get_parent(dip);
27620114761dSAlan Adamson, SD OSSD 
27630114761dSAlan Adamson, SD OSSD 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
27640114761dSAlan Adamson, SD OSSD 	    DDI_PROP_DONTPASS, "device_type", &device_type)
27650114761dSAlan Adamson, SD OSSD 	    != DDI_PROP_SUCCESS) {
27660114761dSAlan Adamson, SD OSSD 		return (DDI_FAILURE);
27670114761dSAlan Adamson, SD OSSD 	}
27680114761dSAlan Adamson, SD OSSD 
27690114761dSAlan Adamson, SD OSSD 	if (strcmp(device_type, "pciex") == 0)
27700114761dSAlan Adamson, SD OSSD 		rc = DDI_SUCCESS;
27710114761dSAlan Adamson, SD OSSD 	else
27720114761dSAlan Adamson, SD OSSD 		rc = DDI_FAILURE;
27730114761dSAlan Adamson, SD OSSD 
27740114761dSAlan Adamson, SD OSSD 	ddi_prop_free(device_type);
27750114761dSAlan Adamson, SD OSSD 	return (rc);
27760114761dSAlan Adamson, SD OSSD }
27770114761dSAlan Adamson, SD OSSD 
27783221df98SKrishna Elango void
pcie_set_rber_fatal(dev_info_t * dip,boolean_t val)27793221df98SKrishna Elango pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
27803221df98SKrishna Elango {
27813221df98SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
27823221df98SKrishna Elango 	bus_p->bus_pfd->pe_rber_fatal = val;
27833221df98SKrishna Elango }
27843221df98SKrishna Elango 
27853221df98SKrishna Elango /*
27863221df98SKrishna Elango  * Return parent Root Port's pe_rber_fatal value.
27873221df98SKrishna Elango  */
27883221df98SKrishna Elango boolean_t
pcie_get_rber_fatal(dev_info_t * dip)27893221df98SKrishna Elango pcie_get_rber_fatal(dev_info_t *dip)
27903221df98SKrishna Elango {
27913221df98SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
27923221df98SKrishna Elango 	pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
27933221df98SKrishna Elango 	return (rp_bus_p->bus_pfd->pe_rber_fatal);
27943221df98SKrishna Elango }
27953221df98SKrishna Elango 
279626947304SEvan Yan int
pcie_ari_supported(dev_info_t * dip)279726947304SEvan Yan pcie_ari_supported(dev_info_t *dip)
279826947304SEvan Yan {
279926947304SEvan Yan 	uint32_t devcap2;
280026947304SEvan Yan 	uint16_t pciecap;
280126947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
280226947304SEvan Yan 	uint8_t dev_type;
280326947304SEvan Yan 
280426947304SEvan Yan 	PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
280526947304SEvan Yan 
280626947304SEvan Yan 	if (bus_p == NULL)
280726947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
280826947304SEvan Yan 
280926947304SEvan Yan 	dev_type = bus_p->bus_dev_type;
281026947304SEvan Yan 
281126947304SEvan Yan 	if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
281226947304SEvan Yan 	    (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
281326947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
281426947304SEvan Yan 
281526947304SEvan Yan 	if (pcie_disable_ari) {
281626947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
281726947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
281826947304SEvan Yan 	}
281926947304SEvan Yan 
282026947304SEvan Yan 	pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
282126947304SEvan Yan 
282226947304SEvan Yan 	if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
282326947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
282426947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
282526947304SEvan Yan 	}
282626947304SEvan Yan 
282726947304SEvan Yan 	devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
282826947304SEvan Yan 
282926947304SEvan Yan 	PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
283026947304SEvan Yan 	    dip, devcap2);
283126947304SEvan Yan 
283226947304SEvan Yan 	if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
283326947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: "
283426947304SEvan Yan 		    "dip=%p: ARI Forwarding is supported\n", dip);
283526947304SEvan Yan 		return (PCIE_ARI_FORW_SUPPORTED);
283626947304SEvan Yan 	}
283726947304SEvan Yan 	return (PCIE_ARI_FORW_NOT_SUPPORTED);
283826947304SEvan Yan }
283926947304SEvan Yan 
284026947304SEvan Yan int
pcie_ari_enable(dev_info_t * dip)284126947304SEvan Yan pcie_ari_enable(dev_info_t *dip)
284226947304SEvan Yan {
284326947304SEvan Yan 	uint16_t devctl2;
284426947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
284526947304SEvan Yan 
284626947304SEvan Yan 	PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
284726947304SEvan Yan 
284826947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
284926947304SEvan Yan 		return (DDI_FAILURE);
285026947304SEvan Yan 
285126947304SEvan Yan 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
285226947304SEvan Yan 	devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
285326947304SEvan Yan 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
285426947304SEvan Yan 
285526947304SEvan Yan 	PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
285626947304SEvan Yan 	    dip, devctl2);
285726947304SEvan Yan 
285826947304SEvan Yan 	return (DDI_SUCCESS);
285926947304SEvan Yan }
286026947304SEvan Yan 
286126947304SEvan Yan int
pcie_ari_disable(dev_info_t * dip)286226947304SEvan Yan pcie_ari_disable(dev_info_t *dip)
286326947304SEvan Yan {
286426947304SEvan Yan 	uint16_t devctl2;
286526947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
286626947304SEvan Yan 
286726947304SEvan Yan 	PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
286826947304SEvan Yan 
286926947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
287026947304SEvan Yan 		return (DDI_FAILURE);
287126947304SEvan Yan 
287226947304SEvan Yan 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
287326947304SEvan Yan 	devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
287426947304SEvan Yan 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
287526947304SEvan Yan 
287626947304SEvan Yan 	PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
287726947304SEvan Yan 	    dip, devctl2);
287826947304SEvan Yan 
287926947304SEvan Yan 	return (DDI_SUCCESS);
288026947304SEvan Yan }
288126947304SEvan Yan 
288226947304SEvan Yan int
pcie_ari_is_enabled(dev_info_t * dip)288326947304SEvan Yan pcie_ari_is_enabled(dev_info_t *dip)
288426947304SEvan Yan {
288526947304SEvan Yan 	uint16_t devctl2;
288626947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
288726947304SEvan Yan 
288826947304SEvan Yan 	PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
288926947304SEvan Yan 
289026947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
289126947304SEvan Yan 		return (PCIE_ARI_FORW_DISABLED);
289226947304SEvan Yan 
289326947304SEvan Yan 	devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
289426947304SEvan Yan 
289526947304SEvan Yan 	PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
289626947304SEvan Yan 	    dip, devctl2);
289726947304SEvan Yan 
289826947304SEvan Yan 	if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
289926947304SEvan Yan 		PCIE_DBG("pcie_ari_is_enabled: "
290026947304SEvan Yan 		    "dip=%p: ARI Forwarding is enabled\n", dip);
290126947304SEvan Yan 		return (PCIE_ARI_FORW_ENABLED);
290226947304SEvan Yan 	}
290326947304SEvan Yan 
290426947304SEvan Yan 	return (PCIE_ARI_FORW_DISABLED);
290526947304SEvan Yan }
290626947304SEvan Yan 
290726947304SEvan Yan int
pcie_ari_device(dev_info_t * dip)290826947304SEvan Yan pcie_ari_device(dev_info_t *dip)
290926947304SEvan Yan {
291026947304SEvan Yan 	ddi_acc_handle_t handle;
291126947304SEvan Yan 	uint16_t cap_ptr;
291226947304SEvan Yan 
291326947304SEvan Yan 	PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
291426947304SEvan Yan 
291526947304SEvan Yan 	/*
291626947304SEvan Yan 	 * XXX - This function may be called before the bus_p structure
291726947304SEvan Yan 	 * has been populated.  This code can be changed to remove
291826947304SEvan Yan 	 * pci_config_setup()/pci_config_teardown() when the RFE
291926947304SEvan Yan 	 * to populate the bus_p structures early in boot is putback.
292026947304SEvan Yan 	 */
292126947304SEvan Yan 
292226947304SEvan Yan 	/* First make sure it is a PCIe device */
292326947304SEvan Yan 
292426947304SEvan Yan 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
292526947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
292626947304SEvan Yan 
292726947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
292826947304SEvan Yan 	    != DDI_SUCCESS) {
292926947304SEvan Yan 		pci_config_teardown(&handle);
293026947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
293126947304SEvan Yan 	}
293226947304SEvan Yan 
293326947304SEvan Yan 	/* Locate the ARI Capability */
293426947304SEvan Yan 
293526947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
293626947304SEvan Yan 	    &cap_ptr)) == DDI_FAILURE) {
293726947304SEvan Yan 		pci_config_teardown(&handle);
293826947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
293926947304SEvan Yan 	}
294026947304SEvan Yan 
294126947304SEvan Yan 	/* ARI Capability was found so it must be a ARI device */
294226947304SEvan Yan 	PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
294326947304SEvan Yan 
294426947304SEvan Yan 	pci_config_teardown(&handle);
294526947304SEvan Yan 	return (PCIE_ARI_DEVICE);
294626947304SEvan Yan }
294726947304SEvan Yan 
294826947304SEvan Yan int
pcie_ari_get_next_function(dev_info_t * dip,int * func)294926947304SEvan Yan pcie_ari_get_next_function(dev_info_t *dip, int *func)
295026947304SEvan Yan {
295126947304SEvan Yan 	uint32_t val;
295226947304SEvan Yan 	uint16_t cap_ptr, next_function;
295326947304SEvan Yan 	ddi_acc_handle_t handle;
295426947304SEvan Yan 
295526947304SEvan Yan 	/*
295626947304SEvan Yan 	 * XXX - This function may be called before the bus_p structure
295726947304SEvan Yan 	 * has been populated.  This code can be changed to remove
295826947304SEvan Yan 	 * pci_config_setup()/pci_config_teardown() when the RFE
295926947304SEvan Yan 	 * to populate the bus_p structures early in boot is putback.
296026947304SEvan Yan 	 */
296126947304SEvan Yan 
296226947304SEvan Yan 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
296326947304SEvan Yan 		return (DDI_FAILURE);
296426947304SEvan Yan 
296526947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle,
296626947304SEvan Yan 	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
296726947304SEvan Yan 		pci_config_teardown(&handle);
296826947304SEvan Yan 		return (DDI_FAILURE);
296926947304SEvan Yan 	}
297026947304SEvan Yan 
2971296f12dcSToomas Soome 	val = PCI_CAP_GET32(handle, 0, cap_ptr, PCIE_ARI_CAP);
297226947304SEvan Yan 
297326947304SEvan Yan 	next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
297426947304SEvan Yan 	    PCIE_ARI_CAP_NEXT_FUNC_MASK;
297526947304SEvan Yan 
297626947304SEvan Yan 	pci_config_teardown(&handle);
297726947304SEvan Yan 
297826947304SEvan Yan 	*func = next_function;
297926947304SEvan Yan 
298026947304SEvan Yan 	return (DDI_SUCCESS);
298126947304SEvan Yan }
298226947304SEvan Yan 
298326947304SEvan Yan dev_info_t *
pcie_func_to_dip(dev_info_t * dip,pcie_req_id_t function)298426947304SEvan Yan pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
298526947304SEvan Yan {
298626947304SEvan Yan 	pcie_req_id_t child_bdf;
298726947304SEvan Yan 	dev_info_t *cdip;
298826947304SEvan Yan 
298926947304SEvan Yan 	for (cdip = ddi_get_child(dip); cdip;
299026947304SEvan Yan 	    cdip = ddi_get_next_sibling(cdip)) {
299126947304SEvan Yan 
299226947304SEvan Yan 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
299326947304SEvan Yan 			return (NULL);
299426947304SEvan Yan 
299526947304SEvan Yan 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
299626947304SEvan Yan 			return (cdip);
299726947304SEvan Yan 	}
299826947304SEvan Yan 	return (NULL);
299926947304SEvan Yan }
300026947304SEvan Yan 
3001f8d2de6bSjchu #ifdef	DEBUG
3002eae2e508Skrishnae 
3003eae2e508Skrishnae static void
pcie_print_bus(pcie_bus_t * bus_p)3004eae2e508Skrishnae pcie_print_bus(pcie_bus_t *bus_p)
3005eae2e508Skrishnae {
3006eae2e508Skrishnae 	pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
3007eae2e508Skrishnae 	pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
3008eae2e508Skrishnae 
3009eae2e508Skrishnae 	pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
3010eae2e508Skrishnae 	pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
3011eae2e508Skrishnae 	pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
3012eae2e508Skrishnae 	pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
3013eae2e508Skrishnae 	pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
3014eae2e508Skrishnae 	pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
3015eae2e508Skrishnae 	pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
3016eae2e508Skrishnae 	pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
3017eae2e508Skrishnae 	pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
3018eae2e508Skrishnae 	pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
3019eae2e508Skrishnae }
3020eae2e508Skrishnae 
3021f8d2de6bSjchu /*
3022bf8fc234Set  * For debugging purposes set pcie_dbg_print != 0 to see printf messages
3023f8d2de6bSjchu  * during interrupt.
3024f8d2de6bSjchu  *
3025f8d2de6bSjchu  * When a proper solution is in place this code will disappear.
3026f8d2de6bSjchu  * Potential solutions are:
3027f8d2de6bSjchu  * o circular buffers
3028f8d2de6bSjchu  * o taskq to print at lower pil
3029f8d2de6bSjchu  */
3030f8d2de6bSjchu int pcie_dbg_print = 0;
3031fc51f9bbSKrishna Elango void
pcie_dbg(char * fmt,...)3032f8d2de6bSjchu pcie_dbg(char *fmt, ...)
3033f8d2de6bSjchu {
3034f8d2de6bSjchu 	va_list ap;
3035f8d2de6bSjchu 
3036f8d2de6bSjchu 	if (!pcie_debug_flags) {
3037f8d2de6bSjchu 		return;
3038f8d2de6bSjchu 	}
3039f8d2de6bSjchu 	va_start(ap, fmt);
3040f8d2de6bSjchu 	if (servicing_interrupt()) {
3041f8d2de6bSjchu 		if (pcie_dbg_print) {
3042f8d2de6bSjchu 			prom_vprintf(fmt, ap);
3043f8d2de6bSjchu 		}
3044f8d2de6bSjchu 	} else {
3045f8d2de6bSjchu 		prom_vprintf(fmt, ap);
3046f8d2de6bSjchu 	}
3047f8d2de6bSjchu 	va_end(ap);
3048f8d2de6bSjchu }
3049f8d2de6bSjchu #endif	/* DEBUG */
305046ad6a07Skrishnae 
3051b3d69c05SRobert Mustacchi boolean_t
pcie_link_bw_supported(dev_info_t * dip)3052b3d69c05SRobert Mustacchi pcie_link_bw_supported(dev_info_t *dip)
3053b3d69c05SRobert Mustacchi {
3054b3d69c05SRobert Mustacchi 	uint32_t linkcap;
3055b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3056b3d69c05SRobert Mustacchi 
3057b3d69c05SRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p)) {
3058b3d69c05SRobert Mustacchi 		return (B_FALSE);
3059b3d69c05SRobert Mustacchi 	}
3060b3d69c05SRobert Mustacchi 
3061b3d69c05SRobert Mustacchi 	if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3062b3d69c05SRobert Mustacchi 		return (B_FALSE);
3063b3d69c05SRobert Mustacchi 	}
3064b3d69c05SRobert Mustacchi 
3065b3d69c05SRobert Mustacchi 	linkcap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
3066b3d69c05SRobert Mustacchi 	return ((linkcap & PCIE_LINKCAP_LINK_BW_NOTIFY_CAP) != 0);
3067b3d69c05SRobert Mustacchi }
3068b3d69c05SRobert Mustacchi 
3069b3d69c05SRobert Mustacchi int
pcie_link_bw_enable(dev_info_t * dip)3070b3d69c05SRobert Mustacchi pcie_link_bw_enable(dev_info_t *dip)
3071b3d69c05SRobert Mustacchi {
3072b3d69c05SRobert Mustacchi 	uint16_t linkctl;
3073b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3074b3d69c05SRobert Mustacchi 
3075f7afc1fdSRobert Mustacchi 	if (pcie_disable_lbw != 0) {
3076f7afc1fdSRobert Mustacchi 		return (DDI_FAILURE);
3077f7afc1fdSRobert Mustacchi 	}
3078f7afc1fdSRobert Mustacchi 
3079b3d69c05SRobert Mustacchi 	if (!pcie_link_bw_supported(dip)) {
3080b3d69c05SRobert Mustacchi 		return (DDI_FAILURE);
3081b3d69c05SRobert Mustacchi 	}
3082b3d69c05SRobert Mustacchi 
3083b3d69c05SRobert Mustacchi 	mutex_init(&bus_p->bus_lbw_mutex, NULL, MUTEX_DRIVER, NULL);
3084b3d69c05SRobert Mustacchi 	cv_init(&bus_p->bus_lbw_cv, NULL, CV_DRIVER, NULL);
3085b3d69c05SRobert Mustacchi 	linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3086b3d69c05SRobert Mustacchi 	linkctl |= PCIE_LINKCTL_LINK_BW_INTR_EN;
3087b3d69c05SRobert Mustacchi 	linkctl |= PCIE_LINKCTL_LINK_AUTO_BW_INTR_EN;
3088b3d69c05SRobert Mustacchi 	PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, linkctl);
3089b3d69c05SRobert Mustacchi 
3090b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_pbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
3091b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_cbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
3092b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_state |= PCIE_LBW_S_ENABLED;
3093b3d69c05SRobert Mustacchi 
3094b3d69c05SRobert Mustacchi 	return (DDI_SUCCESS);
3095b3d69c05SRobert Mustacchi }
3096b3d69c05SRobert Mustacchi 
3097b3d69c05SRobert Mustacchi int
pcie_link_bw_disable(dev_info_t * dip)3098b3d69c05SRobert Mustacchi pcie_link_bw_disable(dev_info_t *dip)
3099b3d69c05SRobert Mustacchi {
3100b3d69c05SRobert Mustacchi 	uint16_t linkctl;
3101b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3102b3d69c05SRobert Mustacchi 
3103b3d69c05SRobert Mustacchi 	if ((bus_p->bus_lbw_state & PCIE_LBW_S_ENABLED) == 0) {
3104b3d69c05SRobert Mustacchi 		return (DDI_FAILURE);
3105b3d69c05SRobert Mustacchi 	}
3106b3d69c05SRobert Mustacchi 
3107b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_lbw_mutex);
3108b3d69c05SRobert Mustacchi 	while ((bus_p->bus_lbw_state &
3109b3d69c05SRobert Mustacchi 	    (PCIE_LBW_S_DISPATCHED | PCIE_LBW_S_RUNNING)) != 0) {
3110b3d69c05SRobert Mustacchi 		cv_wait(&bus_p->bus_lbw_cv, &bus_p->bus_lbw_mutex);
3111b3d69c05SRobert Mustacchi 	}
3112b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_lbw_mutex);
3113b3d69c05SRobert Mustacchi 
3114b3d69c05SRobert Mustacchi 	linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3115b3d69c05SRobert Mustacchi 	linkctl &= ~PCIE_LINKCTL_LINK_BW_INTR_EN;
3116b3d69c05SRobert Mustacchi 	linkctl &= ~PCIE_LINKCTL_LINK_AUTO_BW_INTR_EN;
3117b3d69c05SRobert Mustacchi 	PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, linkctl);
3118b3d69c05SRobert Mustacchi 
3119b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_state &= ~PCIE_LBW_S_ENABLED;
3120b3d69c05SRobert Mustacchi 	kmem_free(bus_p->bus_lbw_pbuf, MAXPATHLEN);
3121b3d69c05SRobert Mustacchi 	kmem_free(bus_p->bus_lbw_cbuf, MAXPATHLEN);
3122b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_pbuf = NULL;
3123b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_cbuf = NULL;
3124b3d69c05SRobert Mustacchi 
3125b3d69c05SRobert Mustacchi 	mutex_destroy(&bus_p->bus_lbw_mutex);
3126b3d69c05SRobert Mustacchi 	cv_destroy(&bus_p->bus_lbw_cv);
3127b3d69c05SRobert Mustacchi 
3128b3d69c05SRobert Mustacchi 	return (DDI_SUCCESS);
3129b3d69c05SRobert Mustacchi }
3130b3d69c05SRobert Mustacchi 
3131b3d69c05SRobert Mustacchi void
pcie_link_bw_taskq(void * arg)3132b3d69c05SRobert Mustacchi pcie_link_bw_taskq(void *arg)
3133b3d69c05SRobert Mustacchi {
3134b3d69c05SRobert Mustacchi 	dev_info_t *dip = arg;
3135b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3136b3d69c05SRobert Mustacchi 	dev_info_t *cdip;
3137b3d69c05SRobert Mustacchi 	boolean_t again;
3138b3d69c05SRobert Mustacchi 	sysevent_t *se;
3139b3d69c05SRobert Mustacchi 	sysevent_value_t se_val;
3140b3d69c05SRobert Mustacchi 	sysevent_id_t eid;
3141b3d69c05SRobert Mustacchi 	sysevent_attr_list_t *ev_attr_list;
3142b3d69c05SRobert Mustacchi 
3143b3d69c05SRobert Mustacchi top:
31443fe80ca4SDan Cross 	ndi_devi_enter(dip);
3145b3d69c05SRobert Mustacchi 	se = NULL;
3146b3d69c05SRobert Mustacchi 	ev_attr_list = NULL;
3147b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_lbw_mutex);
3148b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_state &= ~PCIE_LBW_S_DISPATCHED;
3149b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_state |= PCIE_LBW_S_RUNNING;
3150b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_lbw_mutex);
3151b3d69c05SRobert Mustacchi 
3152b3d69c05SRobert Mustacchi 	/*
3153b3d69c05SRobert Mustacchi 	 * Update our own speeds as we've likely changed something.
3154b3d69c05SRobert Mustacchi 	 */
3155b3d69c05SRobert Mustacchi 	pcie_capture_speeds(dip);
3156b3d69c05SRobert Mustacchi 
3157b3d69c05SRobert Mustacchi 	/*
3158b3d69c05SRobert Mustacchi 	 * Walk our children. We only care about updating this on function 0
3159b3d69c05SRobert Mustacchi 	 * because the PCIe specification requires that these all be the same
3160b3d69c05SRobert Mustacchi 	 * otherwise.
3161b3d69c05SRobert Mustacchi 	 */
3162b3d69c05SRobert Mustacchi 	for (cdip = ddi_get_child(dip); cdip != NULL;
3163b3d69c05SRobert Mustacchi 	    cdip = ddi_get_next_sibling(cdip)) {
3164b3d69c05SRobert Mustacchi 		pcie_bus_t *cbus_p = PCIE_DIP2BUS(cdip);
3165b3d69c05SRobert Mustacchi 
3166b3d69c05SRobert Mustacchi 		if (cbus_p == NULL) {
3167b3d69c05SRobert Mustacchi 			continue;
3168b3d69c05SRobert Mustacchi 		}
3169b3d69c05SRobert Mustacchi 
3170b3d69c05SRobert Mustacchi 		if ((cbus_p->bus_bdf & PCIE_REQ_ID_FUNC_MASK) != 0) {
3171b3d69c05SRobert Mustacchi 			continue;
3172b3d69c05SRobert Mustacchi 		}
3173b3d69c05SRobert Mustacchi 
3174b3d69c05SRobert Mustacchi 		/*
3175b3d69c05SRobert Mustacchi 		 * It's possible that this can fire while a child is otherwise
3176b3d69c05SRobert Mustacchi 		 * only partially constructed. Therefore, if we don't have the
3177b3d69c05SRobert Mustacchi 		 * config handle, don't bother updating the child.
3178b3d69c05SRobert Mustacchi 		 */
3179b3d69c05SRobert Mustacchi 		if (cbus_p->bus_cfg_hdl == NULL) {
3180b3d69c05SRobert Mustacchi 			continue;
3181b3d69c05SRobert Mustacchi 		}
3182b3d69c05SRobert Mustacchi 
3183b3d69c05SRobert Mustacchi 		pcie_capture_speeds(cdip);
3184b3d69c05SRobert Mustacchi 		break;
3185b3d69c05SRobert Mustacchi 	}
3186b3d69c05SRobert Mustacchi 
3187b3d69c05SRobert Mustacchi 	se = sysevent_alloc(EC_PCIE, ESC_PCIE_LINK_STATE,
3188b3d69c05SRobert Mustacchi 	    ILLUMOS_KERN_PUB "pcie", SE_SLEEP);
3189b3d69c05SRobert Mustacchi 
3190b3d69c05SRobert Mustacchi 	(void) ddi_pathname(dip, bus_p->bus_lbw_pbuf);
3191b3d69c05SRobert Mustacchi 	se_val.value_type = SE_DATA_TYPE_STRING;
3192b3d69c05SRobert Mustacchi 	se_val.value.sv_string = bus_p->bus_lbw_pbuf;
3193b3d69c05SRobert Mustacchi 	if (sysevent_add_attr(&ev_attr_list, PCIE_EV_DETECTOR_PATH, &se_val,
3194b3d69c05SRobert Mustacchi 	    SE_SLEEP) != 0) {
31953fe80ca4SDan Cross 		ndi_devi_exit(dip);
3196b3d69c05SRobert Mustacchi 		goto err;
3197b3d69c05SRobert Mustacchi 	}
3198b3d69c05SRobert Mustacchi 
3199b3d69c05SRobert Mustacchi 	if (cdip != NULL) {
3200b3d69c05SRobert Mustacchi 		(void) ddi_pathname(cdip, bus_p->bus_lbw_cbuf);
3201b3d69c05SRobert Mustacchi 
3202b3d69c05SRobert Mustacchi 		se_val.value_type = SE_DATA_TYPE_STRING;
3203b3d69c05SRobert Mustacchi 		se_val.value.sv_string = bus_p->bus_lbw_cbuf;
3204b3d69c05SRobert Mustacchi 
3205b3d69c05SRobert Mustacchi 		/*
3206b3d69c05SRobert Mustacchi 		 * If this fails, that's OK. We'd rather get the event off and
3207b3d69c05SRobert Mustacchi 		 * there's a chance that there may not be anything there for us.
3208b3d69c05SRobert Mustacchi 		 */
3209b3d69c05SRobert Mustacchi 		(void) sysevent_add_attr(&ev_attr_list, PCIE_EV_CHILD_PATH,
3210b3d69c05SRobert Mustacchi 		    &se_val, SE_SLEEP);
3211b3d69c05SRobert Mustacchi 	}
3212b3d69c05SRobert Mustacchi 
32133fe80ca4SDan Cross 	ndi_devi_exit(dip);
3214b3d69c05SRobert Mustacchi 
3215b3d69c05SRobert Mustacchi 	/*
3216b3d69c05SRobert Mustacchi 	 * Before we generate and send down a sysevent, we need to tell the
3217b3d69c05SRobert Mustacchi 	 * system that parts of the devinfo cache need to be invalidated. While
3218b3d69c05SRobert Mustacchi 	 * the function below takes several args, it ignores them all. Because
3219b3d69c05SRobert Mustacchi 	 * this is a global invalidation, we don't bother trying to do much more
3220b3d69c05SRobert Mustacchi 	 * than requesting a global invalidation, lest we accidentally kick off
3221b3d69c05SRobert Mustacchi 	 * several in a row.
3222b3d69c05SRobert Mustacchi 	 */
3223b3d69c05SRobert Mustacchi 	ddi_prop_cache_invalidate(DDI_DEV_T_NONE, NULL, NULL, 0);
3224b3d69c05SRobert Mustacchi 
3225b3d69c05SRobert Mustacchi 	if (sysevent_attach_attributes(se, ev_attr_list) != 0) {
3226b3d69c05SRobert Mustacchi 		goto err;
3227b3d69c05SRobert Mustacchi 	}
3228b3d69c05SRobert Mustacchi 	ev_attr_list = NULL;
3229b3d69c05SRobert Mustacchi 
3230b3d69c05SRobert Mustacchi 	if (log_sysevent(se, SE_SLEEP, &eid) != 0) {
3231b3d69c05SRobert Mustacchi 		goto err;
3232b3d69c05SRobert Mustacchi 	}
3233b3d69c05SRobert Mustacchi 
3234b3d69c05SRobert Mustacchi err:
3235b3d69c05SRobert Mustacchi 	sysevent_free_attr(ev_attr_list);
3236b3d69c05SRobert Mustacchi 	sysevent_free(se);
3237b3d69c05SRobert Mustacchi 
3238b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_lbw_mutex);
3239b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_state &= ~PCIE_LBW_S_RUNNING;
3240b3d69c05SRobert Mustacchi 	cv_broadcast(&bus_p->bus_lbw_cv);
3241b3d69c05SRobert Mustacchi 	again = (bus_p->bus_lbw_state & PCIE_LBW_S_DISPATCHED) != 0;
3242b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_lbw_mutex);
3243b3d69c05SRobert Mustacchi 
3244b3d69c05SRobert Mustacchi 	if (again) {
3245b3d69c05SRobert Mustacchi 		goto top;
3246b3d69c05SRobert Mustacchi 	}
3247b3d69c05SRobert Mustacchi }
3248b3d69c05SRobert Mustacchi 
3249b3d69c05SRobert Mustacchi int
pcie_link_bw_intr(dev_info_t * dip)3250b3d69c05SRobert Mustacchi pcie_link_bw_intr(dev_info_t *dip)
3251b3d69c05SRobert Mustacchi {
3252b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3253b3d69c05SRobert Mustacchi 	uint16_t linksts;
3254b3d69c05SRobert Mustacchi 	uint16_t flags = PCIE_LINKSTS_LINK_BW_MGMT | PCIE_LINKSTS_AUTO_BW;
3255*ead3c390SKeith M Wesolowski 	hrtime_t now;
3256b3d69c05SRobert Mustacchi 
3257b3d69c05SRobert Mustacchi 	if ((bus_p->bus_lbw_state & PCIE_LBW_S_ENABLED) == 0) {
3258b3d69c05SRobert Mustacchi 		return (DDI_INTR_UNCLAIMED);
3259b3d69c05SRobert Mustacchi 	}
3260b3d69c05SRobert Mustacchi 
3261b3d69c05SRobert Mustacchi 	linksts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3262b3d69c05SRobert Mustacchi 	if ((linksts & flags) == 0) {
3263b3d69c05SRobert Mustacchi 		return (DDI_INTR_UNCLAIMED);
3264b3d69c05SRobert Mustacchi 	}
3265b3d69c05SRobert Mustacchi 
3266*ead3c390SKeith M Wesolowski 	now = gethrtime();
3267*ead3c390SKeith M Wesolowski 
3268b3d69c05SRobert Mustacchi 	/*
3269b3d69c05SRobert Mustacchi 	 * Check if we've already dispatched this event. If we have already
3270b3d69c05SRobert Mustacchi 	 * dispatched it, then there's nothing else to do, we coalesce multiple
3271b3d69c05SRobert Mustacchi 	 * events.
3272b3d69c05SRobert Mustacchi 	 */
3273b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_lbw_mutex);
3274b3d69c05SRobert Mustacchi 	bus_p->bus_lbw_nevents++;
3275*ead3c390SKeith M Wesolowski 	bus_p->bus_lbw_last_ts = now;
3276b3d69c05SRobert Mustacchi 	if ((bus_p->bus_lbw_state & PCIE_LBW_S_DISPATCHED) == 0) {
3277b3d69c05SRobert Mustacchi 		if ((bus_p->bus_lbw_state & PCIE_LBW_S_RUNNING) == 0) {
3278b3d69c05SRobert Mustacchi 			taskq_dispatch_ent(pcie_link_tq, pcie_link_bw_taskq,
3279b3d69c05SRobert Mustacchi 			    dip, 0, &bus_p->bus_lbw_ent);
3280b3d69c05SRobert Mustacchi 		}
3281b3d69c05SRobert Mustacchi 
3282b3d69c05SRobert Mustacchi 		bus_p->bus_lbw_state |= PCIE_LBW_S_DISPATCHED;
3283b3d69c05SRobert Mustacchi 	}
3284b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_lbw_mutex);
3285b3d69c05SRobert Mustacchi 
3286b3d69c05SRobert Mustacchi 	PCIE_CAP_PUT(16, bus_p, PCIE_LINKSTS, flags);
3287b3d69c05SRobert Mustacchi 	return (DDI_INTR_CLAIMED);
3288b3d69c05SRobert Mustacchi }
3289b3d69c05SRobert Mustacchi 
3290b3d69c05SRobert Mustacchi int
pcie_link_set_target(dev_info_t * dip,pcie_link_speed_t speed)3291b3d69c05SRobert Mustacchi pcie_link_set_target(dev_info_t *dip, pcie_link_speed_t speed)
3292b3d69c05SRobert Mustacchi {
3293b3d69c05SRobert Mustacchi 	uint16_t ctl2, rval;
3294b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3295b3d69c05SRobert Mustacchi 
3296b3d69c05SRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p)) {
3297b3d69c05SRobert Mustacchi 		return (ENOTSUP);
3298b3d69c05SRobert Mustacchi 	}
3299b3d69c05SRobert Mustacchi 
3300b3d69c05SRobert Mustacchi 	if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3301b3d69c05SRobert Mustacchi 		return (ENOTSUP);
3302b3d69c05SRobert Mustacchi 	}
3303b3d69c05SRobert Mustacchi 
330489427192SRobert Mustacchi 	if (bus_p->bus_pcie_vers < 2) {
330589427192SRobert Mustacchi 		return (ENOTSUP);
330689427192SRobert Mustacchi 	}
330789427192SRobert Mustacchi 
3308b3d69c05SRobert Mustacchi 	switch (speed) {
3309b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_2_5:
3310b3d69c05SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_2_5;
3311b3d69c05SRobert Mustacchi 		break;
3312b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_5:
3313b3d69c05SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_5;
3314b3d69c05SRobert Mustacchi 		break;
3315b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_8:
3316b3d69c05SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_8;
3317b3d69c05SRobert Mustacchi 		break;
3318b3d69c05SRobert Mustacchi 	case PCIE_LINK_SPEED_16:
3319b3d69c05SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_16;
3320b3d69c05SRobert Mustacchi 		break;
332189427192SRobert Mustacchi 	case PCIE_LINK_SPEED_32:
332289427192SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_32;
332389427192SRobert Mustacchi 		break;
332489427192SRobert Mustacchi 	case PCIE_LINK_SPEED_64:
332589427192SRobert Mustacchi 		rval = PCIE_LINKCTL2_TARGET_SPEED_64;
332689427192SRobert Mustacchi 		break;
3327b3d69c05SRobert Mustacchi 	default:
3328b3d69c05SRobert Mustacchi 		return (EINVAL);
3329b3d69c05SRobert Mustacchi 	}
3330b3d69c05SRobert Mustacchi 
3331b3d69c05SRobert Mustacchi 	mutex_enter(&bus_p->bus_speed_mutex);
333289427192SRobert Mustacchi 	if ((bus_p->bus_sup_speed & speed) == 0) {
333389427192SRobert Mustacchi 		mutex_exit(&bus_p->bus_speed_mutex);
333489427192SRobert Mustacchi 		return (ENOTSUP);
333589427192SRobert Mustacchi 	}
333689427192SRobert Mustacchi 
3337b3d69c05SRobert Mustacchi 	bus_p->bus_target_speed = speed;
3338b3d69c05SRobert Mustacchi 	bus_p->bus_speed_flags |= PCIE_LINK_F_ADMIN_TARGET;
3339b3d69c05SRobert Mustacchi 
3340b3d69c05SRobert Mustacchi 	ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
3341b3d69c05SRobert Mustacchi 	ctl2 &= ~PCIE_LINKCTL2_TARGET_SPEED_MASK;
3342b3d69c05SRobert Mustacchi 	ctl2 |= rval;
3343b3d69c05SRobert Mustacchi 	PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL2, ctl2);
3344b3d69c05SRobert Mustacchi 	mutex_exit(&bus_p->bus_speed_mutex);
3345b3d69c05SRobert Mustacchi 
3346b3d69c05SRobert Mustacchi 	/*
3347b3d69c05SRobert Mustacchi 	 * Make sure our updates have been reflected in devinfo.
3348b3d69c05SRobert Mustacchi 	 */
3349b3d69c05SRobert Mustacchi 	pcie_capture_speeds(dip);
3350b3d69c05SRobert Mustacchi 
3351b3d69c05SRobert Mustacchi 	return (0);
3352b3d69c05SRobert Mustacchi }
3353b3d69c05SRobert Mustacchi 
3354b3d69c05SRobert Mustacchi int
pcie_link_retrain(dev_info_t * dip)3355b3d69c05SRobert Mustacchi pcie_link_retrain(dev_info_t *dip)
3356b3d69c05SRobert Mustacchi {
3357b3d69c05SRobert Mustacchi 	uint16_t ctl;
3358b3d69c05SRobert Mustacchi 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3359b3d69c05SRobert Mustacchi 
3360b3d69c05SRobert Mustacchi 	if (!PCIE_IS_PCIE(bus_p)) {
3361b3d69c05SRobert Mustacchi 		return (ENOTSUP);
3362b3d69c05SRobert Mustacchi 	}
3363b3d69c05SRobert Mustacchi 
3364b3d69c05SRobert Mustacchi 	if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3365b3d69c05SRobert Mustacchi 		return (ENOTSUP);
3366b3d69c05SRobert Mustacchi 	}
3367b3d69c05SRobert Mustacchi 
3368b3d69c05SRobert Mustacchi 	/*
3369b3d69c05SRobert Mustacchi 	 * The PCIe specification suggests that we make sure that the link isn't
3370b3d69c05SRobert Mustacchi 	 * in training before issuing this command in case there was a state
3371b3d69c05SRobert Mustacchi 	 * machine transition prior to when we got here. We wait and then go
3372b3d69c05SRobert Mustacchi 	 * ahead and issue the command anyways.
3373b3d69c05SRobert Mustacchi 	 */
3374b3d69c05SRobert Mustacchi 	for (uint32_t i = 0; i < pcie_link_retrain_count; i++) {
3375b3d69c05SRobert Mustacchi 		uint16_t sts;
3376b3d69c05SRobert Mustacchi 
3377b3d69c05SRobert Mustacchi 		sts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3378b3d69c05SRobert Mustacchi 		if ((sts & PCIE_LINKSTS_LINK_TRAINING) == 0)
3379b3d69c05SRobert Mustacchi 			break;
3380b3d69c05SRobert Mustacchi 		delay(drv_usectohz(pcie_link_retrain_delay_ms * 1000));
3381b3d69c05SRobert Mustacchi 	}
3382b3d69c05SRobert Mustacchi 
3383b3d69c05SRobert Mustacchi 	ctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3384b3d69c05SRobert Mustacchi 	ctl |= PCIE_LINKCTL_RETRAIN_LINK;
3385b3d69c05SRobert Mustacchi 	PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, ctl);
3386b3d69c05SRobert Mustacchi 
3387b3d69c05SRobert Mustacchi 	/*
3388b3d69c05SRobert Mustacchi 	 * Wait again to see if it clears before returning to the user.
3389b3d69c05SRobert Mustacchi 	 */
3390b3d69c05SRobert Mustacchi 	for (uint32_t i = 0; i < pcie_link_retrain_count; i++) {
3391b3d69c05SRobert Mustacchi 		uint16_t sts;
3392b3d69c05SRobert Mustacchi 
3393b3d69c05SRobert Mustacchi 		sts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3394b3d69c05SRobert Mustacchi 		if ((sts & PCIE_LINKSTS_LINK_TRAINING) == 0)
3395b3d69c05SRobert Mustacchi 			break;
3396b3d69c05SRobert Mustacchi 		delay(drv_usectohz(pcie_link_retrain_delay_ms * 1000));
3397b3d69c05SRobert Mustacchi 	}
3398b3d69c05SRobert Mustacchi 
3399b3d69c05SRobert Mustacchi 	return (0);
3400b3d69c05SRobert Mustacchi }
34015b2c4190SRobert Mustacchi 
34025b2c4190SRobert Mustacchi /*
34035b2c4190SRobert Mustacchi  * Here we're going through and grabbing information about a given PCIe device.
34045b2c4190SRobert Mustacchi  * Our situation is a little bit complicated at this point. This gets invoked
34055b2c4190SRobert Mustacchi  * both during early initialization and during hotplug events. We cannot rely on
34065b2c4190SRobert Mustacchi  * the device node having been fully set up, that is, while the pcie_bus_t
34075b2c4190SRobert Mustacchi  * normally contains a ddi_acc_handle_t for configuration space, that may not be
34085b2c4190SRobert Mustacchi  * valid yet as this can occur before child initialization or we may be dealing
34095b2c4190SRobert Mustacchi  * with a function that will never have a handle.
34105b2c4190SRobert Mustacchi  *
34115b2c4190SRobert Mustacchi  * However, we should always have a fully furnished pcie_bus_t, which means that
34125b2c4190SRobert Mustacchi  * we can get its bdf and use that to access the devices configuration space.
34135b2c4190SRobert Mustacchi  */
34145b2c4190SRobert Mustacchi static int
pcie_fabric_feature_scan(dev_info_t * dip,void * arg)34155b2c4190SRobert Mustacchi pcie_fabric_feature_scan(dev_info_t *dip, void *arg)
34165b2c4190SRobert Mustacchi {
34175b2c4190SRobert Mustacchi 	pcie_bus_t *bus_p;
34185b2c4190SRobert Mustacchi 	uint32_t devcap;
34195b2c4190SRobert Mustacchi 	uint16_t mps;
34205b2c4190SRobert Mustacchi 	dev_info_t *rcdip;
34215b2c4190SRobert Mustacchi 	pcie_fabric_data_t *fab = arg;
34225b2c4190SRobert Mustacchi 
34235b2c4190SRobert Mustacchi 	/*
34245b2c4190SRobert Mustacchi 	 * Skip over non-PCIe devices. If we encounter something here, we don't
34255b2c4190SRobert Mustacchi 	 * bother going through any of its children because we don't have reason
34265b2c4190SRobert Mustacchi 	 * to believe that a PCIe device that this will impact will exist below
34275b2c4190SRobert Mustacchi 	 * this. While it is possible that there's a PCIe fabric downstream an
34285b2c4190SRobert Mustacchi 	 * intermediate old PCI/PCI-X bus, at that point, we'll still trigger
34295b2c4190SRobert Mustacchi 	 * our complex fabric detection and use the minimums.
34305b2c4190SRobert Mustacchi 	 *
34315b2c4190SRobert Mustacchi 	 * The reason this doesn't trigger an immediate flagging as a complex
34325b2c4190SRobert Mustacchi 	 * case like the one below is because we could be scanning a device that
34335b2c4190SRobert Mustacchi 	 * is a nexus driver and has children already (albeit that would be
34345b2c4190SRobert Mustacchi 	 * somewhat surprising as we don't anticipate being called at this
34355b2c4190SRobert Mustacchi 	 * point).
34365b2c4190SRobert Mustacchi 	 */
34375b2c4190SRobert Mustacchi 	if (pcie_dev(dip) != DDI_SUCCESS) {
34385b2c4190SRobert Mustacchi 		return (DDI_WALK_PRUNECHILD);
34395b2c4190SRobert Mustacchi 	}
34405b2c4190SRobert Mustacchi 
34415b2c4190SRobert Mustacchi 	/*
34425b2c4190SRobert Mustacchi 	 * If we fail to find a pcie_bus_t for some reason, that's somewhat
34435b2c4190SRobert Mustacchi 	 * surprising. We log this fact and set the complex flag and indicate it
34445b2c4190SRobert Mustacchi 	 * was because of this case. This immediately transitions us to a
34455b2c4190SRobert Mustacchi 	 * "complex" case which means use the minimal, safe, settings.
34465b2c4190SRobert Mustacchi 	 */
34475b2c4190SRobert Mustacchi 	bus_p = PCIE_DIP2BUS(dip);
34485b2c4190SRobert Mustacchi 	if (bus_p == NULL) {
34495b2c4190SRobert Mustacchi 		dev_err(dip, CE_WARN, "failed to find associated pcie_bus_t "
34505b2c4190SRobert Mustacchi 		    "during fabric scan");
34515b2c4190SRobert Mustacchi 		fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
34525b2c4190SRobert Mustacchi 		return (DDI_WALK_TERMINATE);
34535b2c4190SRobert Mustacchi 	}
345489cd7a0dSRobert Mustacchi 
345589cd7a0dSRobert Mustacchi 	/*
345689cd7a0dSRobert Mustacchi 	 * In a similar case, there is hardware out there which is a PCIe
345789cd7a0dSRobert Mustacchi 	 * device, but does not advertise a PCIe capability. An example of this
345889cd7a0dSRobert Mustacchi 	 * is the IDT Tsi382A which can hide its PCIe capability. If this is
345989cd7a0dSRobert Mustacchi 	 * the case, we immediately terminate scanning and flag this as a
346089cd7a0dSRobert Mustacchi 	 * 'complex' case which causes us to use guaranteed safe settings.
346189cd7a0dSRobert Mustacchi 	 */
346289cd7a0dSRobert Mustacchi 	if (bus_p->bus_pcie_off == 0) {
346389cd7a0dSRobert Mustacchi 		dev_err(dip, CE_WARN, "encountered PCIe device without PCIe "
346489cd7a0dSRobert Mustacchi 		    "capability");
346589cd7a0dSRobert Mustacchi 		fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
346689cd7a0dSRobert Mustacchi 		return (DDI_WALK_TERMINATE);
346789cd7a0dSRobert Mustacchi 	}
346889cd7a0dSRobert Mustacchi 
34695b2c4190SRobert Mustacchi 	rcdip = pcie_get_rc_dip(dip);
34705b2c4190SRobert Mustacchi 
34715b2c4190SRobert Mustacchi 	/*
34725b2c4190SRobert Mustacchi 	 * First, start by determining what the device's tagging and max packet
34735b2c4190SRobert Mustacchi 	 * size is. All PCIe devices will always have the 8-bit tag information
34745b2c4190SRobert Mustacchi 	 * as this has existed since PCIe 1.0. 10-bit tagging requires a V2
34755b2c4190SRobert Mustacchi 	 * PCIe capability. 14-bit requires the DEV3 cap. If we are missing a
34765b2c4190SRobert Mustacchi 	 * version or capability, then we always treat that as lacking the bits
34775b2c4190SRobert Mustacchi 	 * in the fabric.
34785b2c4190SRobert Mustacchi 	 */
34795b2c4190SRobert Mustacchi 	ASSERT3U(bus_p->bus_pcie_off, !=, 0);
34805b2c4190SRobert Mustacchi 	devcap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
34815b2c4190SRobert Mustacchi 	    PCIE_DEVCAP);
34825b2c4190SRobert Mustacchi 	mps = devcap & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
34835b2c4190SRobert Mustacchi 	if (mps < fab->pfd_mps_found) {
34845b2c4190SRobert Mustacchi 		fab->pfd_mps_found = mps;
34855b2c4190SRobert Mustacchi 	}
34865b2c4190SRobert Mustacchi 
34875b2c4190SRobert Mustacchi 	if ((devcap & PCIE_DEVCAP_EXT_TAG_8BIT) == 0) {
34885b2c4190SRobert Mustacchi 		fab->pfd_tag_found &= ~PCIE_TAG_8B;
34895b2c4190SRobert Mustacchi 	}
34905b2c4190SRobert Mustacchi 
34915b2c4190SRobert Mustacchi 	if (bus_p->bus_pcie_vers == PCIE_PCIECAP_VER_2_0) {
34925b2c4190SRobert Mustacchi 		uint32_t devcap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
34935b2c4190SRobert Mustacchi 		    bus_p->bus_pcie_off + PCIE_DEVCAP2);
34945b2c4190SRobert Mustacchi 		if ((devcap2 & PCIE_DEVCAP2_10B_TAG_COMP_SUP) == 0) {
34955b2c4190SRobert Mustacchi 			fab->pfd_tag_found &= ~PCIE_TAG_10B_COMP;
34965b2c4190SRobert Mustacchi 		}
34975b2c4190SRobert Mustacchi 	} else {
34985b2c4190SRobert Mustacchi 		fab->pfd_tag_found &= ~PCIE_TAG_10B_COMP;
34995b2c4190SRobert Mustacchi 	}
35005b2c4190SRobert Mustacchi 
35015b2c4190SRobert Mustacchi 	if (bus_p->bus_dev3_off != 0) {
35025b2c4190SRobert Mustacchi 		uint32_t devcap3 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
35035b2c4190SRobert Mustacchi 		    bus_p->bus_dev3_off + PCIE_DEVCAP3);
35045b2c4190SRobert Mustacchi 		if ((devcap3 & PCIE_DEVCAP3_14B_TAG_COMP_SUP) == 0) {
35055b2c4190SRobert Mustacchi 			fab->pfd_tag_found &= ~PCIE_TAG_14B_COMP;
35065b2c4190SRobert Mustacchi 		}
35075b2c4190SRobert Mustacchi 	} else {
35085b2c4190SRobert Mustacchi 		fab->pfd_tag_found &= ~PCIE_TAG_14B_COMP;
35095b2c4190SRobert Mustacchi 	}
35105b2c4190SRobert Mustacchi 
35115b2c4190SRobert Mustacchi 	/*
35125b2c4190SRobert Mustacchi 	 * Now that we have captured device information, we must go and ask
35135b2c4190SRobert Mustacchi 	 * questions of the topology here. The big theory statement enumerates
35145b2c4190SRobert Mustacchi 	 * several types of cases. The big question we need to answer is have we
35155b2c4190SRobert Mustacchi 	 * encountered a hotpluggable bridge that means we need to mark this as
35165b2c4190SRobert Mustacchi 	 * complex.
35175b2c4190SRobert Mustacchi 	 *
35185b2c4190SRobert Mustacchi 	 * The big theory statement notes several different kinds of hotplug
35195b2c4190SRobert Mustacchi 	 * topologies that exist that we can theoretically support. Right now we
35205b2c4190SRobert Mustacchi 	 * opt to keep our lives simple and focus solely on (4) and (5). These
35215b2c4190SRobert Mustacchi 	 * can both be summarized by a single, fairly straightforward rule:
35225b2c4190SRobert Mustacchi 	 *
35235b2c4190SRobert Mustacchi 	 * The only allowed hotpluggable entity is a root port.
35245b2c4190SRobert Mustacchi 	 *
35255b2c4190SRobert Mustacchi 	 * The reason that this can work and detect cases like (6), (7), and our
35265b2c4190SRobert Mustacchi 	 * other invalid ones is that the hotplug code will scan and find all
35275b2c4190SRobert Mustacchi 	 * children before we are called into here.
35285b2c4190SRobert Mustacchi 	 */
35295b2c4190SRobert Mustacchi 	if (bus_p->bus_hp_sup_modes != 0) {
35305b2c4190SRobert Mustacchi 		/*
35315b2c4190SRobert Mustacchi 		 * We opt to terminate in this case because there's no value in
35325b2c4190SRobert Mustacchi 		 * scanning the rest of the tree at this point.
35335b2c4190SRobert Mustacchi 		 */
35345b2c4190SRobert Mustacchi 		if (!PCIE_IS_RP(bus_p)) {
35355b2c4190SRobert Mustacchi 			fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
35365b2c4190SRobert Mustacchi 			return (DDI_WALK_TERMINATE);
35375b2c4190SRobert Mustacchi 		}
35385b2c4190SRobert Mustacchi 
35395b2c4190SRobert Mustacchi 		fab->pfd_flags |= PCIE_FABRIC_F_RP_HP;
35405b2c4190SRobert Mustacchi 	}
35415b2c4190SRobert Mustacchi 
35425b2c4190SRobert Mustacchi 	/*
35435b2c4190SRobert Mustacchi 	 * As our walk starts at a root port, we need to make sure that we don't
35445b2c4190SRobert Mustacchi 	 * pick up any of its siblings and their children as those would be
35455b2c4190SRobert Mustacchi 	 * different PCIe fabric domains for us to scan. In many hardware
35465b2c4190SRobert Mustacchi 	 * platforms multiple root ports are all at the same level in the tree.
35475b2c4190SRobert Mustacchi 	 */
35485b2c4190SRobert Mustacchi 	if (bus_p->bus_rp_dip == dip) {
35495b2c4190SRobert Mustacchi 		return (DDI_WALK_PRUNESIB);
35505b2c4190SRobert Mustacchi 	}
35515b2c4190SRobert Mustacchi 
35525b2c4190SRobert Mustacchi 	return (DDI_WALK_CONTINUE);
35535b2c4190SRobert Mustacchi }
35545b2c4190SRobert Mustacchi 
35555b2c4190SRobert Mustacchi static int
pcie_fabric_feature_set(dev_info_t * dip,void * arg)35565b2c4190SRobert Mustacchi pcie_fabric_feature_set(dev_info_t *dip, void *arg)
35575b2c4190SRobert Mustacchi {
35585b2c4190SRobert Mustacchi 	pcie_bus_t *bus_p;
35595b2c4190SRobert Mustacchi 	dev_info_t *rcdip;
35605b2c4190SRobert Mustacchi 	pcie_fabric_data_t *fab = arg;
35615b2c4190SRobert Mustacchi 	uint32_t devcap, devctl;
35625b2c4190SRobert Mustacchi 
35635b2c4190SRobert Mustacchi 	if (pcie_dev(dip) != DDI_SUCCESS) {
35645b2c4190SRobert Mustacchi 		return (DDI_WALK_PRUNECHILD);
35655b2c4190SRobert Mustacchi 	}
35665b2c4190SRobert Mustacchi 
35675b2c4190SRobert Mustacchi 	/*
35685b2c4190SRobert Mustacchi 	 * The missing bus_t sent us into the complex case previously. We still
35695b2c4190SRobert Mustacchi 	 * need to make sure all devices have values we expect here and thus
357089cd7a0dSRobert Mustacchi 	 * don't terminate like the above. The same is true for the case where
357189cd7a0dSRobert Mustacchi 	 * there is no PCIe capability.
35725b2c4190SRobert Mustacchi 	 */
35735b2c4190SRobert Mustacchi 	bus_p = PCIE_DIP2BUS(dip);
357489cd7a0dSRobert Mustacchi 	if (bus_p == NULL || bus_p->bus_pcie_off == 0) {
35755b2c4190SRobert Mustacchi 		return (DDI_WALK_CONTINUE);
35765b2c4190SRobert Mustacchi 	}
35775b2c4190SRobert Mustacchi 	rcdip = pcie_get_rc_dip(dip);
35785b2c4190SRobert Mustacchi 
35795b2c4190SRobert Mustacchi 	devcap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35805b2c4190SRobert Mustacchi 	    PCIE_DEVCAP);
35815b2c4190SRobert Mustacchi 	devctl = pci_cfgacc_get16(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35825b2c4190SRobert Mustacchi 	    PCIE_DEVCTL);
35835b2c4190SRobert Mustacchi 
35845b2c4190SRobert Mustacchi 	if ((devcap & PCIE_DEVCAP_EXT_TAG_8BIT) != 0 &&
35855b2c4190SRobert Mustacchi 	    (fab->pfd_tag_act & PCIE_TAG_8B) != 0) {
35865b2c4190SRobert Mustacchi 		devctl |= PCIE_DEVCTL_EXT_TAG_FIELD_EN;
35875b2c4190SRobert Mustacchi 	}
35885b2c4190SRobert Mustacchi 
35895b2c4190SRobert Mustacchi 	devctl &= ~PCIE_DEVCTL_MAX_PAYLOAD_MASK;
35905b2c4190SRobert Mustacchi 	ASSERT0(fab->pfd_mps_act & ~PCIE_DEVCAP_MAX_PAYLOAD_MASK);
35915b2c4190SRobert Mustacchi 	devctl |= fab->pfd_mps_act << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT;
35925b2c4190SRobert Mustacchi 
35935b2c4190SRobert Mustacchi 	pci_cfgacc_put16(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35945b2c4190SRobert Mustacchi 	    PCIE_DEVCTL, devctl);
35955b2c4190SRobert Mustacchi 
35965b2c4190SRobert Mustacchi 	if (bus_p->bus_pcie_vers == PCIE_PCIECAP_VER_2_0 &&
35975b2c4190SRobert Mustacchi 	    (fab->pfd_tag_act & PCIE_TAG_10B_COMP) != 0) {
35985b2c4190SRobert Mustacchi 		uint32_t devcap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
35995b2c4190SRobert Mustacchi 		    bus_p->bus_pcie_off + PCIE_DEVCAP2);
36005b2c4190SRobert Mustacchi 
36015b2c4190SRobert Mustacchi 		if ((devcap2 & PCIE_DEVCAP2_10B_TAG_REQ_SUP) == 0) {
36025b2c4190SRobert Mustacchi 			uint16_t devctl2 = pci_cfgacc_get16(rcdip,
36035b2c4190SRobert Mustacchi 			    bus_p->bus_bdf, bus_p->bus_pcie_off + PCIE_DEVCTL2);
36045b2c4190SRobert Mustacchi 			devctl2 |= PCIE_DEVCTL2_10B_TAG_REQ_EN;
36055b2c4190SRobert Mustacchi 			pci_cfgacc_put16(rcdip, bus_p->bus_bdf,
36065b2c4190SRobert Mustacchi 			    bus_p->bus_pcie_off + PCIE_DEVCTL2, devctl2);
36075b2c4190SRobert Mustacchi 		}
36085b2c4190SRobert Mustacchi 	}
36095b2c4190SRobert Mustacchi 
36105b2c4190SRobert Mustacchi 	if (bus_p->bus_dev3_off != 0 &&
36115b2c4190SRobert Mustacchi 	    (fab->pfd_tag_act & PCIE_TAG_14B_COMP) != 0) {
36125b2c4190SRobert Mustacchi 		uint32_t devcap3 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
36135b2c4190SRobert Mustacchi 		    bus_p->bus_dev3_off + PCIE_DEVCAP3);
36145b2c4190SRobert Mustacchi 
36155b2c4190SRobert Mustacchi 		if ((devcap3 & PCIE_DEVCAP3_14B_TAG_REQ_SUP) == 0) {
36165b2c4190SRobert Mustacchi 			uint16_t devctl3 = pci_cfgacc_get16(rcdip,
36175b2c4190SRobert Mustacchi 			    bus_p->bus_bdf, bus_p->bus_dev3_off + PCIE_DEVCTL3);
36185b2c4190SRobert Mustacchi 			devctl3 |= PCIE_DEVCTL3_14B_TAG_REQ_EN;
36195b2c4190SRobert Mustacchi 			pci_cfgacc_put16(rcdip, bus_p->bus_bdf,
36205b2c4190SRobert Mustacchi 			    bus_p->bus_pcie_off + PCIE_DEVCTL2, devctl3);
36215b2c4190SRobert Mustacchi 		}
36225b2c4190SRobert Mustacchi 	}
36235b2c4190SRobert Mustacchi 
36245b2c4190SRobert Mustacchi 	/*
36255b2c4190SRobert Mustacchi 	 * As our walk starts at a root port, we need to make sure that we don't
36265b2c4190SRobert Mustacchi 	 * pick up any of its siblings and their children as those would be
36275b2c4190SRobert Mustacchi 	 * different PCIe fabric domains for us to scan. In many hardware
36285b2c4190SRobert Mustacchi 	 * platforms multiple root ports are all at the same level in the tree.
36295b2c4190SRobert Mustacchi 	 */
36305b2c4190SRobert Mustacchi 	if (bus_p->bus_rp_dip == dip) {
36315b2c4190SRobert Mustacchi 		return (DDI_WALK_PRUNESIB);
36325b2c4190SRobert Mustacchi 	}
36335b2c4190SRobert Mustacchi 
36345b2c4190SRobert Mustacchi 	return (DDI_WALK_CONTINUE);
36355b2c4190SRobert Mustacchi }
36365b2c4190SRobert Mustacchi 
36375b2c4190SRobert Mustacchi /*
36385b2c4190SRobert Mustacchi  * This is used to scan and determine the total set of PCIe fabric settings that
36395b2c4190SRobert Mustacchi  * we should have in the system for everything downstream of this specified root
36405b2c4190SRobert Mustacchi  * port. Note, it is only really safe to call this while working from the
36415b2c4190SRobert Mustacchi  * perspective of a root port as we will be walking down the entire device tree.
36425b2c4190SRobert Mustacchi  *
36435b2c4190SRobert Mustacchi  * However, our callers, particularly hoptlug, don't have all the information
36445b2c4190SRobert Mustacchi  * we'd like. In particular, we need to check that:
36455b2c4190SRobert Mustacchi  *
36465b2c4190SRobert Mustacchi  *   o This is actually a PCIe device.
36475b2c4190SRobert Mustacchi  *   o That this is a root port (see the big theory statement to understand this
36485b2c4190SRobert Mustacchi  *     constraint).
36495b2c4190SRobert Mustacchi  */
36505b2c4190SRobert Mustacchi void
pcie_fabric_setup(dev_info_t * dip)36515b2c4190SRobert Mustacchi pcie_fabric_setup(dev_info_t *dip)
36525b2c4190SRobert Mustacchi {
36535b2c4190SRobert Mustacchi 	pcie_bus_t *bus_p;
36545b2c4190SRobert Mustacchi 	pcie_fabric_data_t *fab;
36555b2c4190SRobert Mustacchi 	dev_info_t *pdip;
36565b2c4190SRobert Mustacchi 
36575b2c4190SRobert Mustacchi 	bus_p = PCIE_DIP2BUS(dip);
36585b2c4190SRobert Mustacchi 	if (bus_p == NULL || !PCIE_IS_RP(bus_p)) {
36595b2c4190SRobert Mustacchi 		return;
36605b2c4190SRobert Mustacchi 	}
36615b2c4190SRobert Mustacchi 
36625b2c4190SRobert Mustacchi 	VERIFY3P(bus_p->bus_fab, !=, NULL);
36635b2c4190SRobert Mustacchi 	fab = bus_p->bus_fab;
36645b2c4190SRobert Mustacchi 
36655b2c4190SRobert Mustacchi 	/*
36665b2c4190SRobert Mustacchi 	 * For us to call ddi_walk_devs(), our parent needs to be held.
36675b2c4190SRobert Mustacchi 	 * ddi_walk_devs() will take care of grabbing our dip as part of its
36685b2c4190SRobert Mustacchi 	 * walk before we iterate over our children.
36695b2c4190SRobert Mustacchi 	 *
36705b2c4190SRobert Mustacchi 	 * A reasonable question to ask here is why is it safe to ask for our
36715b2c4190SRobert Mustacchi 	 * parent? In this case, because we have entered here through some
36725b2c4190SRobert Mustacchi 	 * thread that's operating on us whether as part of attach or a hotplug
36735b2c4190SRobert Mustacchi 	 * event, our dip somewhat by definition has to be valid. If we were
36745b2c4190SRobert Mustacchi 	 * looking at our dip's children and then asking them for a parent, then
36755b2c4190SRobert Mustacchi 	 * that would be a race condition.
36765b2c4190SRobert Mustacchi 	 */
36775b2c4190SRobert Mustacchi 	pdip = ddi_get_parent(dip);
36785b2c4190SRobert Mustacchi 	VERIFY3P(pdip, !=, NULL);
36793fe80ca4SDan Cross 	ndi_devi_enter(pdip);
36805b2c4190SRobert Mustacchi 	fab->pfd_flags |= PCIE_FABRIC_F_SCANNING;
36815b2c4190SRobert Mustacchi 
36825b2c4190SRobert Mustacchi 	/*
36835b2c4190SRobert Mustacchi 	 * Reinitialize the tracking structure to basically set the maximum
36845b2c4190SRobert Mustacchi 	 * caps. These will be chipped away during the scan.
36855b2c4190SRobert Mustacchi 	 */
36865b2c4190SRobert Mustacchi 	fab->pfd_mps_found = PCIE_DEVCAP_MAX_PAYLOAD_4096;
36875b2c4190SRobert Mustacchi 	fab->pfd_tag_found = PCIE_TAG_ALL;
36885b2c4190SRobert Mustacchi 	fab->pfd_flags &= ~PCIE_FABRIC_F_COMPLEX;
36895b2c4190SRobert Mustacchi 
36905b2c4190SRobert Mustacchi 	ddi_walk_devs(dip, pcie_fabric_feature_scan, fab);
36915b2c4190SRobert Mustacchi 
36925b2c4190SRobert Mustacchi 	if ((fab->pfd_flags & PCIE_FABRIC_F_COMPLEX) != 0) {
36935b2c4190SRobert Mustacchi 		fab->pfd_tag_act = PCIE_TAG_5B;
36945b2c4190SRobert Mustacchi 		fab->pfd_mps_act = PCIE_DEVCAP_MAX_PAYLOAD_128;
36955b2c4190SRobert Mustacchi 	} else {
36965b2c4190SRobert Mustacchi 		fab->pfd_tag_act = fab->pfd_tag_found;
36975b2c4190SRobert Mustacchi 		fab->pfd_mps_act = fab->pfd_mps_found;
36985b2c4190SRobert Mustacchi 	}
36995b2c4190SRobert Mustacchi 
37005b2c4190SRobert Mustacchi 	ddi_walk_devs(dip, pcie_fabric_feature_set, fab);
37015b2c4190SRobert Mustacchi 
37025b2c4190SRobert Mustacchi 	fab->pfd_flags &= ~PCIE_FABRIC_F_SCANNING;
37033fe80ca4SDan Cross 	ndi_devi_exit(pdip);
37045b2c4190SRobert Mustacchi }
3705