1d4bc0535SKrishna Elango /*
2d4bc0535SKrishna Elango * CDDL HEADER START
3d4bc0535SKrishna Elango *
4d4bc0535SKrishna Elango * The contents of this file are subject to the terms of the
5d4bc0535SKrishna Elango * Common Development and Distribution License (the "License").
6d4bc0535SKrishna Elango * You may not use this file except in compliance with the License.
7d4bc0535SKrishna Elango *
8d4bc0535SKrishna Elango * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d4bc0535SKrishna Elango * or http://www.opensolaris.org/os/licensing.
10d4bc0535SKrishna Elango * See the License for the specific language governing permissions
11d4bc0535SKrishna Elango * and limitations under the License.
12d4bc0535SKrishna Elango *
13d4bc0535SKrishna Elango * When distributing Covered Code, include this CDDL HEADER in each
14d4bc0535SKrishna Elango * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d4bc0535SKrishna Elango * If applicable, add the following below this CDDL HEADER, with the
16d4bc0535SKrishna Elango * fields enclosed by brackets "[]" replaced with your own identifying
17d4bc0535SKrishna Elango * information: Portions Copyright [yyyy] [name of copyright owner]
18d4bc0535SKrishna Elango *
19d4bc0535SKrishna Elango * CDDL HEADER END
20d4bc0535SKrishna Elango */
219187c210SAlan Adamson, SD OSSD
22d4bc0535SKrishna Elango /*
2383e6495bSDaniel Ice * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24b3d69c05SRobert Mustacchi * Copyright 2019 Joyent, Inc.
25ead3c390SKeith M Wesolowski * Copyright 2024 Oxide Computer Company
26d4bc0535SKrishna Elango */
27d4bc0535SKrishna Elango
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
476d4bc0535SKrishna Elango #include <sys/sysmacros.h>
477d4bc0535SKrishna Elango #include <sys/types.h>
478d4bc0535SKrishna Elango #include <sys/kmem.h>
479d4bc0535SKrishna Elango #include <sys/modctl.h>
480d4bc0535SKrishna Elango #include <sys/ddi.h>
481d4bc0535SKrishna Elango #include <sys/sunddi.h>
482d4bc0535SKrishna Elango #include <sys/sunndi.h>
483d4bc0535SKrishna Elango #include <sys/fm/protocol.h>
484d4bc0535SKrishna Elango #include <sys/fm/util.h>
485d4bc0535SKrishna Elango #include <sys/promif.h>
486d4bc0535SKrishna Elango #include <sys/disp.h>
48726947304SEvan Yan #include <sys/stat.h>
48826947304SEvan Yan #include <sys/file.h>
489d4bc0535SKrishna Elango #include <sys/pci_cap.h>
49026947304SEvan Yan #include <sys/pci_impl.h>
491d4bc0535SKrishna Elango #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>
500d4bc0535SKrishna Elango
50126947304SEvan Yan /* Local functions prototypes */
502d4bc0535SKrishna Elango static void pcie_init_pfd(dev_info_t *);
503d4bc0535SKrishna Elango static void pcie_fini_pfd(dev_info_t *);
504d4bc0535SKrishna Elango
505d4bc0535SKrishna Elango #ifdef DEBUG
506d4bc0535SKrishna Elango uint_t pcie_debug_flags = 0;
507d4bc0535SKrishna Elango static void pcie_print_bus(pcie_bus_t *bus_p);
50826947304SEvan Yan void pcie_dbg(char *fmt, ...);
509d4bc0535SKrishna Elango #endif /* DEBUG */
510d4bc0535SKrishna Elango
511d4bc0535SKrishna Elango /* Variable to control default PCI-Express config settings */
512d4bc0535SKrishna Elango ushort_t pcie_command_default =
513d4bc0535SKrishna Elango PCI_COMM_SERR_ENABLE |
514d4bc0535SKrishna Elango PCI_COMM_WAIT_CYC_ENAB |
515d4bc0535SKrishna Elango PCI_COMM_PARITY_DETECT |
516d4bc0535SKrishna Elango PCI_COMM_ME |
517d4bc0535SKrishna Elango PCI_COMM_MAE |
518d4bc0535SKrishna Elango PCI_COMM_IO;
519d4bc0535SKrishna Elango
520d4bc0535SKrishna Elango /* xxx_fw are bits that are controlled by FW and should not be modified */
521d4bc0535SKrishna Elango ushort_t pcie_command_default_fw =
522d4bc0535SKrishna Elango PCI_COMM_SPEC_CYC |
523d4bc0535SKrishna Elango PCI_COMM_MEMWR_INVAL |
524d4bc0535SKrishna Elango PCI_COMM_PALETTE_SNOOP |
525d4bc0535SKrishna Elango PCI_COMM_WAIT_CYC_ENAB |
526d4bc0535SKrishna Elango 0xF800; /* Reserved Bits */
527d4bc0535SKrishna Elango
528d4bc0535SKrishna Elango ushort_t pcie_bdg_command_default_fw =
529d4bc0535SKrishna Elango PCI_BCNF_BCNTRL_ISA_ENABLE |
530d4bc0535SKrishna Elango PCI_BCNF_BCNTRL_VGA_ENABLE |
531d4bc0535SKrishna Elango 0xF000; /* Reserved Bits */
532d4bc0535SKrishna Elango
533d4bc0535SKrishna Elango /* PCI-Express Base error defaults */
534d4bc0535SKrishna Elango ushort_t pcie_base_err_default =
535d4bc0535SKrishna Elango PCIE_DEVCTL_CE_REPORTING_EN |
536d4bc0535SKrishna Elango PCIE_DEVCTL_NFE_REPORTING_EN |
537d4bc0535SKrishna Elango PCIE_DEVCTL_FE_REPORTING_EN |
538d4bc0535SKrishna Elango PCIE_DEVCTL_UR_REPORTING_EN;
539d4bc0535SKrishna Elango
540*28e5e903SRobert Mustacchi /*
541*28e5e903SRobert Mustacchi * This contains default values and masks that are used to manipulate the device
542*28e5e903SRobert Mustacchi * control register and ensure that it is in a normal state. The mask controls
543*28e5e903SRobert Mustacchi * things that are managed by pcie_fabric_setup(), firmware, or other sources
544*28e5e903SRobert Mustacchi * and therefore should be preserved unless we're explicitly trying to change
545*28e5e903SRobert Mustacchi * it.
546*28e5e903SRobert Mustacchi */
547*28e5e903SRobert Mustacchi uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN | PCIE_DEVCTL_MAX_READ_REQ_512;
548*28e5e903SRobert Mustacchi uint16_t pcie_devctl_default_mask = PCIE_DEVCTL_MAX_READ_REQ_MASK |
549*28e5e903SRobert Mustacchi PCIE_DEVCTL_MAX_PAYLOAD_MASK | PCIE_DEVCTL_EXT_TAG_FIELD_EN;
550d4bc0535SKrishna Elango
551d4bc0535SKrishna Elango /* PCI-Express AER Root Control Register */
552d4bc0535SKrishna Elango #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
553d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
554d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
555d4bc0535SKrishna Elango
556d4bc0535SKrishna Elango ushort_t pcie_root_ctrl_default =
557d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
558d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
559d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
560d4bc0535SKrishna Elango
561d4bc0535SKrishna Elango /* PCI-Express Root Error Command Register */
562d4bc0535SKrishna Elango ushort_t pcie_root_error_cmd_default =
563d4bc0535SKrishna Elango PCIE_AER_RE_CMD_CE_REP_EN |
564d4bc0535SKrishna Elango PCIE_AER_RE_CMD_NFE_REP_EN |
565d4bc0535SKrishna Elango PCIE_AER_RE_CMD_FE_REP_EN;
566d4bc0535SKrishna Elango
567d4bc0535SKrishna Elango /* ECRC settings in the PCIe AER Control Register */
568d4bc0535SKrishna Elango uint32_t pcie_ecrc_value =
569d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_GEN_ENA |
570d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_CHECK_ENA;
571d4bc0535SKrishna Elango
572d4bc0535SKrishna Elango /*
573d4bc0535SKrishna Elango * If a particular platform wants to disable certain errors such as UR/MA,
574d4bc0535SKrishna Elango * instead of using #defines have the platform's PCIe Root Complex driver set
575d4bc0535SKrishna Elango * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For
576d4bc0535SKrishna Elango * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the
577d4bc0535SKrishna Elango * closest PCIe root complex driver is PX.
578d4bc0535SKrishna Elango *
579d4bc0535SKrishna Elango * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
580d4bc0535SKrishna Elango * systems may want to disable SERR in general. For root ports, enabling SERR
581d4bc0535SKrishna Elango * causes NMIs which are not handled and results in a watchdog timeout error.
582d4bc0535SKrishna Elango */
583d4bc0535SKrishna Elango uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */
584d4bc0535SKrishna Elango uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */
585d4bc0535SKrishna Elango uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */
586d4bc0535SKrishna Elango uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */
587d4bc0535SKrishna Elango
588d4bc0535SKrishna Elango /* Default severities needed for eversholt. Error handling doesn't care */
589d4bc0535SKrishna Elango uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
590d4bc0535SKrishna Elango PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
591d4bc0535SKrishna Elango PCIE_AER_UCE_TRAINING;
592d4bc0535SKrishna Elango uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
593d4bc0535SKrishna Elango PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
594d4bc0535SKrishna Elango PCIE_AER_SUCE_USC_MSG_DATA_ERR;
595d4bc0535SKrishna Elango
59626947304SEvan Yan int pcie_disable_ari = 0;
597d4bc0535SKrishna Elango
598b3d69c05SRobert Mustacchi /*
599f7afc1fdSRobert Mustacchi * On some platforms, such as the AMD B450 chipset, we've seen an odd
600f7afc1fdSRobert Mustacchi * relationship between enabling link bandwidth notifications and AERs about
601f7afc1fdSRobert Mustacchi * ECRC errors. This provides a mechanism to disable it.
602f7afc1fdSRobert Mustacchi */
603f7afc1fdSRobert Mustacchi int pcie_disable_lbw = 0;
604f7afc1fdSRobert Mustacchi
605f7afc1fdSRobert Mustacchi /*
606b3d69c05SRobert Mustacchi * Amount of time to wait for an in-progress retraining. The default is to try
607b3d69c05SRobert Mustacchi * 500 times in 10ms chunks, thus a total of 5s.
608b3d69c05SRobert Mustacchi */
609b3d69c05SRobert Mustacchi uint32_t pcie_link_retrain_count = 500;
610b3d69c05SRobert Mustacchi uint32_t pcie_link_retrain_delay_ms = 10;
611b3d69c05SRobert Mustacchi
612b3d69c05SRobert Mustacchi taskq_t *pcie_link_tq;
613b3d69c05SRobert Mustacchi kmutex_t pcie_link_tq_mutex;
614b3d69c05SRobert Mustacchi
615b3d69c05SRobert Mustacchi static int pcie_link_bw_intr(dev_info_t *);
616b3d69c05SRobert Mustacchi static void pcie_capture_speeds(dev_info_t *);
617d4bc0535SKrishna Elango
618c0da6274SZhi-Jun Robin Fu dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
619c0da6274SZhi-Jun Robin Fu
620d4bc0535SKrishna Elango /*
621d4bc0535SKrishna Elango * modload support
622d4bc0535SKrishna Elango */
623d4bc0535SKrishna Elango
624d4bc0535SKrishna Elango static struct modlmisc modlmisc = {
625d4bc0535SKrishna Elango &mod_miscops, /* Type of module */
62626947304SEvan Yan "PCI Express Framework Module"
627d4bc0535SKrishna Elango };
628d4bc0535SKrishna Elango
629d4bc0535SKrishna Elango static struct modlinkage modlinkage = {
630d4bc0535SKrishna Elango MODREV_1,
631d4bc0535SKrishna Elango (void *)&modlmisc,
632d4bc0535SKrishna Elango NULL
633d4bc0535SKrishna Elango };
634d4bc0535SKrishna Elango
635d4bc0535SKrishna Elango /*
636d4bc0535SKrishna Elango * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
637d4bc0535SKrishna Elango * Currently used to send the pci.fabric ereports whose payload depends on the
638d4bc0535SKrishna Elango * type of PCI device it is being sent for.
639d4bc0535SKrishna Elango */
640d4bc0535SKrishna Elango char *pcie_nv_buf;
641d4bc0535SKrishna Elango nv_alloc_t *pcie_nvap;
642d4bc0535SKrishna Elango nvlist_t *pcie_nvl;
643d4bc0535SKrishna Elango
644d4bc0535SKrishna Elango int
_init(void)645d4bc0535SKrishna Elango _init(void)
646d4bc0535SKrishna Elango {
647d4bc0535SKrishna Elango int rval;
648d4bc0535SKrishna Elango
649d4bc0535SKrishna Elango pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
650d4bc0535SKrishna Elango pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
651d4bc0535SKrishna Elango pcie_nvl = fm_nvlist_create(pcie_nvap);
652b3d69c05SRobert Mustacchi mutex_init(&pcie_link_tq_mutex, NULL, MUTEX_DRIVER, NULL);
653d4bc0535SKrishna Elango
654c92295a9SAn Bui if ((rval = mod_install(&modlinkage)) != 0) {
655b3d69c05SRobert Mustacchi mutex_destroy(&pcie_link_tq_mutex);
656c92295a9SAn Bui fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
657c92295a9SAn Bui fm_nva_xdestroy(pcie_nvap);
658c92295a9SAn Bui kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
659c92295a9SAn Bui }
660d4bc0535SKrishna Elango return (rval);
661d4bc0535SKrishna Elango }
662d4bc0535SKrishna Elango
663d4bc0535SKrishna Elango int
_fini()664d4bc0535SKrishna Elango _fini()
665d4bc0535SKrishna Elango {
666d4bc0535SKrishna Elango int rval;
667d4bc0535SKrishna Elango
668c92295a9SAn Bui if ((rval = mod_remove(&modlinkage)) == 0) {
669b3d69c05SRobert Mustacchi if (pcie_link_tq != NULL) {
670b3d69c05SRobert Mustacchi taskq_destroy(pcie_link_tq);
671b3d69c05SRobert Mustacchi }
672b3d69c05SRobert Mustacchi mutex_destroy(&pcie_link_tq_mutex);
673d4bc0535SKrishna Elango fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
674d4bc0535SKrishna Elango fm_nva_xdestroy(pcie_nvap);
675d4bc0535SKrishna Elango kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
676c92295a9SAn Bui }
677d4bc0535SKrishna Elango return (rval);
678d4bc0535SKrishna Elango }
679d4bc0535SKrishna Elango
680d4bc0535SKrishna Elango int
_info(struct modinfo * modinfop)681d4bc0535SKrishna Elango _info(struct modinfo *modinfop)
682d4bc0535SKrishna Elango {
683d4bc0535SKrishna Elango return (mod_info(&modlinkage, modinfop));
684d4bc0535SKrishna Elango }
685d4bc0535SKrishna Elango
68626947304SEvan Yan /* ARGSUSED */
68726947304SEvan Yan int
pcie_init(dev_info_t * dip,caddr_t arg)68826947304SEvan Yan pcie_init(dev_info_t *dip, caddr_t arg)
68926947304SEvan Yan {
69026947304SEvan Yan int ret = DDI_SUCCESS;
69126947304SEvan Yan
69226947304SEvan Yan /*
693b3d69c05SRobert Mustacchi * Our _init function is too early to create a taskq. Create the pcie
694b3d69c05SRobert Mustacchi * link management taskq here now instead.
695b3d69c05SRobert Mustacchi */
696b3d69c05SRobert Mustacchi mutex_enter(&pcie_link_tq_mutex);
697b3d69c05SRobert Mustacchi if (pcie_link_tq == NULL) {
698b3d69c05SRobert Mustacchi pcie_link_tq = taskq_create("pcie_link", 1, minclsyspri, 0, 0,
699b3d69c05SRobert Mustacchi 0);
700b3d69c05SRobert Mustacchi }
701b3d69c05SRobert Mustacchi mutex_exit(&pcie_link_tq_mutex);
702b3d69c05SRobert Mustacchi
703b3d69c05SRobert Mustacchi
704b3d69c05SRobert Mustacchi /*
70526947304SEvan Yan * Create a "devctl" minor node to support DEVCTL_DEVICE_*
70626947304SEvan Yan * and DEVCTL_BUS_* ioctls to this bus.
70726947304SEvan Yan */
70826947304SEvan Yan if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
70926947304SEvan Yan PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
71026947304SEvan Yan DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
71126947304SEvan Yan PCIE_DBG("Failed to create devctl minor node for %s%d\n",
71226947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip));
71326947304SEvan Yan
71426947304SEvan Yan return (ret);
71526947304SEvan Yan }
71626947304SEvan Yan
71726947304SEvan Yan if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
71826947304SEvan Yan /*
719ed11b501SColin Zou - Sun Microsystems - Beijing China * On some x86 platforms, we observed unexpected hotplug
720ed11b501SColin Zou - Sun Microsystems - Beijing China * initialization failures in recent years. The known cause
721ed11b501SColin Zou - Sun Microsystems - Beijing China * is a hardware issue: while the problem PCI bridges have
722ed11b501SColin Zou - Sun Microsystems - Beijing China * the Hotplug Capable registers set, the machine actually
723ed11b501SColin Zou - Sun Microsystems - Beijing China * does not implement the expected ACPI object.
724ed11b501SColin Zou - Sun Microsystems - Beijing China *
725ed11b501SColin Zou - Sun Microsystems - Beijing China * We don't want to stop PCI driver attach and system boot
726ed11b501SColin Zou - Sun Microsystems - Beijing China * just because of this hotplug initialization failure.
727ed11b501SColin Zou - Sun Microsystems - Beijing China * Continue with a debug message printed.
72826947304SEvan Yan */
729ed11b501SColin Zou - Sun Microsystems - Beijing China PCIE_DBG("%s%d: Failed setting hotplug framework\n",
73026947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip));
73126947304SEvan Yan
73226947304SEvan Yan #if defined(__sparc)
73326947304SEvan Yan ddi_remove_minor_node(dip, "devctl");
73426947304SEvan Yan
73526947304SEvan Yan return (ret);
73626947304SEvan Yan #endif /* defined(__sparc) */
73726947304SEvan Yan }
73826947304SEvan Yan
73926947304SEvan Yan return (DDI_SUCCESS);
74026947304SEvan Yan }
74126947304SEvan Yan
74226947304SEvan Yan /* ARGSUSED */
74326947304SEvan Yan int
pcie_uninit(dev_info_t * dip)74426947304SEvan Yan pcie_uninit(dev_info_t *dip)
74526947304SEvan Yan {
74626947304SEvan Yan int ret = DDI_SUCCESS;
74726947304SEvan Yan
74826947304SEvan Yan if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
74926947304SEvan Yan (void) pcie_ari_disable(dip);
75026947304SEvan Yan
75126947304SEvan Yan if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
75226947304SEvan Yan PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
75326947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip));
75426947304SEvan Yan
75526947304SEvan Yan return (ret);
75626947304SEvan Yan }
75726947304SEvan Yan
758b3d69c05SRobert Mustacchi if (pcie_link_bw_supported(dip)) {
759b3d69c05SRobert Mustacchi (void) pcie_link_bw_disable(dip);
760b3d69c05SRobert Mustacchi }
761b3d69c05SRobert Mustacchi
76226947304SEvan Yan ddi_remove_minor_node(dip, "devctl");
76326947304SEvan Yan
76426947304SEvan Yan return (ret);
76526947304SEvan Yan }
76626947304SEvan Yan
76770f83219SEvan Yan /*
76870f83219SEvan Yan * PCIe module interface for enabling hotplug interrupt.
76970f83219SEvan Yan *
77070f83219SEvan Yan * It should be called after pcie_init() is done and bus driver's
77170f83219SEvan Yan * interrupt handlers have being attached.
77270f83219SEvan Yan */
77370f83219SEvan Yan int
pcie_hpintr_enable(dev_info_t * dip)77470f83219SEvan Yan pcie_hpintr_enable(dev_info_t *dip)
77570f83219SEvan Yan {
77670f83219SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
77770f83219SEvan Yan pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip);
77870f83219SEvan Yan
77970f83219SEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
78070f83219SEvan Yan (void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
78170f83219SEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
78270f83219SEvan Yan (void) pcishpc_enable_irqs(ctrl_p);
78370f83219SEvan Yan }
78470f83219SEvan Yan return (DDI_SUCCESS);
78570f83219SEvan Yan }
78670f83219SEvan Yan
78770f83219SEvan Yan /*
78870f83219SEvan Yan * PCIe module interface for disabling hotplug interrupt.
78970f83219SEvan Yan *
79070f83219SEvan Yan * It should be called before pcie_uninit() is called and bus driver's
79170f83219SEvan Yan * interrupt handlers is dettached.
79270f83219SEvan Yan */
79370f83219SEvan Yan int
pcie_hpintr_disable(dev_info_t * dip)79470f83219SEvan Yan pcie_hpintr_disable(dev_info_t *dip)
79570f83219SEvan Yan {
79670f83219SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
79770f83219SEvan Yan pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip);
79870f83219SEvan Yan
79970f83219SEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
80070f83219SEvan Yan (void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
80170f83219SEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
80270f83219SEvan Yan (void) pcishpc_disable_irqs(ctrl_p);
80370f83219SEvan Yan }
80470f83219SEvan Yan return (DDI_SUCCESS);
80570f83219SEvan Yan }
80670f83219SEvan Yan
80726947304SEvan Yan /* ARGSUSED */
80826947304SEvan Yan int
pcie_intr(dev_info_t * dip)80926947304SEvan Yan pcie_intr(dev_info_t *dip)
81026947304SEvan Yan {
811b3d69c05SRobert Mustacchi int hp, lbw;
812b3d69c05SRobert Mustacchi
813b3d69c05SRobert Mustacchi hp = pcie_hp_intr(dip);
814b3d69c05SRobert Mustacchi lbw = pcie_link_bw_intr(dip);
815b3d69c05SRobert Mustacchi
816b3d69c05SRobert Mustacchi if (hp == DDI_INTR_CLAIMED || lbw == DDI_INTR_CLAIMED) {
817b3d69c05SRobert Mustacchi return (DDI_INTR_CLAIMED);
818b3d69c05SRobert Mustacchi }
819b3d69c05SRobert Mustacchi
820b3d69c05SRobert Mustacchi return (DDI_INTR_UNCLAIMED);
82126947304SEvan Yan }
82226947304SEvan Yan
82326947304SEvan Yan /* ARGSUSED */
82426947304SEvan Yan int
pcie_open(dev_info_t * dip,dev_t * devp,int flags,int otyp,cred_t * credp)82526947304SEvan Yan pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
82626947304SEvan Yan {
82726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
82826947304SEvan Yan
82926947304SEvan Yan /*
83026947304SEvan Yan * Make sure the open is for the right file type.
83126947304SEvan Yan */
83226947304SEvan Yan if (otyp != OTYP_CHR)
83326947304SEvan Yan return (EINVAL);
83426947304SEvan Yan
83526947304SEvan Yan /*
83626947304SEvan Yan * Handle the open by tracking the device state.
83726947304SEvan Yan */
83826947304SEvan Yan if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
83926947304SEvan Yan ((flags & FEXCL) &&
84026947304SEvan Yan (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
84126947304SEvan Yan return (EBUSY);
84226947304SEvan Yan }
84326947304SEvan Yan
84426947304SEvan Yan if (flags & FEXCL)
84526947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
84626947304SEvan Yan else
84726947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
84826947304SEvan Yan
84926947304SEvan Yan return (0);
85026947304SEvan Yan }
85126947304SEvan Yan
85226947304SEvan Yan /* ARGSUSED */
85326947304SEvan Yan int
pcie_close(dev_info_t * dip,dev_t dev,int flags,int otyp,cred_t * credp)85426947304SEvan Yan pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
85526947304SEvan Yan {
85626947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
85726947304SEvan Yan
85826947304SEvan Yan if (otyp != OTYP_CHR)
85926947304SEvan Yan return (EINVAL);
86026947304SEvan Yan
86126947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
86226947304SEvan Yan
86326947304SEvan Yan return (0);
86426947304SEvan Yan }
86526947304SEvan Yan
86626947304SEvan Yan /* ARGSUSED */
86726947304SEvan Yan int
pcie_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)86826947304SEvan Yan pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
86926947304SEvan Yan cred_t *credp, int *rvalp)
87026947304SEvan Yan {
87126947304SEvan Yan struct devctl_iocdata *dcp;
87226947304SEvan Yan uint_t bus_state;
87326947304SEvan Yan int rv = DDI_SUCCESS;
87426947304SEvan Yan
87526947304SEvan Yan /*
87626947304SEvan Yan * We can use the generic implementation for devctl ioctl
87726947304SEvan Yan */
87826947304SEvan Yan switch (cmd) {
87926947304SEvan Yan case DEVCTL_DEVICE_GETSTATE:
88026947304SEvan Yan case DEVCTL_DEVICE_ONLINE:
88126947304SEvan Yan case DEVCTL_DEVICE_OFFLINE:
88226947304SEvan Yan case DEVCTL_BUS_GETSTATE:
88326947304SEvan Yan return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
88426947304SEvan Yan default:
88526947304SEvan Yan break;
88626947304SEvan Yan }
88726947304SEvan Yan
88826947304SEvan Yan /*
88926947304SEvan Yan * read devctl ioctl data
89026947304SEvan Yan */
89126947304SEvan Yan if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
89226947304SEvan Yan return (EFAULT);
89326947304SEvan Yan
89426947304SEvan Yan switch (cmd) {
89526947304SEvan Yan case DEVCTL_BUS_QUIESCE:
89626947304SEvan Yan if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
89726947304SEvan Yan if (bus_state == BUS_QUIESCED)
89826947304SEvan Yan break;
89926947304SEvan Yan (void) ndi_set_bus_state(dip, BUS_QUIESCED);
90026947304SEvan Yan break;
90126947304SEvan Yan case DEVCTL_BUS_UNQUIESCE:
90226947304SEvan Yan if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
90326947304SEvan Yan if (bus_state == BUS_ACTIVE)
90426947304SEvan Yan break;
90526947304SEvan Yan (void) ndi_set_bus_state(dip, BUS_ACTIVE);
90626947304SEvan Yan break;
90726947304SEvan Yan case DEVCTL_BUS_RESET:
90826947304SEvan Yan case DEVCTL_BUS_RESETALL:
90926947304SEvan Yan case DEVCTL_DEVICE_RESET:
91026947304SEvan Yan rv = ENOTSUP;
91126947304SEvan Yan break;
91226947304SEvan Yan default:
91326947304SEvan Yan rv = ENOTTY;
91426947304SEvan Yan }
91526947304SEvan Yan
91626947304SEvan Yan ndi_dc_freehdl(dcp);
91726947304SEvan Yan return (rv);
91826947304SEvan Yan }
91926947304SEvan Yan
92026947304SEvan Yan /* ARGSUSED */
92126947304SEvan 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)92226947304SEvan Yan pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
92326947304SEvan Yan int flags, char *name, caddr_t valuep, int *lengthp)
92426947304SEvan Yan {
92526947304SEvan Yan if (dev == DDI_DEV_T_ANY)
92626947304SEvan Yan goto skip;
92726947304SEvan Yan
92826947304SEvan Yan if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
92926947304SEvan Yan strcmp(name, "pci-occupant") == 0) {
93026947304SEvan Yan int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
93126947304SEvan Yan
93226947304SEvan Yan pcie_hp_create_occupant_props(dip, dev, pci_dev);
93326947304SEvan Yan }
93426947304SEvan Yan
93526947304SEvan Yan skip:
93626947304SEvan Yan return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
93726947304SEvan Yan }
93826947304SEvan Yan
939c0da6274SZhi-Jun Robin Fu int
pcie_init_cfghdl(dev_info_t * cdip)940c0da6274SZhi-Jun Robin Fu pcie_init_cfghdl(dev_info_t *cdip)
941c0da6274SZhi-Jun Robin Fu {
942c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p;
943c0da6274SZhi-Jun Robin Fu ddi_acc_handle_t eh = NULL;
944c0da6274SZhi-Jun Robin Fu
945c0da6274SZhi-Jun Robin Fu bus_p = PCIE_DIP2BUS(cdip);
946c0da6274SZhi-Jun Robin Fu if (bus_p == NULL)
947c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE);
948c0da6274SZhi-Jun Robin Fu
949c0da6274SZhi-Jun Robin Fu /* Create an config access special to error handling */
950c0da6274SZhi-Jun Robin Fu if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
951c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN, "Cannot setup config access"
952c0da6274SZhi-Jun Robin Fu " for BDF 0x%x\n", bus_p->bus_bdf);
953c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE);
954c0da6274SZhi-Jun Robin Fu }
955c0da6274SZhi-Jun Robin Fu
956c0da6274SZhi-Jun Robin Fu bus_p->bus_cfg_hdl = eh;
957c0da6274SZhi-Jun Robin Fu return (DDI_SUCCESS);
958c0da6274SZhi-Jun Robin Fu }
959c0da6274SZhi-Jun Robin Fu
960c0da6274SZhi-Jun Robin Fu void
pcie_fini_cfghdl(dev_info_t * cdip)961c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(dev_info_t *cdip)
962c0da6274SZhi-Jun Robin Fu {
963c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
964c0da6274SZhi-Jun Robin Fu
965c0da6274SZhi-Jun Robin Fu pci_config_teardown(&bus_p->bus_cfg_hdl);
966c0da6274SZhi-Jun Robin Fu }
967c0da6274SZhi-Jun Robin Fu
968826c0d1dSRobert Mustacchi void
pcie_determine_serial(dev_info_t * dip)969826c0d1dSRobert Mustacchi pcie_determine_serial(dev_info_t *dip)
970826c0d1dSRobert Mustacchi {
971826c0d1dSRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
972826c0d1dSRobert Mustacchi ddi_acc_handle_t h;
973826c0d1dSRobert Mustacchi uint16_t cap;
974826c0d1dSRobert Mustacchi uchar_t serial[8];
975826c0d1dSRobert Mustacchi uint32_t low, high;
976826c0d1dSRobert Mustacchi
977826c0d1dSRobert Mustacchi if (!PCIE_IS_PCIE(bus_p))
978826c0d1dSRobert Mustacchi return;
979826c0d1dSRobert Mustacchi
980826c0d1dSRobert Mustacchi h = bus_p->bus_cfg_hdl;
981826c0d1dSRobert Mustacchi
982826c0d1dSRobert Mustacchi if ((PCI_CAP_LOCATE(h, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap)) ==
983826c0d1dSRobert Mustacchi DDI_FAILURE)
984826c0d1dSRobert Mustacchi return;
985826c0d1dSRobert Mustacchi
986826c0d1dSRobert Mustacchi high = PCI_XCAP_GET32(h, 0, cap, PCIE_SER_SID_UPPER_DW);
987826c0d1dSRobert Mustacchi low = PCI_XCAP_GET32(h, 0, cap, PCIE_SER_SID_LOWER_DW);
988826c0d1dSRobert Mustacchi
989826c0d1dSRobert Mustacchi /*
990826c0d1dSRobert Mustacchi * Here, we're trying to figure out if we had an invalid PCIe read. From
991826c0d1dSRobert Mustacchi * looking at the contents of the value, it can be hard to tell the
992826c0d1dSRobert Mustacchi * difference between a value that has all 1s correctly versus if we had
993826c0d1dSRobert Mustacchi * an error. In this case, we only assume it's invalid if both register
994826c0d1dSRobert Mustacchi * reads are invalid. We also only use 32-bit reads as we're not sure if
995826c0d1dSRobert Mustacchi * all devices will support these as 64-bit reads, while we know that
996826c0d1dSRobert Mustacchi * they'll support these as 32-bit reads.
997826c0d1dSRobert Mustacchi */
998826c0d1dSRobert Mustacchi if (high == PCI_EINVAL32 && low == PCI_EINVAL32)
999826c0d1dSRobert Mustacchi return;
1000826c0d1dSRobert Mustacchi
1001826c0d1dSRobert Mustacchi serial[0] = low & 0xff;
1002826c0d1dSRobert Mustacchi serial[1] = (low >> 8) & 0xff;
1003826c0d1dSRobert Mustacchi serial[2] = (low >> 16) & 0xff;
1004826c0d1dSRobert Mustacchi serial[3] = (low >> 24) & 0xff;
1005826c0d1dSRobert Mustacchi serial[4] = high & 0xff;
1006826c0d1dSRobert Mustacchi serial[5] = (high >> 8) & 0xff;
1007826c0d1dSRobert Mustacchi serial[6] = (high >> 16) & 0xff;
1008826c0d1dSRobert Mustacchi serial[7] = (high >> 24) & 0xff;
1009826c0d1dSRobert Mustacchi
1010826c0d1dSRobert Mustacchi (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "pcie-serial",
1011826c0d1dSRobert Mustacchi serial, sizeof (serial));
1012826c0d1dSRobert Mustacchi }
1013826c0d1dSRobert Mustacchi
1014f7afc1fdSRobert Mustacchi static void
pcie_determine_aspm(dev_info_t * dip)1015f7afc1fdSRobert Mustacchi pcie_determine_aspm(dev_info_t *dip)
1016f7afc1fdSRobert Mustacchi {
1017f7afc1fdSRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1018f7afc1fdSRobert Mustacchi uint32_t linkcap;
1019f7afc1fdSRobert Mustacchi uint16_t linkctl;
1020f7afc1fdSRobert Mustacchi
1021f7afc1fdSRobert Mustacchi if (!PCIE_IS_PCIE(bus_p))
1022f7afc1fdSRobert Mustacchi return;
1023f7afc1fdSRobert Mustacchi
1024f7afc1fdSRobert Mustacchi linkcap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
1025f7afc1fdSRobert Mustacchi linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
1026f7afc1fdSRobert Mustacchi
1027f7afc1fdSRobert Mustacchi switch (linkcap & PCIE_LINKCAP_ASPM_SUP_MASK) {
1028f7afc1fdSRobert Mustacchi case PCIE_LINKCAP_ASPM_SUP_L0S:
1029f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1030f7afc1fdSRobert Mustacchi "pcie-aspm-support", "l0s");
1031f7afc1fdSRobert Mustacchi break;
1032f7afc1fdSRobert Mustacchi case PCIE_LINKCAP_ASPM_SUP_L1:
1033f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1034f7afc1fdSRobert Mustacchi "pcie-aspm-support", "l1");
1035f7afc1fdSRobert Mustacchi break;
1036f7afc1fdSRobert Mustacchi case PCIE_LINKCAP_ASPM_SUP_L0S_L1:
1037f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1038f7afc1fdSRobert Mustacchi "pcie-aspm-support", "l0s,l1");
1039f7afc1fdSRobert Mustacchi break;
1040f7afc1fdSRobert Mustacchi default:
1041f7afc1fdSRobert Mustacchi return;
1042f7afc1fdSRobert Mustacchi }
1043f7afc1fdSRobert Mustacchi
1044f7afc1fdSRobert Mustacchi switch (linkctl & PCIE_LINKCTL_ASPM_CTL_MASK) {
1045f7afc1fdSRobert Mustacchi case PCIE_LINKCTL_ASPM_CTL_DIS:
1046f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1047f7afc1fdSRobert Mustacchi "pcie-aspm-state", "disabled");
1048f7afc1fdSRobert Mustacchi break;
1049f7afc1fdSRobert Mustacchi case PCIE_LINKCTL_ASPM_CTL_L0S:
1050f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1051f7afc1fdSRobert Mustacchi "pcie-aspm-state", "l0s");
1052f7afc1fdSRobert Mustacchi break;
1053f7afc1fdSRobert Mustacchi case PCIE_LINKCTL_ASPM_CTL_L1:
1054f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1055f7afc1fdSRobert Mustacchi "pcie-aspm-state", "l1");
1056f7afc1fdSRobert Mustacchi break;
1057f7afc1fdSRobert Mustacchi case PCIE_LINKCTL_ASPM_CTL_L0S_L1:
1058f7afc1fdSRobert Mustacchi (void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
1059f7afc1fdSRobert Mustacchi "pcie-aspm-state", "l0s,l1");
1060f7afc1fdSRobert Mustacchi break;
1061f7afc1fdSRobert Mustacchi }
1062f7afc1fdSRobert Mustacchi }
1063f7afc1fdSRobert Mustacchi
1064d4bc0535SKrishna Elango /*
10655b2c4190SRobert Mustacchi * PCI-Express child device initialization. Note, this only will be called on a
10665b2c4190SRobert Mustacchi * device or function if we actually attach a device driver to it.
10675b2c4190SRobert Mustacchi *
10685b2c4190SRobert Mustacchi * This function enables generic pci-express interrupts and error handling.
10695b2c4190SRobert Mustacchi * Note, tagging, the max packet size, and related are all set up before this
10705b2c4190SRobert Mustacchi * point and is performed in pcie_fabric_setup().
1071d4bc0535SKrishna Elango *
1072d4bc0535SKrishna Elango * @param pdip root dip (root nexus's dip)
1073d4bc0535SKrishna Elango * @param cdip child's dip (device's dip)
1074d4bc0535SKrishna Elango * @return DDI_SUCCESS or DDI_FAILURE
1075d4bc0535SKrishna Elango */
1076d4bc0535SKrishna Elango /* ARGSUSED */
1077d4bc0535SKrishna Elango int
pcie_initchild(dev_info_t * cdip)1078d4bc0535SKrishna Elango pcie_initchild(dev_info_t *cdip)
1079d4bc0535SKrishna Elango {
1080d4bc0535SKrishna Elango uint16_t tmp16, reg16;
1081d4bc0535SKrishna Elango pcie_bus_t *bus_p;
1082d4bc0535SKrishna Elango
1083d4bc0535SKrishna Elango bus_p = PCIE_DIP2BUS(cdip);
1084d4bc0535SKrishna Elango if (bus_p == NULL) {
1085d4bc0535SKrishna Elango PCIE_DBG("%s: BUS not found.\n",
1086d4bc0535SKrishna Elango ddi_driver_name(cdip));
1087d4bc0535SKrishna Elango
1088d4bc0535SKrishna Elango return (DDI_FAILURE);
1089d4bc0535SKrishna Elango }
1090d4bc0535SKrishna Elango
1091c0da6274SZhi-Jun Robin Fu if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
1092c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE);
1093c0da6274SZhi-Jun Robin Fu
1094d4bc0535SKrishna Elango /* Clear the device's status register */
1095d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
1096d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
1097d4bc0535SKrishna Elango
1098d4bc0535SKrishna Elango /* Setup the device's command register */
1099d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
1100d4bc0535SKrishna Elango tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
1101d4bc0535SKrishna Elango
1102d4bc0535SKrishna Elango if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
1103d4bc0535SKrishna Elango tmp16 &= ~PCI_COMM_SERR_ENABLE;
1104d4bc0535SKrishna Elango
1105d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
1106d4bc0535SKrishna Elango PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
1107d4bc0535SKrishna Elango
1108d4bc0535SKrishna Elango /*
1109d4bc0535SKrishna Elango * If the device has a bus control register then program it
1110d4bc0535SKrishna Elango * based on the settings in the command register.
1111d4bc0535SKrishna Elango */
1112d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) {
1113d4bc0535SKrishna Elango /* Clear the device's secondary status register */
1114d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
1115d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
1116d4bc0535SKrishna Elango
1117d4bc0535SKrishna Elango /* Setup the device's secondary command register */
1118d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
1119d4bc0535SKrishna Elango tmp16 = (reg16 & pcie_bdg_command_default_fw);
1120d4bc0535SKrishna Elango
1121d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
1122d4bc0535SKrishna Elango /*
1123d4bc0535SKrishna Elango * Workaround for this Nvidia bridge. Don't enable the SERR
1124d4bc0535SKrishna Elango * enable bit in the bridge control register as it could lead to
1125d4bc0535SKrishna Elango * bogus NMIs.
1126d4bc0535SKrishna Elango */
1127d4bc0535SKrishna Elango if (bus_p->bus_dev_ven_id == 0x037010DE)
1128d4bc0535SKrishna Elango tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
1129d4bc0535SKrishna Elango
1130d4bc0535SKrishna Elango if (pcie_command_default & PCI_COMM_PARITY_DETECT)
1131d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
1132d4bc0535SKrishna Elango
1133d4bc0535SKrishna Elango /*
1134d4bc0535SKrishna Elango * Enable Master Abort Mode only if URs have not been masked.
1135d4bc0535SKrishna Elango * For PCI and PCIe-PCI bridges, enabling this bit causes a
1136d4bc0535SKrishna Elango * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this
1137d4bc0535SKrishna Elango * bit is masked, posted requests are dropped and non-posted
1138d4bc0535SKrishna Elango * requests are returned with -1.
1139d4bc0535SKrishna Elango */
1140d4bc0535SKrishna Elango if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
1141d4bc0535SKrishna Elango tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
1142d4bc0535SKrishna Elango else
1143d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
1144d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
1145d4bc0535SKrishna Elango PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
1146d4bc0535SKrishna Elango reg16);
1147d4bc0535SKrishna Elango }
1148d4bc0535SKrishna Elango
1149d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) {
1150*28e5e903SRobert Mustacchi /*
1151*28e5e903SRobert Mustacchi * Get the device control register into an initial state that
1152*28e5e903SRobert Mustacchi * makes sense. The maximum payload, tagging, and related will
1153*28e5e903SRobert Mustacchi * be dealt with in pcie_fabric_setup().
1154*28e5e903SRobert Mustacchi */
1155d4bc0535SKrishna Elango reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
1156*28e5e903SRobert Mustacchi tmp16 = (reg16 & pcie_devctl_default_mask) |
1157*28e5e903SRobert Mustacchi (pcie_devctl_default & ~pcie_devctl_default_mask);
1158d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
1159d4bc0535SKrishna Elango PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
1160d4bc0535SKrishna Elango
1161d4bc0535SKrishna Elango /* Enable PCIe errors */
1162d4bc0535SKrishna Elango pcie_enable_errors(cdip);
1163826c0d1dSRobert Mustacchi
1164826c0d1dSRobert Mustacchi pcie_determine_serial(cdip);
1165b3d69c05SRobert Mustacchi
1166f7afc1fdSRobert Mustacchi pcie_determine_aspm(cdip);
1167f7afc1fdSRobert Mustacchi
1168b3d69c05SRobert Mustacchi pcie_capture_speeds(cdip);
1169d4bc0535SKrishna Elango }
1170d4bc0535SKrishna Elango
117126947304SEvan Yan bus_p->bus_ari = B_FALSE;
117226947304SEvan Yan if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
117326947304SEvan Yan == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
117426947304SEvan Yan == PCIE_ARI_DEVICE)) {
117526947304SEvan Yan bus_p->bus_ari = B_TRUE;
117626947304SEvan Yan }
117726947304SEvan Yan
1178d4bc0535SKrishna Elango return (DDI_SUCCESS);
1179d4bc0535SKrishna Elango }
1180d4bc0535SKrishna Elango
1181d4bc0535SKrishna Elango static void
pcie_init_pfd(dev_info_t * dip)1182d4bc0535SKrishna Elango pcie_init_pfd(dev_info_t *dip)
1183d4bc0535SKrishna Elango {
1184d4bc0535SKrishna Elango pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t);
1185d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1186d4bc0535SKrishna Elango
1187d4bc0535SKrishna Elango PCIE_DIP2PFD(dip) = pfd_p;
1188d4bc0535SKrishna Elango
1189d4bc0535SKrishna Elango pfd_p->pe_bus_p = bus_p;
1190d4bc0535SKrishna Elango pfd_p->pe_severity_flags = 0;
119179bed773SHans Rosenfeld pfd_p->pe_severity_mask = 0;
1192fc256490SJason Beloro pfd_p->pe_orig_severity_flags = 0;
1193d4bc0535SKrishna Elango pfd_p->pe_lock = B_FALSE;
1194d4bc0535SKrishna Elango pfd_p->pe_valid = B_FALSE;
1195d4bc0535SKrishna Elango
1196d4bc0535SKrishna Elango /* Allocate the root fault struct for both RC and RP */
1197d4bc0535SKrishna Elango if (PCIE_IS_ROOT(bus_p)) {
1198d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
1199d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
1200fc256490SJason Beloro PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
1201d4bc0535SKrishna Elango }
1202d4bc0535SKrishna Elango
1203d4bc0535SKrishna Elango PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
1204fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
1205fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
1206d4bc0535SKrishna Elango
1207d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p))
1208d4bc0535SKrishna Elango PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
1209d4bc0535SKrishna Elango
1210d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) {
1211d4bc0535SKrishna Elango PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
1212d4bc0535SKrishna Elango
1213d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p))
1214d4bc0535SKrishna Elango PCIE_RP_REG(pfd_p) =
1215d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
1216d4bc0535SKrishna Elango
1217d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
1218d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
1219d4bc0535SKrishna Elango
1220d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) {
1221d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p) =
1222d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
1223d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
1224d4bc0535SKrishna Elango PCIE_INVALID_BDF;
1225d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
1226d4bc0535SKrishna Elango PCIE_INVALID_BDF;
1227d4bc0535SKrishna Elango } else if (PCIE_IS_PCIE_BDG(bus_p)) {
1228d4bc0535SKrishna Elango PCIE_ADV_BDG_REG(pfd_p) =
1229d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
1230d4bc0535SKrishna Elango PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
1231d4bc0535SKrishna Elango PCIE_INVALID_BDF;
1232d4bc0535SKrishna Elango }
1233d4bc0535SKrishna Elango
1234d4bc0535SKrishna Elango if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
1235d4bc0535SKrishna Elango PCIX_BDG_ERR_REG(pfd_p) =
1236d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
1237d4bc0535SKrishna Elango
1238d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1239d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 0) =
1240d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1241d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 1) =
1242d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1243d4bc0535SKrishna Elango }
1244d4bc0535SKrishna Elango }
1245ffb64830SJordan Paige Hendricks
1246ffb64830SJordan Paige Hendricks PCIE_SLOT_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_slot_regs_t);
1247ffb64830SJordan Paige Hendricks PCIE_SLOT_REG(pfd_p)->pcie_slot_regs_valid = B_FALSE;
1248ffb64830SJordan Paige Hendricks PCIE_SLOT_REG(pfd_p)->pcie_slot_cap = 0;
1249ffb64830SJordan Paige Hendricks PCIE_SLOT_REG(pfd_p)->pcie_slot_control = 0;
1250ffb64830SJordan Paige Hendricks PCIE_SLOT_REG(pfd_p)->pcie_slot_status = 0;
1251ffb64830SJordan Paige Hendricks
1252d4bc0535SKrishna Elango } else if (PCIE_IS_PCIX(bus_p)) {
1253d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) {
1254d4bc0535SKrishna Elango PCIX_BDG_ERR_REG(pfd_p) =
1255d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
1256d4bc0535SKrishna Elango
1257d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1258d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 0) =
1259d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1260d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 1) =
1261d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1262d4bc0535SKrishna Elango }
1263d4bc0535SKrishna Elango } else {
1264d4bc0535SKrishna Elango PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
1265d4bc0535SKrishna Elango
1266d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p))
1267d4bc0535SKrishna Elango PCIX_ECC_REG(pfd_p) =
1268d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t);
1269d4bc0535SKrishna Elango }
1270d4bc0535SKrishna Elango }
1271d4bc0535SKrishna Elango }
1272d4bc0535SKrishna Elango
1273d4bc0535SKrishna Elango static void
pcie_fini_pfd(dev_info_t * dip)1274d4bc0535SKrishna Elango pcie_fini_pfd(dev_info_t *dip)
1275d4bc0535SKrishna Elango {
1276d4bc0535SKrishna Elango pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
1277d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1278d4bc0535SKrishna Elango
1279d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) {
1280d4bc0535SKrishna Elango if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
1281d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1282d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
1283d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t));
1284d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
1285d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t));
1286d4bc0535SKrishna Elango }
1287d4bc0535SKrishna Elango
1288d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ERR_REG(pfd_p),
1289d4bc0535SKrishna Elango sizeof (pf_pcix_bdg_err_regs_t));
1290d4bc0535SKrishna Elango }
1291d4bc0535SKrishna Elango
1292d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p))
1293d4bc0535SKrishna Elango kmem_free(PCIE_ADV_RP_REG(pfd_p),
1294d4bc0535SKrishna Elango sizeof (pf_pcie_adv_rp_err_regs_t));
1295d4bc0535SKrishna Elango else if (PCIE_IS_PCIE_BDG(bus_p))
1296d4bc0535SKrishna Elango kmem_free(PCIE_ADV_BDG_REG(pfd_p),
1297d4bc0535SKrishna Elango sizeof (pf_pcie_adv_bdg_err_regs_t));
1298d4bc0535SKrishna Elango
1299d4bc0535SKrishna Elango kmem_free(PCIE_ADV_REG(pfd_p),
1300d4bc0535SKrishna Elango sizeof (pf_pcie_adv_err_regs_t));
1301d4bc0535SKrishna Elango
1302d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p))
1303d4bc0535SKrishna Elango kmem_free(PCIE_RP_REG(pfd_p),
1304d4bc0535SKrishna Elango sizeof (pf_pcie_rp_err_regs_t));
1305d4bc0535SKrishna Elango
1306d4bc0535SKrishna Elango kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
1307d4bc0535SKrishna Elango } else if (PCIE_IS_PCIX(bus_p)) {
1308d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) {
1309d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) {
1310d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
1311d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t));
1312d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
1313d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t));
1314d4bc0535SKrishna Elango }
1315d4bc0535SKrishna Elango
1316d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ERR_REG(pfd_p),
1317d4bc0535SKrishna Elango sizeof (pf_pcix_bdg_err_regs_t));
1318d4bc0535SKrishna Elango } else {
1319d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p))
1320d4bc0535SKrishna Elango kmem_free(PCIX_ECC_REG(pfd_p),
1321d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t));
1322d4bc0535SKrishna Elango
1323d4bc0535SKrishna Elango kmem_free(PCIX_ERR_REG(pfd_p),
1324d4bc0535SKrishna Elango sizeof (pf_pcix_err_regs_t));
1325d4bc0535SKrishna Elango }
1326d4bc0535SKrishna Elango }
1327d4bc0535SKrishna Elango
1328d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p))
1329d4bc0535SKrishna Elango kmem_free(PCI_BDG_ERR_REG(pfd_p),
1330d4bc0535SKrishna Elango sizeof (pf_pci_bdg_err_regs_t));
1331d4bc0535SKrishna Elango
1332fc256490SJason Beloro kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
1333d4bc0535SKrishna Elango kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
1334d4bc0535SKrishna Elango
1335fc256490SJason Beloro if (PCIE_IS_ROOT(bus_p)) {
1336d4bc0535SKrishna Elango kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
1337fc256490SJason Beloro kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
1338fc256490SJason Beloro }
1339d4bc0535SKrishna Elango
1340d4bc0535SKrishna Elango kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
1341d4bc0535SKrishna Elango
1342d4bc0535SKrishna Elango PCIE_DIP2PFD(dip) = NULL;
1343d4bc0535SKrishna Elango }
1344d4bc0535SKrishna Elango
1345d4bc0535SKrishna Elango
1346d4bc0535SKrishna Elango /*
1347d4bc0535SKrishna Elango * Special functions to allocate pf_data_t's for PCIe root complexes.
1348d4bc0535SKrishna Elango * Note: Root Complex not Root Port
1349d4bc0535SKrishna Elango */
1350d4bc0535SKrishna Elango void
pcie_rc_init_pfd(dev_info_t * dip,pf_data_t * pfd_p)1351d4bc0535SKrishna Elango pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
1352d4bc0535SKrishna Elango {
1353d4bc0535SKrishna Elango pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
1354d4bc0535SKrishna Elango pfd_p->pe_severity_flags = 0;
135579bed773SHans Rosenfeld pfd_p->pe_severity_mask = 0;
1356fc256490SJason Beloro pfd_p->pe_orig_severity_flags = 0;
1357d4bc0535SKrishna Elango pfd_p->pe_lock = B_FALSE;
1358d4bc0535SKrishna Elango pfd_p->pe_valid = B_FALSE;
1359d4bc0535SKrishna Elango
1360d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
1361d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
1362fc256490SJason Beloro PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
1363d4bc0535SKrishna Elango PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
1364fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
1365fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
1366d4bc0535SKrishna Elango PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
1367d4bc0535SKrishna Elango PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
1368d4bc0535SKrishna Elango PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
1369d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
1370d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
1371fc256490SJason Beloro PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF;
1372fc256490SJason Beloro PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF;
1373d4bc0535SKrishna Elango
1374d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
1375d4bc0535SKrishna Elango }
1376d4bc0535SKrishna Elango
1377d4bc0535SKrishna Elango void
pcie_rc_fini_pfd(pf_data_t * pfd_p)1378d4bc0535SKrishna Elango pcie_rc_fini_pfd(pf_data_t *pfd_p)
1379d4bc0535SKrishna Elango {
1380d4bc0535SKrishna Elango kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
1381d4bc0535SKrishna Elango kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
1382d4bc0535SKrishna Elango kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
1383d4bc0535SKrishna Elango kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
1384d4bc0535SKrishna Elango kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
1385fc256490SJason Beloro kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
1386d4bc0535SKrishna Elango kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
1387d4bc0535SKrishna Elango kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
1388fc256490SJason Beloro kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
1389d4bc0535SKrishna Elango }
1390d4bc0535SKrishna Elango
1391c0da6274SZhi-Jun Robin Fu /*
1392c0da6274SZhi-Jun Robin Fu * init pcie_bus_t for root complex
1393c0da6274SZhi-Jun Robin Fu *
1394c0da6274SZhi-Jun Robin Fu * Only a few of the fields in bus_t is valid for root complex.
1395c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized in this routine:
1396c0da6274SZhi-Jun Robin Fu *
1397c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_dip>
1398c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_rp_dip
1399c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl
1400c0da6274SZhi-Jun Robin Fu * uint_t <bus_fm_flags>
1401c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_bdf
1402c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_rp_bdf
1403c0da6274SZhi-Jun Robin Fu * uint32_t bus_dev_ven_id
1404c0da6274SZhi-Jun Robin Fu * uint8_t bus_rev_id
1405c0da6274SZhi-Jun Robin Fu * uint8_t <bus_hdr_type>
1406c0da6274SZhi-Jun Robin Fu * uint16_t <bus_dev_type>
1407c0da6274SZhi-Jun Robin Fu * uint8_t bus_bdg_secbus
1408c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcie_off
1409c0da6274SZhi-Jun Robin Fu * uint16_t <bus_aer_off>
1410c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcix_off
1411c0da6274SZhi-Jun Robin Fu * uint16_t bus_ecc_ver
1412c0da6274SZhi-Jun Robin Fu * pci_bus_range_t bus_bus_range
1413c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * bus_addr_ranges
1414c0da6274SZhi-Jun Robin Fu * int bus_addr_entries
1415c0da6274SZhi-Jun Robin Fu * pci_regspec_t * bus_assigned_addr
1416c0da6274SZhi-Jun Robin Fu * int bus_assigned_entries
1417c0da6274SZhi-Jun Robin Fu * pf_data_t * bus_pfd
1418fc256490SJason Beloro * pcie_domain_t * <bus_dom>
1419c0da6274SZhi-Jun Robin Fu * int bus_mps
1420c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base
1421c0da6274SZhi-Jun Robin Fu * void * bus_plat_private
1422c0da6274SZhi-Jun Robin Fu */
1423d4bc0535SKrishna Elango void
pcie_rc_init_bus(dev_info_t * dip)1424d4bc0535SKrishna Elango pcie_rc_init_bus(dev_info_t *dip)
1425d4bc0535SKrishna Elango {
1426d4bc0535SKrishna Elango pcie_bus_t *bus_p;
1427d4bc0535SKrishna Elango
1428d4bc0535SKrishna Elango bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
1429d4bc0535SKrishna Elango bus_p->bus_dip = dip;
1430d4bc0535SKrishna Elango bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
1431d4bc0535SKrishna Elango bus_p->bus_hdr_type = PCI_HEADER_ONE;
1432d4bc0535SKrishna Elango
1433d4bc0535SKrishna Elango /* Fake that there are AER logs */
1434d4bc0535SKrishna Elango bus_p->bus_aer_off = (uint16_t)-1;
1435d4bc0535SKrishna Elango
1436d4bc0535SKrishna Elango /* Needed only for handle lookup */
143779bed773SHans Rosenfeld atomic_or_uint(&bus_p->bus_fm_flags, PF_FM_READY);
1438d4bc0535SKrishna Elango
1439d4bc0535SKrishna Elango ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
1440fc256490SJason Beloro
1441fc256490SJason Beloro PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t);
1442d4bc0535SKrishna Elango }
1443d4bc0535SKrishna Elango
1444d4bc0535SKrishna Elango void
pcie_rc_fini_bus(dev_info_t * dip)1445d4bc0535SKrishna Elango pcie_rc_fini_bus(dev_info_t *dip)
1446d4bc0535SKrishna Elango {
1447c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
1448296f12dcSToomas Soome ndi_set_bus_private(dip, B_FALSE, 0, NULL);
1449fc256490SJason Beloro kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t));
1450d4bc0535SKrishna Elango kmem_free(bus_p, sizeof (pcie_bus_t));
1451d4bc0535SKrishna Elango }
1452d4bc0535SKrishna Elango
1453b3d69c05SRobert Mustacchi static int
pcie_width_to_int(pcie_link_width_t width)1454b3d69c05SRobert Mustacchi pcie_width_to_int(pcie_link_width_t width)
1455b3d69c05SRobert Mustacchi {
1456b3d69c05SRobert Mustacchi switch (width) {
1457b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X1:
1458b3d69c05SRobert Mustacchi return (1);
1459b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X2:
1460b3d69c05SRobert Mustacchi return (2);
1461b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X4:
1462b3d69c05SRobert Mustacchi return (4);
1463b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X8:
1464b3d69c05SRobert Mustacchi return (8);
1465b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X12:
1466b3d69c05SRobert Mustacchi return (12);
1467b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X16:
1468b3d69c05SRobert Mustacchi return (16);
1469b3d69c05SRobert Mustacchi case PCIE_LINK_WIDTH_X32:
1470b3d69c05SRobert Mustacchi return (32);
1471b3d69c05SRobert Mustacchi default:
1472b3d69c05SRobert Mustacchi return (0);
1473b3d69c05SRobert Mustacchi }
1474b3d69c05SRobert Mustacchi }
1475b3d69c05SRobert Mustacchi
1476b3d69c05SRobert Mustacchi /*
1477b3d69c05SRobert Mustacchi * Return the speed in Transfers / second. This is a signed quantity to match
1478b3d69c05SRobert Mustacchi * the ndi/ddi property interfaces.
1479b3d69c05SRobert Mustacchi */
1480b3d69c05SRobert Mustacchi static int64_t
pcie_speed_to_int(pcie_link_speed_t speed)1481b3d69c05SRobert Mustacchi pcie_speed_to_int(pcie_link_speed_t speed)
1482b3d69c05SRobert Mustacchi {
1483b3d69c05SRobert Mustacchi switch (speed) {
1484b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_2_5:
1485b3d69c05SRobert Mustacchi return (2500000000LL);
1486b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_5:
1487b3d69c05SRobert Mustacchi return (5000000000LL);
1488b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_8:
1489b3d69c05SRobert Mustacchi return (8000000000LL);
1490b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_16:
1491b3d69c05SRobert Mustacchi return (16000000000LL);
149289427192SRobert Mustacchi case PCIE_LINK_SPEED_32:
149389427192SRobert Mustacchi return (32000000000LL);
149489427192SRobert Mustacchi case PCIE_LINK_SPEED_64:
149589427192SRobert Mustacchi return (64000000000LL);
1496b3d69c05SRobert Mustacchi default:
1497b3d69c05SRobert Mustacchi return (0);
1498b3d69c05SRobert Mustacchi }
1499b3d69c05SRobert Mustacchi }
1500b3d69c05SRobert Mustacchi
1501b3d69c05SRobert Mustacchi /*
1502b3d69c05SRobert Mustacchi * Translate the recorded speed information into devinfo properties.
1503b3d69c05SRobert Mustacchi */
1504b3d69c05SRobert Mustacchi static void
pcie_speeds_to_devinfo(dev_info_t * dip,pcie_bus_t * bus_p)1505b3d69c05SRobert Mustacchi pcie_speeds_to_devinfo(dev_info_t *dip, pcie_bus_t *bus_p)
1506b3d69c05SRobert Mustacchi {
1507b3d69c05SRobert Mustacchi if (bus_p->bus_max_width != PCIE_LINK_WIDTH_UNKNOWN) {
1508b3d69c05SRobert Mustacchi (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1509b3d69c05SRobert Mustacchi "pcie-link-maximum-width",
1510b3d69c05SRobert Mustacchi pcie_width_to_int(bus_p->bus_max_width));
1511b3d69c05SRobert Mustacchi }
1512b3d69c05SRobert Mustacchi
1513b3d69c05SRobert Mustacchi if (bus_p->bus_cur_width != PCIE_LINK_WIDTH_UNKNOWN) {
1514b3d69c05SRobert Mustacchi (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1515b3d69c05SRobert Mustacchi "pcie-link-current-width",
1516b3d69c05SRobert Mustacchi pcie_width_to_int(bus_p->bus_cur_width));
1517b3d69c05SRobert Mustacchi }
1518b3d69c05SRobert Mustacchi
1519b3d69c05SRobert Mustacchi if (bus_p->bus_cur_speed != PCIE_LINK_SPEED_UNKNOWN) {
1520b3d69c05SRobert Mustacchi (void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1521b3d69c05SRobert Mustacchi "pcie-link-current-speed",
1522b3d69c05SRobert Mustacchi pcie_speed_to_int(bus_p->bus_cur_speed));
1523b3d69c05SRobert Mustacchi }
1524b3d69c05SRobert Mustacchi
1525b3d69c05SRobert Mustacchi if (bus_p->bus_max_speed != PCIE_LINK_SPEED_UNKNOWN) {
1526b3d69c05SRobert Mustacchi (void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1527b3d69c05SRobert Mustacchi "pcie-link-maximum-speed",
1528b3d69c05SRobert Mustacchi pcie_speed_to_int(bus_p->bus_max_speed));
1529b3d69c05SRobert Mustacchi }
1530b3d69c05SRobert Mustacchi
1531b3d69c05SRobert Mustacchi if (bus_p->bus_target_speed != PCIE_LINK_SPEED_UNKNOWN) {
1532b3d69c05SRobert Mustacchi (void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
1533b3d69c05SRobert Mustacchi "pcie-link-target-speed",
1534b3d69c05SRobert Mustacchi pcie_speed_to_int(bus_p->bus_target_speed));
1535b3d69c05SRobert Mustacchi }
1536b3d69c05SRobert Mustacchi
1537b3d69c05SRobert Mustacchi if ((bus_p->bus_speed_flags & PCIE_LINK_F_ADMIN_TARGET) != 0) {
1538b3d69c05SRobert Mustacchi (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1539b3d69c05SRobert Mustacchi "pcie-link-admin-target-speed");
1540b3d69c05SRobert Mustacchi }
1541b3d69c05SRobert Mustacchi
1542b3d69c05SRobert Mustacchi if (bus_p->bus_sup_speed != PCIE_LINK_SPEED_UNKNOWN) {
154389427192SRobert Mustacchi int64_t speeds[PCIE_NSPEEDS];
1544b3d69c05SRobert Mustacchi uint_t nspeeds = 0;
1545b3d69c05SRobert Mustacchi
1546b3d69c05SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_2_5) {
1547b3d69c05SRobert Mustacchi speeds[nspeeds++] =
1548b3d69c05SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_2_5);
1549b3d69c05SRobert Mustacchi }
1550b3d69c05SRobert Mustacchi
1551b3d69c05SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_5) {
1552b3d69c05SRobert Mustacchi speeds[nspeeds++] =
1553b3d69c05SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_5);
1554b3d69c05SRobert Mustacchi }
1555b3d69c05SRobert Mustacchi
1556b3d69c05SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_8) {
1557b3d69c05SRobert Mustacchi speeds[nspeeds++] =
1558b3d69c05SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_8);
1559b3d69c05SRobert Mustacchi }
1560b3d69c05SRobert Mustacchi
1561b3d69c05SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_16) {
1562b3d69c05SRobert Mustacchi speeds[nspeeds++] =
1563b3d69c05SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_16);
1564b3d69c05SRobert Mustacchi }
1565b3d69c05SRobert Mustacchi
156689427192SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_32) {
156789427192SRobert Mustacchi speeds[nspeeds++] =
156889427192SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_32);
156989427192SRobert Mustacchi }
157089427192SRobert Mustacchi
157189427192SRobert Mustacchi if (bus_p->bus_sup_speed & PCIE_LINK_SPEED_64) {
157289427192SRobert Mustacchi speeds[nspeeds++] =
157389427192SRobert Mustacchi pcie_speed_to_int(PCIE_LINK_SPEED_64);
157489427192SRobert Mustacchi }
157589427192SRobert Mustacchi
1576b3d69c05SRobert Mustacchi (void) ndi_prop_update_int64_array(DDI_DEV_T_NONE, dip,
1577b3d69c05SRobert Mustacchi "pcie-link-supported-speeds", speeds, nspeeds);
1578b3d69c05SRobert Mustacchi }
1579b3d69c05SRobert Mustacchi }
1580b3d69c05SRobert Mustacchi
1581d4bc0535SKrishna Elango /*
1582662dc8a5SRobert Mustacchi * We need to capture the supported, maximum, and current device speed and
1583662dc8a5SRobert Mustacchi * width. The way that this has been done has changed over time.
1584662dc8a5SRobert Mustacchi *
1585662dc8a5SRobert Mustacchi * Prior to PCIe Gen 3, there were only current and supported speed fields.
1586662dc8a5SRobert Mustacchi * These were found in the link status and link capabilities registers of the
1587662dc8a5SRobert Mustacchi * PCI express capability. With the change to PCIe Gen 3, the information in the
1588662dc8a5SRobert Mustacchi * link capabilities changed to the maximum value. The supported speeds vector
1589662dc8a5SRobert Mustacchi * was moved to the link capabilities 2 register.
1590662dc8a5SRobert Mustacchi *
1591662dc8a5SRobert Mustacchi * Now, a device may not implement some of these registers. To determine whether
1592662dc8a5SRobert Mustacchi * or not it's here, we have to do the following. First, we need to check the
1593662dc8a5SRobert Mustacchi * revision of the PCI express capability. The link capabilities 2 register did
1594b3d69c05SRobert Mustacchi * not exist prior to version 2 of this capability. If a modern device does not
1595b3d69c05SRobert Mustacchi * implement it, it is supposed to return zero for the register.
1596662dc8a5SRobert Mustacchi */
1597662dc8a5SRobert Mustacchi static void
pcie_capture_speeds(dev_info_t * dip)1598b3d69c05SRobert Mustacchi pcie_capture_speeds(dev_info_t *dip)
1599662dc8a5SRobert Mustacchi {
1600662dc8a5SRobert Mustacchi uint16_t vers, status;
1601b3d69c05SRobert Mustacchi uint32_t cap, cap2, ctl2;
1602b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
16037687d0d8SRobert Mustacchi dev_info_t *rcdip;
1604662dc8a5SRobert Mustacchi
1605662dc8a5SRobert Mustacchi if (!PCIE_IS_PCIE(bus_p))
1606662dc8a5SRobert Mustacchi return;
1607662dc8a5SRobert Mustacchi
16087687d0d8SRobert Mustacchi rcdip = pcie_get_rc_dip(dip);
16097687d0d8SRobert Mustacchi if (bus_p->bus_cfg_hdl == NULL) {
16107687d0d8SRobert Mustacchi vers = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16117687d0d8SRobert Mustacchi bus_p->bus_pcie_off + PCIE_PCIECAP);
16127687d0d8SRobert Mustacchi } else {
1613b3d69c05SRobert Mustacchi vers = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
16147687d0d8SRobert Mustacchi }
1615662dc8a5SRobert Mustacchi if (vers == PCI_EINVAL16)
1616662dc8a5SRobert Mustacchi return;
1617662dc8a5SRobert Mustacchi vers &= PCIE_PCIECAP_VER_MASK;
1618662dc8a5SRobert Mustacchi
1619662dc8a5SRobert Mustacchi /*
1620662dc8a5SRobert Mustacchi * Verify the capability's version.
1621662dc8a5SRobert Mustacchi */
1622662dc8a5SRobert Mustacchi switch (vers) {
1623662dc8a5SRobert Mustacchi case PCIE_PCIECAP_VER_1_0:
1624662dc8a5SRobert Mustacchi cap2 = 0;
1625b3d69c05SRobert Mustacchi ctl2 = 0;
1626662dc8a5SRobert Mustacchi break;
1627662dc8a5SRobert Mustacchi case PCIE_PCIECAP_VER_2_0:
16287687d0d8SRobert Mustacchi if (bus_p->bus_cfg_hdl == NULL) {
16297687d0d8SRobert Mustacchi cap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
16307687d0d8SRobert Mustacchi bus_p->bus_pcie_off + PCIE_LINKCAP2);
16317687d0d8SRobert Mustacchi ctl2 = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16327687d0d8SRobert Mustacchi bus_p->bus_pcie_off + PCIE_LINKCTL2);
16337687d0d8SRobert Mustacchi } else {
1634b3d69c05SRobert Mustacchi cap2 = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP2);
16357687d0d8SRobert Mustacchi ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
16367687d0d8SRobert Mustacchi }
1637662dc8a5SRobert Mustacchi if (cap2 == PCI_EINVAL32)
1638662dc8a5SRobert Mustacchi cap2 = 0;
1639b3d69c05SRobert Mustacchi if (ctl2 == PCI_EINVAL16)
1640b3d69c05SRobert Mustacchi ctl2 = 0;
1641662dc8a5SRobert Mustacchi break;
1642662dc8a5SRobert Mustacchi default:
1643662dc8a5SRobert Mustacchi /* Don't try and handle an unknown version */
1644662dc8a5SRobert Mustacchi return;
1645662dc8a5SRobert Mustacchi }
1646662dc8a5SRobert Mustacchi
16477687d0d8SRobert Mustacchi if (bus_p->bus_cfg_hdl == NULL) {
16487687d0d8SRobert Mustacchi status = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
16497687d0d8SRobert Mustacchi bus_p->bus_pcie_off + PCIE_LINKSTS);
16507687d0d8SRobert Mustacchi cap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
16517687d0d8SRobert Mustacchi bus_p->bus_pcie_off + PCIE_LINKCAP);
16527687d0d8SRobert Mustacchi } else {
1653b3d69c05SRobert Mustacchi status = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
1654b3d69c05SRobert Mustacchi cap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
16557687d0d8SRobert Mustacchi }
1656662dc8a5SRobert Mustacchi if (status == PCI_EINVAL16 || cap == PCI_EINVAL32)
1657662dc8a5SRobert Mustacchi return;
1658662dc8a5SRobert Mustacchi
1659b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_speed_mutex);
1660b3d69c05SRobert Mustacchi
1661662dc8a5SRobert Mustacchi switch (status & PCIE_LINKSTS_SPEED_MASK) {
1662662dc8a5SRobert Mustacchi case PCIE_LINKSTS_SPEED_2_5:
1663662dc8a5SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_2_5;
1664662dc8a5SRobert Mustacchi break;
1665662dc8a5SRobert Mustacchi case PCIE_LINKSTS_SPEED_5:
1666662dc8a5SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_5;
1667662dc8a5SRobert Mustacchi break;
1668662dc8a5SRobert Mustacchi case PCIE_LINKSTS_SPEED_8:
1669662dc8a5SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_8;
1670662dc8a5SRobert Mustacchi break;
167133756ae2SRobert Mustacchi case PCIE_LINKSTS_SPEED_16:
167233756ae2SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_16;
167333756ae2SRobert Mustacchi break;
167489427192SRobert Mustacchi case PCIE_LINKSTS_SPEED_32:
167589427192SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_32;
167689427192SRobert Mustacchi break;
167789427192SRobert Mustacchi case PCIE_LINKSTS_SPEED_64:
167889427192SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_64;
167989427192SRobert Mustacchi break;
1680662dc8a5SRobert Mustacchi default:
1681662dc8a5SRobert Mustacchi bus_p->bus_cur_speed = PCIE_LINK_SPEED_UNKNOWN;
1682662dc8a5SRobert Mustacchi break;
1683662dc8a5SRobert Mustacchi }
1684662dc8a5SRobert Mustacchi
1685662dc8a5SRobert Mustacchi switch (status & PCIE_LINKSTS_NEG_WIDTH_MASK) {
1686662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X1:
1687662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X1;
1688662dc8a5SRobert Mustacchi break;
1689662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X2:
1690662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X2;
1691662dc8a5SRobert Mustacchi break;
1692662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X4:
1693662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X4;
1694662dc8a5SRobert Mustacchi break;
1695662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X8:
1696662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X8;
1697662dc8a5SRobert Mustacchi break;
1698662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X12:
1699662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X12;
1700662dc8a5SRobert Mustacchi break;
1701662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X16:
1702662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X16;
1703662dc8a5SRobert Mustacchi break;
1704662dc8a5SRobert Mustacchi case PCIE_LINKSTS_NEG_WIDTH_X32:
1705662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_X32;
1706662dc8a5SRobert Mustacchi break;
1707662dc8a5SRobert Mustacchi default:
1708662dc8a5SRobert Mustacchi bus_p->bus_cur_width = PCIE_LINK_WIDTH_UNKNOWN;
1709662dc8a5SRobert Mustacchi break;
1710662dc8a5SRobert Mustacchi }
1711662dc8a5SRobert Mustacchi
1712662dc8a5SRobert Mustacchi switch (cap & PCIE_LINKCAP_MAX_WIDTH_MASK) {
1713662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X1:
1714662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X1;
1715662dc8a5SRobert Mustacchi break;
1716662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X2:
1717662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X2;
1718662dc8a5SRobert Mustacchi break;
1719662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X4:
1720662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X4;
1721662dc8a5SRobert Mustacchi break;
1722662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X8:
1723662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X8;
1724662dc8a5SRobert Mustacchi break;
1725662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X12:
1726662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X12;
1727662dc8a5SRobert Mustacchi break;
1728662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X16:
1729662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X16;
1730662dc8a5SRobert Mustacchi break;
1731662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_WIDTH_X32:
1732662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_X32;
1733662dc8a5SRobert Mustacchi break;
1734662dc8a5SRobert Mustacchi default:
1735662dc8a5SRobert Mustacchi bus_p->bus_max_width = PCIE_LINK_WIDTH_UNKNOWN;
1736662dc8a5SRobert Mustacchi break;
1737662dc8a5SRobert Mustacchi }
1738662dc8a5SRobert Mustacchi
1739662dc8a5SRobert Mustacchi /*
1740662dc8a5SRobert Mustacchi * If we have the Link Capabilities 2, then we can get the supported
1741662dc8a5SRobert Mustacchi * speeds from it and treat the bits in Link Capabilities 1 as the
1742662dc8a5SRobert Mustacchi * maximum. If we don't, then we need to follow the Implementation Note
1743662dc8a5SRobert Mustacchi * in the standard under Link Capabilities 2. Effectively, this means
1744662dc8a5SRobert Mustacchi * that if the value of 10b is set in Link Capabilities register, that
1745662dc8a5SRobert Mustacchi * it supports both 2.5 and 5 GT/s speeds.
1746662dc8a5SRobert Mustacchi */
1747662dc8a5SRobert Mustacchi if (cap2 != 0) {
1748662dc8a5SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_2_5)
1749662dc8a5SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_2_5;
1750662dc8a5SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_5)
1751662dc8a5SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_5;
1752662dc8a5SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_8)
1753662dc8a5SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_8;
175433756ae2SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_16)
175533756ae2SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_16;
175689427192SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_32)
175789427192SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_32;
175889427192SRobert Mustacchi if (cap2 & PCIE_LINKCAP2_SPEED_64)
175989427192SRobert Mustacchi bus_p->bus_sup_speed |= PCIE_LINK_SPEED_64;
1760662dc8a5SRobert Mustacchi
1761662dc8a5SRobert Mustacchi switch (cap & PCIE_LINKCAP_MAX_SPEED_MASK) {
1762662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_2_5:
1763662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_2_5;
1764662dc8a5SRobert Mustacchi break;
1765662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_5:
1766662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_5;
1767662dc8a5SRobert Mustacchi break;
1768662dc8a5SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_8:
1769662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_8;
1770662dc8a5SRobert Mustacchi break;
177133756ae2SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_16:
177233756ae2SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_16;
177333756ae2SRobert Mustacchi break;
177489427192SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_32:
177589427192SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_32;
177689427192SRobert Mustacchi break;
177789427192SRobert Mustacchi case PCIE_LINKCAP_MAX_SPEED_64:
177889427192SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_64;
177989427192SRobert Mustacchi break;
1780662dc8a5SRobert Mustacchi default:
1781662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_UNKNOWN;
1782662dc8a5SRobert Mustacchi break;
1783662dc8a5SRobert Mustacchi }
1784662dc8a5SRobert Mustacchi } else {
1785662dc8a5SRobert Mustacchi if (cap & PCIE_LINKCAP_MAX_SPEED_5) {
1786662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_5;
1787662dc8a5SRobert Mustacchi bus_p->bus_sup_speed = PCIE_LINK_SPEED_2_5 |
1788662dc8a5SRobert Mustacchi PCIE_LINK_SPEED_5;
1789b3d69c05SRobert Mustacchi } else if (cap & PCIE_LINKCAP_MAX_SPEED_2_5) {
1790662dc8a5SRobert Mustacchi bus_p->bus_max_speed = PCIE_LINK_SPEED_2_5;
1791662dc8a5SRobert Mustacchi bus_p->bus_sup_speed = PCIE_LINK_SPEED_2_5;
1792662dc8a5SRobert Mustacchi }
1793662dc8a5SRobert Mustacchi }
1794b3d69c05SRobert Mustacchi
1795b3d69c05SRobert Mustacchi switch (ctl2 & PCIE_LINKCTL2_TARGET_SPEED_MASK) {
1796b3d69c05SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_2_5:
1797b3d69c05SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_2_5;
1798b3d69c05SRobert Mustacchi break;
1799b3d69c05SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_5:
1800b3d69c05SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_5;
1801b3d69c05SRobert Mustacchi break;
1802b3d69c05SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_8:
1803b3d69c05SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_8;
1804b3d69c05SRobert Mustacchi break;
1805b3d69c05SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_16:
1806b3d69c05SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_16;
1807b3d69c05SRobert Mustacchi break;
180889427192SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_32:
180989427192SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_32;
181089427192SRobert Mustacchi break;
181189427192SRobert Mustacchi case PCIE_LINKCTL2_TARGET_SPEED_64:
181289427192SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_64;
181389427192SRobert Mustacchi break;
1814b3d69c05SRobert Mustacchi default:
1815b3d69c05SRobert Mustacchi bus_p->bus_target_speed = PCIE_LINK_SPEED_UNKNOWN;
1816b3d69c05SRobert Mustacchi break;
1817b3d69c05SRobert Mustacchi }
1818b3d69c05SRobert Mustacchi
1819b3d69c05SRobert Mustacchi pcie_speeds_to_devinfo(dip, bus_p);
1820b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_speed_mutex);
1821662dc8a5SRobert Mustacchi }
1822662dc8a5SRobert Mustacchi
1823662dc8a5SRobert Mustacchi /*
1824c0da6274SZhi-Jun Robin Fu * partially init pcie_bus_t for device (dip,bdf) for accessing pci
1825c0da6274SZhi-Jun Robin Fu * config space
1826d4bc0535SKrishna Elango *
1827c0da6274SZhi-Jun Robin Fu * This routine is invoked during boot, either after creating a devinfo node
1828c0da6274SZhi-Jun Robin Fu * (x86 case) or during px driver attach (sparc case); it is also invoked
1829c0da6274SZhi-Jun Robin Fu * in hotplug context after a devinfo node is created.
1830c0da6274SZhi-Jun Robin Fu *
1831c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
1832c0da6274SZhi-Jun Robin Fu * is set:
1833c0da6274SZhi-Jun Robin Fu *
1834c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_dip>
1835c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_rp_dip>
1836c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl
1837c0da6274SZhi-Jun Robin Fu * uint_t bus_fm_flags
1838c0da6274SZhi-Jun Robin Fu * pcie_req_id_t <bus_bdf>
1839c0da6274SZhi-Jun Robin Fu * pcie_req_id_t <bus_rp_bdf>
1840c0da6274SZhi-Jun Robin Fu * uint32_t <bus_dev_ven_id>
1841c0da6274SZhi-Jun Robin Fu * uint8_t <bus_rev_id>
1842c0da6274SZhi-Jun Robin Fu * uint8_t <bus_hdr_type>
1843c0da6274SZhi-Jun Robin Fu * uint16_t <bus_dev_type>
1844c0da6274SZhi-Jun Robin Fu * uint8_t <bus_bdg_secbus
1845c0da6274SZhi-Jun Robin Fu * uint16_t <bus_pcie_off>
1846c0da6274SZhi-Jun Robin Fu * uint16_t <bus_aer_off>
1847c0da6274SZhi-Jun Robin Fu * uint16_t <bus_pcix_off>
1848c0da6274SZhi-Jun Robin Fu * uint16_t <bus_ecc_ver>
1849c0da6274SZhi-Jun Robin Fu * pci_bus_range_t bus_bus_range
1850c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * bus_addr_ranges
1851c0da6274SZhi-Jun Robin Fu * int bus_addr_entries
1852c0da6274SZhi-Jun Robin Fu * pci_regspec_t * bus_assigned_addr
1853c0da6274SZhi-Jun Robin Fu * int bus_assigned_entries
1854c0da6274SZhi-Jun Robin Fu * pf_data_t * bus_pfd
1855fc256490SJason Beloro * pcie_domain_t * bus_dom
1856c0da6274SZhi-Jun Robin Fu * int bus_mps
1857c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base
1858c0da6274SZhi-Jun Robin Fu * void * bus_plat_private
1859c0da6274SZhi-Jun Robin Fu *
1860c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
1861c0da6274SZhi-Jun Robin Fu * is set:
1862c0da6274SZhi-Jun Robin Fu *
1863c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_dip
1864c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_rp_dip
1865c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl
1866c0da6274SZhi-Jun Robin Fu * uint_t bus_fm_flags
1867c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_bdf
1868c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_rp_bdf
1869c0da6274SZhi-Jun Robin Fu * uint32_t bus_dev_ven_id
1870c0da6274SZhi-Jun Robin Fu * uint8_t bus_rev_id
1871c0da6274SZhi-Jun Robin Fu * uint8_t bus_hdr_type
1872c0da6274SZhi-Jun Robin Fu * uint16_t bus_dev_type
1873c0da6274SZhi-Jun Robin Fu * uint8_t <bus_bdg_secbus>
1874c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcie_off
1875c0da6274SZhi-Jun Robin Fu * uint16_t bus_aer_off
1876c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcix_off
1877c0da6274SZhi-Jun Robin Fu * uint16_t bus_ecc_ver
1878c0da6274SZhi-Jun Robin Fu * pci_bus_range_t <bus_bus_range>
1879c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * <bus_addr_ranges>
1880c0da6274SZhi-Jun Robin Fu * int <bus_addr_entries>
1881c0da6274SZhi-Jun Robin Fu * pci_regspec_t * <bus_assigned_addr>
1882c0da6274SZhi-Jun Robin Fu * int <bus_assigned_entries>
1883c0da6274SZhi-Jun Robin Fu * pf_data_t * <bus_pfd>
1884fc256490SJason Beloro * pcie_domain_t * bus_dom
1885c0da6274SZhi-Jun Robin Fu * int bus_mps
1886c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base
1887c0da6274SZhi-Jun Robin Fu * void * <bus_plat_private>
1888d4bc0535SKrishna Elango */
1889c0da6274SZhi-Jun Robin Fu
1890d4bc0535SKrishna Elango pcie_bus_t *
pcie_init_bus(dev_info_t * dip,pcie_req_id_t bdf,uint8_t flags)1891c0da6274SZhi-Jun Robin Fu pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
1892d4bc0535SKrishna Elango {
1893c0da6274SZhi-Jun Robin Fu uint16_t status, base, baseptr, num_cap;
1894c0da6274SZhi-Jun Robin Fu uint32_t capid;
1895d4bc0535SKrishna Elango int range_size;
1896b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = NULL;
1897c0da6274SZhi-Jun Robin Fu dev_info_t *rcdip;
1898d4bc0535SKrishna Elango dev_info_t *pdip;
1899d4bc0535SKrishna Elango const char *errstr = NULL;
1900d4bc0535SKrishna Elango
1901c0da6274SZhi-Jun Robin Fu if (!(flags & PCIE_BUS_INITIAL))
1902c0da6274SZhi-Jun Robin Fu goto initial_done;
1903d4bc0535SKrishna Elango
1904d4bc0535SKrishna Elango bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
1905d4bc0535SKrishna Elango
1906c0da6274SZhi-Jun Robin Fu bus_p->bus_dip = dip;
1907c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf = bdf;
1908d4bc0535SKrishna Elango
1909c0da6274SZhi-Jun Robin Fu rcdip = pcie_get_rc_dip(dip);
1910c0da6274SZhi-Jun Robin Fu ASSERT(rcdip != NULL);
191126947304SEvan Yan
1912c0da6274SZhi-Jun Robin Fu /* Save the Vendor ID, Device ID and revision ID */
1913c0da6274SZhi-Jun Robin Fu bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
1914c0da6274SZhi-Jun Robin Fu bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
1915d4bc0535SKrishna Elango /* Save the Header Type */
1916c0da6274SZhi-Jun Robin Fu bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
1917d4bc0535SKrishna Elango bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
1918d4bc0535SKrishna Elango
1919c0da6274SZhi-Jun Robin Fu /*
1920c0da6274SZhi-Jun Robin Fu * Figure out the device type and all the relavant capability offsets
1921c0da6274SZhi-Jun Robin Fu */
1922c0da6274SZhi-Jun Robin Fu /* set default value */
1923c0da6274SZhi-Jun Robin Fu bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
1924d4bc0535SKrishna Elango
1925c0da6274SZhi-Jun Robin Fu status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
1926c0da6274SZhi-Jun Robin Fu if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
1927c0da6274SZhi-Jun Robin Fu goto caps_done; /* capability not supported */
1928c0da6274SZhi-Jun Robin Fu
1929c0da6274SZhi-Jun Robin Fu /* Relevant conventional capabilities first */
1930c0da6274SZhi-Jun Robin Fu
1931c0da6274SZhi-Jun Robin Fu /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
1932c0da6274SZhi-Jun Robin Fu num_cap = 2;
1933c0da6274SZhi-Jun Robin Fu
1934c0da6274SZhi-Jun Robin Fu switch (bus_p->bus_hdr_type) {
1935c0da6274SZhi-Jun Robin Fu case PCI_HEADER_ZERO:
1936c0da6274SZhi-Jun Robin Fu baseptr = PCI_CONF_CAP_PTR;
1937c0da6274SZhi-Jun Robin Fu break;
1938c0da6274SZhi-Jun Robin Fu case PCI_HEADER_PPB:
1939c0da6274SZhi-Jun Robin Fu baseptr = PCI_BCNF_CAP_PTR;
1940c0da6274SZhi-Jun Robin Fu break;
1941c0da6274SZhi-Jun Robin Fu case PCI_HEADER_CARDBUS:
1942c0da6274SZhi-Jun Robin Fu baseptr = PCI_CBUS_CAP_PTR;
1943c0da6274SZhi-Jun Robin Fu break;
1944c0da6274SZhi-Jun Robin Fu default:
1945c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
1946c0da6274SZhi-Jun Robin Fu __func__, bus_p->bus_hdr_type);
1947c0da6274SZhi-Jun Robin Fu goto caps_done;
1948c0da6274SZhi-Jun Robin Fu }
1949c0da6274SZhi-Jun Robin Fu
1950c0da6274SZhi-Jun Robin Fu base = baseptr;
1951c0da6274SZhi-Jun Robin Fu for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
1952c0da6274SZhi-Jun Robin Fu base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
1953c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get8(rcdip, bdf, base);
19545b2c4190SRobert Mustacchi uint16_t pcap;
19555b2c4190SRobert Mustacchi
1956c0da6274SZhi-Jun Robin Fu switch (capid) {
1957c0da6274SZhi-Jun Robin Fu case PCI_CAP_ID_PCI_E:
1958c0da6274SZhi-Jun Robin Fu bus_p->bus_pcie_off = base;
19595b2c4190SRobert Mustacchi pcap = pci_cfgacc_get16(rcdip, bdf, base +
19605b2c4190SRobert Mustacchi PCIE_PCIECAP);
19615b2c4190SRobert Mustacchi bus_p->bus_dev_type = pcap & PCIE_PCIECAP_DEV_TYPE_MASK;
19625b2c4190SRobert Mustacchi bus_p->bus_pcie_vers = pcap & PCIE_PCIECAP_VER_MASK;
196326947304SEvan Yan
196426947304SEvan Yan /* Check and save PCIe hotplug capability information */
196526947304SEvan Yan if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
1966c0da6274SZhi-Jun Robin Fu (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
196726947304SEvan Yan & PCIE_PCIECAP_SLOT_IMPL) &&
1968c0da6274SZhi-Jun Robin Fu (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
196926947304SEvan Yan & PCIE_SLOTCAP_HP_CAPABLE))
197026947304SEvan Yan bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
1971d4bc0535SKrishna Elango
1972c0da6274SZhi-Jun Robin Fu num_cap--;
1973c0da6274SZhi-Jun Robin Fu break;
1974c0da6274SZhi-Jun Robin Fu case PCI_CAP_ID_PCIX:
1975c0da6274SZhi-Jun Robin Fu bus_p->bus_pcix_off = base;
1976d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p))
1977c0da6274SZhi-Jun Robin Fu bus_p->bus_ecc_ver =
1978c0da6274SZhi-Jun Robin Fu pci_cfgacc_get16(rcdip, bdf, base +
1979d4bc0535SKrishna Elango PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
1980d4bc0535SKrishna Elango else
1981c0da6274SZhi-Jun Robin Fu bus_p->bus_ecc_ver =
1982c0da6274SZhi-Jun Robin Fu pci_cfgacc_get16(rcdip, bdf, base +
1983d4bc0535SKrishna Elango PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
1984c0da6274SZhi-Jun Robin Fu num_cap--;
1985c0da6274SZhi-Jun Robin Fu break;
1986c0da6274SZhi-Jun Robin Fu default:
1987c0da6274SZhi-Jun Robin Fu break;
1988c0da6274SZhi-Jun Robin Fu }
1989d4bc0535SKrishna Elango }
1990d4bc0535SKrishna Elango
199126947304SEvan Yan /* Check and save PCI hotplug (SHPC) capability information */
1992c0da6274SZhi-Jun Robin Fu if (PCIE_IS_BDG(bus_p)) {
1993c0da6274SZhi-Jun Robin Fu base = baseptr;
1994c0da6274SZhi-Jun Robin Fu for (base = pci_cfgacc_get8(rcdip, bdf, base);
1995c0da6274SZhi-Jun Robin Fu base; base = pci_cfgacc_get8(rcdip, bdf,
1996c0da6274SZhi-Jun Robin Fu base + PCI_CAP_NEXT_PTR)) {
1997c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get8(rcdip, bdf, base);
1998c0da6274SZhi-Jun Robin Fu if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
1999c0da6274SZhi-Jun Robin Fu bus_p->bus_pci_hp_off = base;
200026947304SEvan Yan bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
2001c0da6274SZhi-Jun Robin Fu break;
2002c0da6274SZhi-Jun Robin Fu }
2003c0da6274SZhi-Jun Robin Fu }
2004d4bc0535SKrishna Elango }
2005d4bc0535SKrishna Elango
2006c0da6274SZhi-Jun Robin Fu /* Then, relevant extended capabilities */
2007d4bc0535SKrishna Elango
2008c0da6274SZhi-Jun Robin Fu if (!PCIE_IS_PCIE(bus_p))
2009c0da6274SZhi-Jun Robin Fu goto caps_done;
2010c0da6274SZhi-Jun Robin Fu
2011c0da6274SZhi-Jun Robin Fu /* Extended caps: PCIE_EXT_CAP_ID_AER */
2012c0da6274SZhi-Jun Robin Fu for (base = PCIE_EXT_CAP; base; base = (capid >>
2013c0da6274SZhi-Jun Robin Fu PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
2014c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get32(rcdip, bdf, base);
2015c0da6274SZhi-Jun Robin Fu if (capid == PCI_CAP_EINVAL32)
2016c0da6274SZhi-Jun Robin Fu break;
20175b2c4190SRobert Mustacchi switch ((capid >> PCIE_EXT_CAP_ID_SHIFT) &
20185b2c4190SRobert Mustacchi PCIE_EXT_CAP_ID_MASK) {
20195b2c4190SRobert Mustacchi case PCIE_EXT_CAP_ID_AER:
2020c0da6274SZhi-Jun Robin Fu bus_p->bus_aer_off = base;
2021c0da6274SZhi-Jun Robin Fu break;
20225b2c4190SRobert Mustacchi case PCIE_EXT_CAP_ID_DEV3:
20235b2c4190SRobert Mustacchi bus_p->bus_dev3_off = base;
20245b2c4190SRobert Mustacchi break;
2025c0da6274SZhi-Jun Robin Fu }
2026d4bc0535SKrishna Elango }
2027d4bc0535SKrishna Elango
2028c0da6274SZhi-Jun Robin Fu caps_done:
2029d4bc0535SKrishna Elango /* save RP dip and RP bdf */
2030d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) {
2031c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_dip = dip;
2032d4bc0535SKrishna Elango bus_p->bus_rp_bdf = bus_p->bus_bdf;
20335b2c4190SRobert Mustacchi
20345b2c4190SRobert Mustacchi bus_p->bus_fab = PCIE_ZALLOC(pcie_fabric_data_t);
2035d4bc0535SKrishna Elango } else {
2036c0da6274SZhi-Jun Robin Fu for (pdip = ddi_get_parent(dip); pdip;
2037d4bc0535SKrishna Elango pdip = ddi_get_parent(pdip)) {
2038d4bc0535SKrishna Elango pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
2039d4bc0535SKrishna Elango
2040d4bc0535SKrishna Elango /*
2041c0da6274SZhi-Jun Robin Fu * If RP dip and RP bdf in parent's bus_t have
2042c0da6274SZhi-Jun Robin Fu * been initialized, simply use these instead of
2043c0da6274SZhi-Jun Robin Fu * continuing up to the RC.
2044c0da6274SZhi-Jun Robin Fu */
2045c0da6274SZhi-Jun Robin Fu if (parent_bus_p->bus_rp_dip != NULL) {
2046c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
2047c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
2048c0da6274SZhi-Jun Robin Fu break;
2049c0da6274SZhi-Jun Robin Fu }
2050c0da6274SZhi-Jun Robin Fu
2051c0da6274SZhi-Jun Robin Fu /*
2052d4bc0535SKrishna Elango * When debugging be aware that some NVIDIA x86
2053d4bc0535SKrishna Elango * architectures have 2 nodes for each RP, One at Bus
2054d4bc0535SKrishna Elango * 0x0 and one at Bus 0x80. The requester is from Bus
2055d4bc0535SKrishna Elango * 0x80
2056d4bc0535SKrishna Elango */
2057d4bc0535SKrishna Elango if (PCIE_IS_ROOT(parent_bus_p)) {
2058d4bc0535SKrishna Elango bus_p->bus_rp_dip = pdip;
2059d4bc0535SKrishna Elango bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
2060d4bc0535SKrishna Elango break;
2061d4bc0535SKrishna Elango }
2062d4bc0535SKrishna Elango }
2063d4bc0535SKrishna Elango }
2064d4bc0535SKrishna Elango
2065c0da6274SZhi-Jun Robin Fu bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
206679bed773SHans Rosenfeld (void) atomic_swap_uint(&bus_p->bus_fm_flags, 0);
2067d4bc0535SKrishna Elango
2068c0da6274SZhi-Jun Robin Fu ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
2069c0da6274SZhi-Jun Robin Fu
2070c0da6274SZhi-Jun Robin Fu if (PCIE_IS_HOTPLUG_CAPABLE(dip))
2071c0da6274SZhi-Jun Robin Fu (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
2072c0da6274SZhi-Jun Robin Fu "hotplug-capable");
2073c0da6274SZhi-Jun Robin Fu
2074c0da6274SZhi-Jun Robin Fu initial_done:
2075c0da6274SZhi-Jun Robin Fu if (!(flags & PCIE_BUS_FINAL))
2076c0da6274SZhi-Jun Robin Fu goto final_done;
2077c0da6274SZhi-Jun Robin Fu
2078c0da6274SZhi-Jun Robin Fu /* already initialized? */
2079c0da6274SZhi-Jun Robin Fu bus_p = PCIE_DIP2BUS(dip);
2080c0da6274SZhi-Jun Robin Fu
2081c0da6274SZhi-Jun Robin Fu /* Save the Range information if device is a switch/bridge */
2082c0da6274SZhi-Jun Robin Fu if (PCIE_IS_BDG(bus_p)) {
2083c0da6274SZhi-Jun Robin Fu /* get "bus_range" property */
2084c0da6274SZhi-Jun Robin Fu range_size = sizeof (pci_bus_range_t);
2085c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2086c0da6274SZhi-Jun Robin Fu "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
2087c0da6274SZhi-Jun Robin Fu != DDI_PROP_SUCCESS) {
2088c0da6274SZhi-Jun Robin Fu errstr = "Cannot find \"bus-range\" property";
2089c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN,
2090c0da6274SZhi-Jun Robin Fu "PCIE init err info failed BDF 0x%x:%s\n",
2091c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf, errstr);
2092c0da6274SZhi-Jun Robin Fu }
2093c0da6274SZhi-Jun Robin Fu
2094c0da6274SZhi-Jun Robin Fu /* get secondary bus number */
2095c0da6274SZhi-Jun Robin Fu rcdip = pcie_get_rc_dip(dip);
2096c0da6274SZhi-Jun Robin Fu ASSERT(rcdip != NULL);
2097c0da6274SZhi-Jun Robin Fu
2098c0da6274SZhi-Jun Robin Fu bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
2099c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf, PCI_BCNF_SECBUS);
2100c0da6274SZhi-Jun Robin Fu
2101c0da6274SZhi-Jun Robin Fu /* Get "ranges" property */
2102c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2103c0da6274SZhi-Jun Robin Fu "ranges", (caddr_t)&bus_p->bus_addr_ranges,
2104c0da6274SZhi-Jun Robin Fu &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
2105c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries = 0;
2106c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
2107c0da6274SZhi-Jun Robin Fu }
2108c0da6274SZhi-Jun Robin Fu
2109c0da6274SZhi-Jun Robin Fu /* save "assigned-addresses" property array, ignore failues */
2110c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2111c0da6274SZhi-Jun Robin Fu "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
2112c0da6274SZhi-Jun Robin Fu &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
2113c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
2114c0da6274SZhi-Jun Robin Fu else
2115c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries = 0;
2116c0da6274SZhi-Jun Robin Fu
2117c0da6274SZhi-Jun Robin Fu pcie_init_pfd(dip);
2118c0da6274SZhi-Jun Robin Fu
2119c0da6274SZhi-Jun Robin Fu pcie_init_plat(dip);
2120c0da6274SZhi-Jun Robin Fu
21217687d0d8SRobert Mustacchi pcie_capture_speeds(dip);
21227687d0d8SRobert Mustacchi
2123c0da6274SZhi-Jun Robin Fu final_done:
2124d4bc0535SKrishna Elango
2125d4bc0535SKrishna Elango PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
2126c0da6274SZhi-Jun Robin Fu ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
2127d4bc0535SKrishna Elango bus_p->bus_bdg_secbus);
2128d4bc0535SKrishna Elango #ifdef DEBUG
2129b3d69c05SRobert Mustacchi if (bus_p != NULL) {
2130d4bc0535SKrishna Elango pcie_print_bus(bus_p);
2131b3d69c05SRobert Mustacchi }
2132d4bc0535SKrishna Elango #endif
2133d4bc0535SKrishna Elango
2134d4bc0535SKrishna Elango return (bus_p);
2135c0da6274SZhi-Jun Robin Fu }
2136c0da6274SZhi-Jun Robin Fu
2137c0da6274SZhi-Jun Robin Fu /*
2138c0da6274SZhi-Jun Robin Fu * Invoked before destroying devinfo node, mostly during hotplug
2139c0da6274SZhi-Jun Robin Fu * operation to free pcie_bus_t data structure
2140c0da6274SZhi-Jun Robin Fu */
2141c0da6274SZhi-Jun Robin Fu /* ARGSUSED */
2142c0da6274SZhi-Jun Robin Fu void
pcie_fini_bus(dev_info_t * dip,uint8_t flags)2143c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dev_info_t *dip, uint8_t flags)
2144c0da6274SZhi-Jun Robin Fu {
2145c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2146c0da6274SZhi-Jun Robin Fu ASSERT(bus_p);
2147c0da6274SZhi-Jun Robin Fu
2148c0da6274SZhi-Jun Robin Fu if (flags & PCIE_BUS_INITIAL) {
2149c0da6274SZhi-Jun Robin Fu pcie_fini_plat(dip);
2150c0da6274SZhi-Jun Robin Fu pcie_fini_pfd(dip);
2151c0da6274SZhi-Jun Robin Fu
21525b2c4190SRobert Mustacchi if (PCIE_IS_RP(bus_p)) {
21535b2c4190SRobert Mustacchi kmem_free(bus_p->bus_fab, sizeof (pcie_fabric_data_t));
21545b2c4190SRobert Mustacchi bus_p->bus_fab = NULL;
21555b2c4190SRobert Mustacchi }
21565b2c4190SRobert Mustacchi
2157c0da6274SZhi-Jun Robin Fu kmem_free(bus_p->bus_assigned_addr,
2158c0da6274SZhi-Jun Robin Fu (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
2159c0da6274SZhi-Jun Robin Fu kmem_free(bus_p->bus_addr_ranges,
2160c0da6274SZhi-Jun Robin Fu (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
2161c0da6274SZhi-Jun Robin Fu /* zero out the fields that have been destroyed */
2162c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_addr = NULL;
2163c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_ranges = NULL;
2164c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries = 0;
2165c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries = 0;
2166c0da6274SZhi-Jun Robin Fu }
2167c0da6274SZhi-Jun Robin Fu
2168c0da6274SZhi-Jun Robin Fu if (flags & PCIE_BUS_FINAL) {
2169c0da6274SZhi-Jun Robin Fu if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
2170c0da6274SZhi-Jun Robin Fu (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
2171c0da6274SZhi-Jun Robin Fu "hotplug-capable");
2172c0da6274SZhi-Jun Robin Fu }
2173c0da6274SZhi-Jun Robin Fu
2174296f12dcSToomas Soome ndi_set_bus_private(dip, B_TRUE, 0, NULL);
2175d4bc0535SKrishna Elango kmem_free(bus_p, sizeof (pcie_bus_t));
2176c0da6274SZhi-Jun Robin Fu }
2177d4bc0535SKrishna Elango }
2178d4bc0535SKrishna Elango
2179d4bc0535SKrishna Elango int
pcie_postattach_child(dev_info_t * cdip)2180d4bc0535SKrishna Elango pcie_postattach_child(dev_info_t *cdip)
2181d4bc0535SKrishna Elango {
2182d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
2183d4bc0535SKrishna Elango
2184d4bc0535SKrishna Elango if (!bus_p)
2185d4bc0535SKrishna Elango return (DDI_FAILURE);
2186d4bc0535SKrishna Elango
2187d4bc0535SKrishna Elango return (pcie_enable_ce(cdip));
2188d4bc0535SKrishna Elango }
2189d4bc0535SKrishna Elango
2190d4bc0535SKrishna Elango /*
2191d4bc0535SKrishna Elango * PCI-Express child device de-initialization.
2192d4bc0535SKrishna Elango * This function disables generic pci-express interrupts and error
2193d4bc0535SKrishna Elango * handling.
2194d4bc0535SKrishna Elango */
2195d4bc0535SKrishna Elango void
pcie_uninitchild(dev_info_t * cdip)2196d4bc0535SKrishna Elango pcie_uninitchild(dev_info_t *cdip)
2197d4bc0535SKrishna Elango {
2198d4bc0535SKrishna Elango pcie_disable_errors(cdip);
2199c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(cdip);
2200fc256490SJason Beloro pcie_fini_dom(cdip);
2201c0da6274SZhi-Jun Robin Fu }
2202c0da6274SZhi-Jun Robin Fu
2203c0da6274SZhi-Jun Robin Fu /*
2204c0da6274SZhi-Jun Robin Fu * find the root complex dip
2205c0da6274SZhi-Jun Robin Fu */
2206c0da6274SZhi-Jun Robin Fu dev_info_t *
pcie_get_rc_dip(dev_info_t * dip)2207c0da6274SZhi-Jun Robin Fu pcie_get_rc_dip(dev_info_t *dip)
2208c0da6274SZhi-Jun Robin Fu {
2209c0da6274SZhi-Jun Robin Fu dev_info_t *rcdip;
2210c0da6274SZhi-Jun Robin Fu pcie_bus_t *rc_bus_p;
2211c0da6274SZhi-Jun Robin Fu
2212c0da6274SZhi-Jun Robin Fu for (rcdip = ddi_get_parent(dip); rcdip;
2213c0da6274SZhi-Jun Robin Fu rcdip = ddi_get_parent(rcdip)) {
2214c0da6274SZhi-Jun Robin Fu rc_bus_p = PCIE_DIP2BUS(rcdip);
2215c0da6274SZhi-Jun Robin Fu if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
2216c0da6274SZhi-Jun Robin Fu break;
2217c0da6274SZhi-Jun Robin Fu }
2218c0da6274SZhi-Jun Robin Fu
2219c0da6274SZhi-Jun Robin Fu return (rcdip);
2220c0da6274SZhi-Jun Robin Fu }
2221c0da6274SZhi-Jun Robin Fu
22229b3f4fe3SHans Rosenfeld boolean_t
pcie_is_pci_device(dev_info_t * dip)2223c0da6274SZhi-Jun Robin Fu pcie_is_pci_device(dev_info_t *dip)
2224c0da6274SZhi-Jun Robin Fu {
2225c0da6274SZhi-Jun Robin Fu dev_info_t *pdip;
2226c0da6274SZhi-Jun Robin Fu char *device_type;
2227c0da6274SZhi-Jun Robin Fu
2228c0da6274SZhi-Jun Robin Fu pdip = ddi_get_parent(dip);
22299b3f4fe3SHans Rosenfeld if (pdip == NULL)
22309b3f4fe3SHans Rosenfeld return (B_FALSE);
2231c0da6274SZhi-Jun Robin Fu
2232c0da6274SZhi-Jun Robin Fu if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
2233c0da6274SZhi-Jun Robin Fu "device_type", &device_type) != DDI_PROP_SUCCESS)
2234c0da6274SZhi-Jun Robin Fu return (B_FALSE);
2235c0da6274SZhi-Jun Robin Fu
2236c0da6274SZhi-Jun Robin Fu if (strcmp(device_type, "pciex") != 0 &&
2237c0da6274SZhi-Jun Robin Fu strcmp(device_type, "pci") != 0) {
2238c0da6274SZhi-Jun Robin Fu ddi_prop_free(device_type);
2239c0da6274SZhi-Jun Robin Fu return (B_FALSE);
2240c0da6274SZhi-Jun Robin Fu }
2241c0da6274SZhi-Jun Robin Fu
2242c0da6274SZhi-Jun Robin Fu ddi_prop_free(device_type);
2243c0da6274SZhi-Jun Robin Fu return (B_TRUE);
2244c0da6274SZhi-Jun Robin Fu }
2245c0da6274SZhi-Jun Robin Fu
2246c0da6274SZhi-Jun Robin Fu typedef struct {
2247c0da6274SZhi-Jun Robin Fu boolean_t init;
2248c0da6274SZhi-Jun Robin Fu uint8_t flags;
2249c0da6274SZhi-Jun Robin Fu } pcie_bus_arg_t;
2250c0da6274SZhi-Jun Robin Fu
2251c0da6274SZhi-Jun Robin Fu /*ARGSUSED*/
2252c0da6274SZhi-Jun Robin Fu static int
pcie_fab_do_init_fini(dev_info_t * dip,void * arg)2253c0da6274SZhi-Jun Robin Fu pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
2254c0da6274SZhi-Jun Robin Fu {
2255c0da6274SZhi-Jun Robin Fu pcie_req_id_t bdf;
2256c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg;
2257c0da6274SZhi-Jun Robin Fu
2258c0da6274SZhi-Jun Robin Fu if (!pcie_is_pci_device(dip))
2259c0da6274SZhi-Jun Robin Fu goto out;
2260c0da6274SZhi-Jun Robin Fu
2261c0da6274SZhi-Jun Robin Fu if (bus_arg->init) {
2262c0da6274SZhi-Jun Robin Fu if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
2263c0da6274SZhi-Jun Robin Fu goto out;
2264c0da6274SZhi-Jun Robin Fu
2265c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(dip, bdf, bus_arg->flags);
2266c0da6274SZhi-Jun Robin Fu } else {
2267c0da6274SZhi-Jun Robin Fu (void) pcie_fini_bus(dip, bus_arg->flags);
2268c0da6274SZhi-Jun Robin Fu }
2269c0da6274SZhi-Jun Robin Fu
2270c0da6274SZhi-Jun Robin Fu return (DDI_WALK_CONTINUE);
2271c0da6274SZhi-Jun Robin Fu
2272c0da6274SZhi-Jun Robin Fu out:
2273c0da6274SZhi-Jun Robin Fu return (DDI_WALK_PRUNECHILD);
2274d4bc0535SKrishna Elango }
2275d4bc0535SKrishna Elango
2276d4bc0535SKrishna Elango void
pcie_fab_init_bus(dev_info_t * rcdip,uint8_t flags)2277c0da6274SZhi-Jun Robin Fu pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
2278d4bc0535SKrishna Elango {
2279c0da6274SZhi-Jun Robin Fu dev_info_t *dip = ddi_get_child(rcdip);
2280c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t arg;
2281d4bc0535SKrishna Elango
2282c0da6274SZhi-Jun Robin Fu arg.init = B_TRUE;
2283c0da6274SZhi-Jun Robin Fu arg.flags = flags;
2284d4bc0535SKrishna Elango
22853fe80ca4SDan Cross ndi_devi_enter(rcdip);
2286c0da6274SZhi-Jun Robin Fu ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
22873fe80ca4SDan Cross ndi_devi_exit(rcdip);
2288c0da6274SZhi-Jun Robin Fu }
228926947304SEvan Yan
2290c0da6274SZhi-Jun Robin Fu void
pcie_fab_fini_bus(dev_info_t * rcdip,uint8_t flags)2291c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
2292c0da6274SZhi-Jun Robin Fu {
2293c0da6274SZhi-Jun Robin Fu dev_info_t *dip = ddi_get_child(rcdip);
2294c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t arg;
229526947304SEvan Yan
2296c0da6274SZhi-Jun Robin Fu arg.init = B_FALSE;
2297c0da6274SZhi-Jun Robin Fu arg.flags = flags;
2298d4bc0535SKrishna Elango
22993fe80ca4SDan Cross ndi_devi_enter(rcdip);
2300c0da6274SZhi-Jun Robin Fu ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
23013fe80ca4SDan Cross ndi_devi_exit(rcdip);
2302d4bc0535SKrishna Elango }
2303d4bc0535SKrishna Elango
2304d4bc0535SKrishna Elango void
pcie_enable_errors(dev_info_t * dip)2305d4bc0535SKrishna Elango pcie_enable_errors(dev_info_t *dip)
2306d4bc0535SKrishna Elango {
2307d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
2308d4bc0535SKrishna Elango uint16_t reg16, tmp16;
2309d4bc0535SKrishna Elango uint32_t reg32, tmp32;
2310d4bc0535SKrishna Elango
2311d4bc0535SKrishna Elango ASSERT(bus_p);
2312d4bc0535SKrishna Elango
2313d4bc0535SKrishna Elango /*
2314d4bc0535SKrishna Elango * Clear any pending errors
2315d4bc0535SKrishna Elango */
2316d4bc0535SKrishna Elango pcie_clear_errors(dip);
2317d4bc0535SKrishna Elango
2318d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p))
2319d4bc0535SKrishna Elango return;
2320d4bc0535SKrishna Elango
2321d4bc0535SKrishna Elango /*
2322d4bc0535SKrishna Elango * Enable Baseline Error Handling but leave CE reporting off (poweron
2323d4bc0535SKrishna Elango * default).
2324d4bc0535SKrishna Elango */
2325d4bc0535SKrishna Elango if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
2326d4bc0535SKrishna Elango PCI_CAP_EINVAL16) {
2327*28e5e903SRobert Mustacchi tmp16 = (reg16 & pcie_devctl_default_mask) |
2328*28e5e903SRobert Mustacchi (pcie_devctl_default & ~pcie_devctl_default_mask) |
2329*28e5e903SRobert Mustacchi (pcie_base_err_default & ~PCIE_DEVCTL_CE_REPORTING_EN);
2330d4bc0535SKrishna Elango
2331d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
2332d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
2333d4bc0535SKrishna Elango }
2334d4bc0535SKrishna Elango
2335d4bc0535SKrishna Elango /* Enable Root Port Baseline Error Receiving */
2336d4bc0535SKrishna Elango if (PCIE_IS_ROOT(bus_p) &&
2337d4bc0535SKrishna Elango (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
2338d4bc0535SKrishna Elango PCI_CAP_EINVAL16) {
2339d4bc0535SKrishna Elango
2340d4bc0535SKrishna Elango tmp16 = pcie_serr_disable_flag ?
2341d4bc0535SKrishna Elango (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
2342d4bc0535SKrishna Elango pcie_root_ctrl_default;
2343d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
2344d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
2345d4bc0535SKrishna Elango reg16);
2346d4bc0535SKrishna Elango }
2347d4bc0535SKrishna Elango
2348d4bc0535SKrishna Elango /*
2349d4bc0535SKrishna Elango * Enable PCI-Express Advanced Error Handling if Exists
2350d4bc0535SKrishna Elango */
2351d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p))
2352d4bc0535SKrishna Elango return;
2353d4bc0535SKrishna Elango
2354d4bc0535SKrishna Elango /* Set Uncorrectable Severity */
2355d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
2356d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2357d4bc0535SKrishna Elango tmp32 = pcie_aer_uce_severity;
2358d4bc0535SKrishna Elango
2359d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
2360d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
2361d4bc0535SKrishna Elango reg32);
2362d4bc0535SKrishna Elango }
2363d4bc0535SKrishna Elango
2364d4bc0535SKrishna Elango /* Enable Uncorrectable errors */
2365d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
2366d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2367d4bc0535SKrishna Elango tmp32 = pcie_aer_uce_mask;
2368d4bc0535SKrishna Elango
2369d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
2370d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
2371d4bc0535SKrishna Elango reg32);
2372d4bc0535SKrishna Elango }
2373d4bc0535SKrishna Elango
2374d4bc0535SKrishna Elango /* Enable ECRC generation and checking */
2375d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
2376d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2377d4bc0535SKrishna Elango tmp32 = reg32 | pcie_ecrc_value;
2378d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
2379d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
2380d4bc0535SKrishna Elango }
2381d4bc0535SKrishna Elango
2382d4bc0535SKrishna Elango /* Enable Secondary Uncorrectable errors if this is a bridge */
2383d4bc0535SKrishna Elango if (!PCIE_IS_PCIE_BDG(bus_p))
2384d4bc0535SKrishna Elango goto root;
2385d4bc0535SKrishna Elango
2386d4bc0535SKrishna Elango /* Set Uncorrectable Severity */
2387d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
2388d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2389d4bc0535SKrishna Elango tmp32 = pcie_aer_suce_severity;
2390d4bc0535SKrishna Elango
2391d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
2392d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
2393d4bc0535SKrishna Elango reg32);
2394d4bc0535SKrishna Elango }
2395d4bc0535SKrishna Elango
2396d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
2397d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2398d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
2399d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
2400d4bc0535SKrishna Elango PCIE_AER_SUCE_MASK, reg32);
2401d4bc0535SKrishna Elango }
2402d4bc0535SKrishna Elango
2403d4bc0535SKrishna Elango root:
2404d4bc0535SKrishna Elango /*
2405d4bc0535SKrishna Elango * Enable Root Control this is a Root device
2406d4bc0535SKrishna Elango */
2407d4bc0535SKrishna Elango if (!PCIE_IS_ROOT(bus_p))
2408d4bc0535SKrishna Elango return;
2409d4bc0535SKrishna Elango
2410d4bc0535SKrishna Elango if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
2411d4bc0535SKrishna Elango PCI_CAP_EINVAL16) {
2412d4bc0535SKrishna Elango PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
2413d4bc0535SKrishna Elango pcie_root_error_cmd_default);
2414d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
2415d4bc0535SKrishna Elango PCIE_AER_RE_CMD, reg16);
2416d4bc0535SKrishna Elango }
2417d4bc0535SKrishna Elango }
2418d4bc0535SKrishna Elango
2419d4bc0535SKrishna Elango /*
2420d4bc0535SKrishna Elango * This function is used for enabling CE reporting and setting the AER CE mask.
2421d4bc0535SKrishna Elango * When called from outside the pcie module it should always be preceded by
2422d4bc0535SKrishna Elango * a call to pcie_enable_errors.
2423d4bc0535SKrishna Elango */
2424d4bc0535SKrishna Elango int
pcie_enable_ce(dev_info_t * dip)2425d4bc0535SKrishna Elango pcie_enable_ce(dev_info_t *dip)
2426d4bc0535SKrishna Elango {
2427d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
2428d4bc0535SKrishna Elango uint16_t device_sts, device_ctl;
2429d4bc0535SKrishna Elango uint32_t tmp_pcie_aer_ce_mask;
2430d4bc0535SKrishna Elango
2431d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p))
2432d4bc0535SKrishna Elango return (DDI_SUCCESS);
2433d4bc0535SKrishna Elango
2434d4bc0535SKrishna Elango /*
2435d4bc0535SKrishna Elango * The "pcie_ce_mask" property is used to control both the CE reporting
2436d4bc0535SKrishna Elango * enable field in the device control register and the AER CE mask. We
2437d4bc0535SKrishna Elango * leave CE reporting disabled if pcie_ce_mask is set to -1.
2438d4bc0535SKrishna Elango */
2439d4bc0535SKrishna Elango
2440d4bc0535SKrishna Elango tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2441d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
2442d4bc0535SKrishna Elango
2443d4bc0535SKrishna Elango if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
2444d4bc0535SKrishna Elango /*
2445d4bc0535SKrishna Elango * Nothing to do since CE reporting has already been disabled.
2446d4bc0535SKrishna Elango */
2447d4bc0535SKrishna Elango return (DDI_SUCCESS);
2448d4bc0535SKrishna Elango }
2449d4bc0535SKrishna Elango
2450d4bc0535SKrishna Elango if (PCIE_HAS_AER(bus_p)) {
2451d4bc0535SKrishna Elango /* Enable AER CE */
2452d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
2453d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
2454d4bc0535SKrishna Elango 0);
2455d4bc0535SKrishna Elango
2456d4bc0535SKrishna Elango /* Clear any pending AER CE errors */
2457d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
2458d4bc0535SKrishna Elango }
2459d4bc0535SKrishna Elango
2460d4bc0535SKrishna Elango /* clear any pending CE errors */
2461d4bc0535SKrishna Elango if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
2462d4bc0535SKrishna Elango PCI_CAP_EINVAL16)
2463d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
2464d4bc0535SKrishna Elango device_sts & (~PCIE_DEVSTS_CE_DETECTED));
2465d4bc0535SKrishna Elango
2466d4bc0535SKrishna Elango /* Enable CE reporting */
2467d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
2468d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
2469d4bc0535SKrishna Elango (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
2470d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
2471d4bc0535SKrishna Elango
2472d4bc0535SKrishna Elango return (DDI_SUCCESS);
2473d4bc0535SKrishna Elango }
2474d4bc0535SKrishna Elango
2475d4bc0535SKrishna Elango /* ARGSUSED */
2476d4bc0535SKrishna Elango void
pcie_disable_errors(dev_info_t * dip)2477d4bc0535SKrishna Elango pcie_disable_errors(dev_info_t *dip)
2478d4bc0535SKrishna Elango {
2479d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
2480d4bc0535SKrishna Elango uint16_t device_ctl;
2481d4bc0535SKrishna Elango uint32_t aer_reg;
2482d4bc0535SKrishna Elango
2483d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p))
2484d4bc0535SKrishna Elango return;
2485d4bc0535SKrishna Elango
2486d4bc0535SKrishna Elango /*
2487d4bc0535SKrishna Elango * Disable PCI-Express Baseline Error Handling
2488d4bc0535SKrishna Elango */
2489d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
2490d4bc0535SKrishna Elango device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
2491d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
2492d4bc0535SKrishna Elango
2493d4bc0535SKrishna Elango /*
2494d4bc0535SKrishna Elango * Disable PCI-Express Advanced Error Handling if Exists
2495d4bc0535SKrishna Elango */
2496d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p))
2497d4bc0535SKrishna Elango goto root;
2498d4bc0535SKrishna Elango
2499d4bc0535SKrishna Elango /* Disable Uncorrectable errors */
2500d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
2501d4bc0535SKrishna Elango
2502d4bc0535SKrishna Elango /* Disable Correctable errors */
2503d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
2504d4bc0535SKrishna Elango
2505d4bc0535SKrishna Elango /* Disable ECRC generation and checking */
2506d4bc0535SKrishna Elango if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
2507d4bc0535SKrishna Elango PCI_CAP_EINVAL32) {
2508d4bc0535SKrishna Elango aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
2509d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_CHECK_ENA);
2510d4bc0535SKrishna Elango
2511d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
2512d4bc0535SKrishna Elango }
2513d4bc0535SKrishna Elango /*
2514d4bc0535SKrishna Elango * Disable Secondary Uncorrectable errors if this is a bridge
2515d4bc0535SKrishna Elango */
2516d4bc0535SKrishna Elango if (!PCIE_IS_PCIE_BDG(bus_p))
2517d4bc0535SKrishna Elango goto root;
2518d4bc0535SKrishna Elango
2519d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
2520d4bc0535SKrishna Elango
2521d4bc0535SKrishna Elango root:
2522d4bc0535SKrishna Elango /*
2523d4bc0535SKrishna Elango * disable Root Control this is a Root device
2524d4bc0535SKrishna Elango */
2525d4bc0535SKrishna Elango if (!PCIE_IS_ROOT(bus_p))
2526d4bc0535SKrishna Elango return;
2527d4bc0535SKrishna Elango
2528d4bc0535SKrishna Elango if (!pcie_serr_disable_flag) {
2529d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
2530d4bc0535SKrishna Elango device_ctl &= ~PCIE_ROOT_SYS_ERR;
2531d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
2532d4bc0535SKrishna Elango }
2533d4bc0535SKrishna Elango
2534d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p))
2535d4bc0535SKrishna Elango return;
2536d4bc0535SKrishna Elango
2537d4bc0535SKrishna Elango if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
2538d4bc0535SKrishna Elango PCI_CAP_EINVAL16) {
2539d4bc0535SKrishna Elango device_ctl &= ~pcie_root_error_cmd_default;
2540d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
2541d4bc0535SKrishna Elango }
2542d4bc0535SKrishna Elango }
2543d4bc0535SKrishna Elango
2544d4bc0535SKrishna Elango /*
2545d4bc0535SKrishna Elango * Extract bdf from "reg" property.
2546d4bc0535SKrishna Elango */
2547d4bc0535SKrishna Elango int
pcie_get_bdf_from_dip(dev_info_t * dip,pcie_req_id_t * bdf)2548d4bc0535SKrishna Elango pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
2549d4bc0535SKrishna Elango {
2550d4bc0535SKrishna Elango pci_regspec_t *regspec;
2551d4bc0535SKrishna Elango int reglen;
2552d4bc0535SKrishna Elango
2553d4bc0535SKrishna Elango if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2554d4bc0535SKrishna Elango "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS)
2555d4bc0535SKrishna Elango return (DDI_FAILURE);
2556d4bc0535SKrishna Elango
2557d4bc0535SKrishna Elango if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
2558d4bc0535SKrishna Elango ddi_prop_free(regspec);
2559d4bc0535SKrishna Elango return (DDI_FAILURE);
2560d4bc0535SKrishna Elango }
2561d4bc0535SKrishna Elango
2562d4bc0535SKrishna Elango /* Get phys_hi from first element. All have same bdf. */
2563d4bc0535SKrishna Elango *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
2564d4bc0535SKrishna Elango
2565d4bc0535SKrishna Elango ddi_prop_free(regspec);
2566d4bc0535SKrishna Elango return (DDI_SUCCESS);
2567d4bc0535SKrishna Elango }
2568d4bc0535SKrishna Elango
2569d4bc0535SKrishna Elango dev_info_t *
pcie_get_my_childs_dip(dev_info_t * dip,dev_info_t * rdip)2570d4bc0535SKrishna Elango pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
2571d4bc0535SKrishna Elango {
2572d4bc0535SKrishna Elango dev_info_t *cdip = rdip;
2573d4bc0535SKrishna Elango
2574d4bc0535SKrishna Elango for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
2575d4bc0535SKrishna Elango ;
2576d4bc0535SKrishna Elango
2577d4bc0535SKrishna Elango return (cdip);
2578d4bc0535SKrishna Elango }
2579d4bc0535SKrishna Elango
2580d4bc0535SKrishna Elango uint32_t
pcie_get_bdf_for_dma_xfer(dev_info_t * dip,dev_info_t * rdip)2581d4bc0535SKrishna Elango pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
2582d4bc0535SKrishna Elango {
2583d4bc0535SKrishna Elango dev_info_t *cdip;
2584d4bc0535SKrishna Elango
2585d4bc0535SKrishna Elango /*
2586d4bc0535SKrishna Elango * As part of the probing, the PCI fcode interpreter may setup a DMA
2587d4bc0535SKrishna Elango * request if a given card has a fcode on it using dip and rdip of the
258826947304SEvan Yan * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
2589d4bc0535SKrishna Elango * case, return a invalid value for the bdf since we cannot get to the
2590d4bc0535SKrishna Elango * bdf value of the actual device which will be initiating this DMA.
2591d4bc0535SKrishna Elango */
2592d4bc0535SKrishna Elango if (rdip == dip)
2593d4bc0535SKrishna Elango return (PCIE_INVALID_BDF);
2594d4bc0535SKrishna Elango
2595d4bc0535SKrishna Elango cdip = pcie_get_my_childs_dip(dip, rdip);
2596d4bc0535SKrishna Elango
2597d4bc0535SKrishna Elango /*
2598d4bc0535SKrishna Elango * For a given rdip, return the bdf value of dip's (px or pcieb)
2599d4bc0535SKrishna Elango * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
2600d4bc0535SKrishna Elango *
2601d4bc0535SKrishna Elango * XXX - For now, return a invalid bdf value for all PCI and PCI-X
2602d4bc0535SKrishna Elango * devices since this needs more work.
2603d4bc0535SKrishna Elango */
2604d4bc0535SKrishna Elango return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
2605d4bc0535SKrishna Elango PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
2606d4bc0535SKrishna Elango }
2607d4bc0535SKrishna Elango
2608d4bc0535SKrishna Elango uint32_t
pcie_get_aer_uce_mask()2609826c0d1dSRobert Mustacchi pcie_get_aer_uce_mask()
2610826c0d1dSRobert Mustacchi {
2611d4bc0535SKrishna Elango return (pcie_aer_uce_mask);
2612d4bc0535SKrishna Elango }
2613d4bc0535SKrishna Elango uint32_t
pcie_get_aer_ce_mask()2614826c0d1dSRobert Mustacchi pcie_get_aer_ce_mask()
2615826c0d1dSRobert Mustacchi {
2616d4bc0535SKrishna Elango return (pcie_aer_ce_mask);
2617d4bc0535SKrishna Elango }
2618d4bc0535SKrishna Elango uint32_t
pcie_get_aer_suce_mask()2619826c0d1dSRobert Mustacchi pcie_get_aer_suce_mask()
2620826c0d1dSRobert Mustacchi {
2621d4bc0535SKrishna Elango return (pcie_aer_suce_mask);
2622d4bc0535SKrishna Elango }
2623d4bc0535SKrishna Elango uint32_t
pcie_get_serr_mask()2624826c0d1dSRobert Mustacchi pcie_get_serr_mask()
2625826c0d1dSRobert Mustacchi {
2626d4bc0535SKrishna Elango return (pcie_serr_disable_flag);
2627d4bc0535SKrishna Elango }
2628d4bc0535SKrishna Elango
2629d4bc0535SKrishna Elango void
pcie_set_aer_uce_mask(uint32_t mask)2630826c0d1dSRobert Mustacchi pcie_set_aer_uce_mask(uint32_t mask)
2631826c0d1dSRobert Mustacchi {
2632d4bc0535SKrishna Elango pcie_aer_uce_mask = mask;
2633d4bc0535SKrishna Elango if (mask & PCIE_AER_UCE_UR)
2634d4bc0535SKrishna Elango pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
2635d4bc0535SKrishna Elango else
2636d4bc0535SKrishna Elango pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
2637d4bc0535SKrishna Elango
2638d4bc0535SKrishna Elango if (mask & PCIE_AER_UCE_ECRC)
2639d4bc0535SKrishna Elango pcie_ecrc_value = 0;
2640d4bc0535SKrishna Elango }
2641d4bc0535SKrishna Elango
2642d4bc0535SKrishna Elango void
pcie_set_aer_ce_mask(uint32_t mask)2643826c0d1dSRobert Mustacchi pcie_set_aer_ce_mask(uint32_t mask)
2644826c0d1dSRobert Mustacchi {
2645d4bc0535SKrishna Elango pcie_aer_ce_mask = mask;
2646d4bc0535SKrishna Elango }
2647d4bc0535SKrishna Elango void
pcie_set_aer_suce_mask(uint32_t mask)2648826c0d1dSRobert Mustacchi pcie_set_aer_suce_mask(uint32_t mask)
2649826c0d1dSRobert Mustacchi {
2650d4bc0535SKrishna Elango pcie_aer_suce_mask = mask;
2651d4bc0535SKrishna Elango }
2652d4bc0535SKrishna Elango void
pcie_set_serr_mask(uint32_t mask)2653826c0d1dSRobert Mustacchi pcie_set_serr_mask(uint32_t mask)
2654826c0d1dSRobert Mustacchi {
2655d4bc0535SKrishna Elango pcie_serr_disable_flag = mask;
2656d4bc0535SKrishna Elango }
2657d4bc0535SKrishna Elango
2658d4bc0535SKrishna Elango /*
2659d4bc0535SKrishna Elango * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling
2660d4bc0535SKrishna Elango * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge.
2661d4bc0535SKrishna Elango */
2662d4bc0535SKrishna Elango boolean_t
pcie_is_child(dev_info_t * dip,dev_info_t * rdip)2663d4bc0535SKrishna Elango pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
2664d4bc0535SKrishna Elango {
2665d4bc0535SKrishna Elango dev_info_t *cdip = ddi_get_child(dip);
2666d4bc0535SKrishna Elango for (; cdip; cdip = ddi_get_next_sibling(cdip))
2667d4bc0535SKrishna Elango if (cdip == rdip)
2668d4bc0535SKrishna Elango break;
2669d4bc0535SKrishna Elango return (cdip != NULL);
2670d4bc0535SKrishna Elango }
2671d4bc0535SKrishna Elango
2672d4bc0535SKrishna Elango boolean_t
pcie_is_link_disabled(dev_info_t * dip)2673d4bc0535SKrishna Elango pcie_is_link_disabled(dev_info_t *dip)
2674d4bc0535SKrishna Elango {
2675d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
2676d4bc0535SKrishna Elango
2677d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) {
2678d4bc0535SKrishna Elango if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
2679d4bc0535SKrishna Elango PCIE_LINKCTL_LINK_DISABLE)
2680d4bc0535SKrishna Elango return (B_TRUE);
2681d4bc0535SKrishna Elango }
2682d4bc0535SKrishna Elango return (B_FALSE);
2683d4bc0535SKrishna Elango }
2684d4bc0535SKrishna Elango
2685d4bc0535SKrishna Elango /*
2686d4bc0535SKrishna Elango * Determines if there are any root ports attached to a root complex.
2687d4bc0535SKrishna Elango *
2688d4bc0535SKrishna Elango * dip - dip of root complex
2689d4bc0535SKrishna Elango *
2690d4bc0535SKrishna Elango * Returns - DDI_SUCCESS if there is at least one root port otherwise
2691d4bc0535SKrishna Elango * DDI_FAILURE.
2692d4bc0535SKrishna Elango */
2693d4bc0535SKrishna Elango int
pcie_root_port(dev_info_t * dip)2694d4bc0535SKrishna Elango pcie_root_port(dev_info_t *dip)
2695d4bc0535SKrishna Elango {
2696d4bc0535SKrishna Elango int port_type;
2697d4bc0535SKrishna Elango uint16_t cap_ptr;
2698d4bc0535SKrishna Elango ddi_acc_handle_t config_handle;
2699d4bc0535SKrishna Elango dev_info_t *cdip = ddi_get_child(dip);
2700d4bc0535SKrishna Elango
2701d4bc0535SKrishna Elango /*
2702d4bc0535SKrishna Elango * Determine if any of the children of the passed in dip
2703d4bc0535SKrishna Elango * are root ports.
2704d4bc0535SKrishna Elango */
2705d4bc0535SKrishna Elango for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
2706d4bc0535SKrishna Elango
2707d4bc0535SKrishna Elango if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
2708d4bc0535SKrishna Elango continue;
2709d4bc0535SKrishna Elango
2710d4bc0535SKrishna Elango if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
2711d4bc0535SKrishna Elango &cap_ptr)) == DDI_FAILURE) {
2712d4bc0535SKrishna Elango pci_config_teardown(&config_handle);
2713d4bc0535SKrishna Elango continue;
2714d4bc0535SKrishna Elango }
2715d4bc0535SKrishna Elango
2716296f12dcSToomas Soome port_type = PCI_CAP_GET16(config_handle, 0, cap_ptr,
2717d4bc0535SKrishna Elango PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
2718d4bc0535SKrishna Elango
2719d4bc0535SKrishna Elango pci_config_teardown(&config_handle);
2720d4bc0535SKrishna Elango
2721d4bc0535SKrishna Elango if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
2722d4bc0535SKrishna Elango return (DDI_SUCCESS);
2723d4bc0535SKrishna Elango }
2724d4bc0535SKrishna Elango
2725d4bc0535SKrishna Elango /* No root ports were found */
2726d4bc0535SKrishna Elango
2727d4bc0535SKrishna Elango return (DDI_FAILURE);
2728d4bc0535SKrishna Elango }
2729d4bc0535SKrishna Elango
2730d4bc0535SKrishna Elango /*
2731d4bc0535SKrishna Elango * Function that determines if a device a PCIe device.
2732d4bc0535SKrishna Elango *
2733d4bc0535SKrishna Elango * dip - dip of device.
2734d4bc0535SKrishna Elango *
2735d4bc0535SKrishna Elango * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
2736d4bc0535SKrishna Elango */
2737d4bc0535SKrishna Elango int
pcie_dev(dev_info_t * dip)2738d4bc0535SKrishna Elango pcie_dev(dev_info_t *dip)
2739d4bc0535SKrishna Elango {
2740d4bc0535SKrishna Elango /* get parent device's device_type property */
2741d4bc0535SKrishna Elango char *device_type;
2742d4bc0535SKrishna Elango int rc = DDI_FAILURE;
2743d4bc0535SKrishna Elango dev_info_t *pdip = ddi_get_parent(dip);
2744d4bc0535SKrishna Elango
2745d4bc0535SKrishna Elango if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
2746d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "device_type", &device_type)
2747d4bc0535SKrishna Elango != DDI_PROP_SUCCESS) {
2748d4bc0535SKrishna Elango return (DDI_FAILURE);
2749d4bc0535SKrishna Elango }
2750d4bc0535SKrishna Elango
2751d4bc0535SKrishna Elango if (strcmp(device_type, "pciex") == 0)
2752d4bc0535SKrishna Elango rc = DDI_SUCCESS;
2753d4bc0535SKrishna Elango else
2754d4bc0535SKrishna Elango rc = DDI_FAILURE;
2755d4bc0535SKrishna Elango
2756d4bc0535SKrishna Elango ddi_prop_free(device_type);
2757d4bc0535SKrishna Elango return (rc);
2758d4bc0535SKrishna Elango }
2759d4bc0535SKrishna Elango
2760d4bc0535SKrishna Elango void
pcie_set_rber_fatal(dev_info_t * dip,boolean_t val)2761d4bc0535SKrishna Elango pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
2762d4bc0535SKrishna Elango {
2763d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2764d4bc0535SKrishna Elango bus_p->bus_pfd->pe_rber_fatal = val;
2765d4bc0535SKrishna Elango }
2766d4bc0535SKrishna Elango
2767d4bc0535SKrishna Elango /*
2768d4bc0535SKrishna Elango * Return parent Root Port's pe_rber_fatal value.
2769d4bc0535SKrishna Elango */
2770d4bc0535SKrishna Elango boolean_t
pcie_get_rber_fatal(dev_info_t * dip)2771d4bc0535SKrishna Elango pcie_get_rber_fatal(dev_info_t *dip)
2772d4bc0535SKrishna Elango {
2773d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2774d4bc0535SKrishna Elango pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
2775d4bc0535SKrishna Elango return (rp_bus_p->bus_pfd->pe_rber_fatal);
2776d4bc0535SKrishna Elango }
2777d4bc0535SKrishna Elango
277826947304SEvan Yan int
pcie_ari_supported(dev_info_t * dip)277926947304SEvan Yan pcie_ari_supported(dev_info_t *dip)
278026947304SEvan Yan {
278126947304SEvan Yan uint32_t devcap2;
278226947304SEvan Yan uint16_t pciecap;
278326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
278426947304SEvan Yan uint8_t dev_type;
278526947304SEvan Yan
278626947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
278726947304SEvan Yan
278826947304SEvan Yan if (bus_p == NULL)
278926947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED);
279026947304SEvan Yan
279126947304SEvan Yan dev_type = bus_p->bus_dev_type;
279226947304SEvan Yan
279326947304SEvan Yan if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
279426947304SEvan Yan (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
279526947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED);
279626947304SEvan Yan
279726947304SEvan Yan if (pcie_disable_ari) {
279826947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
279926947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED);
280026947304SEvan Yan }
280126947304SEvan Yan
280226947304SEvan Yan pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
280326947304SEvan Yan
280426947304SEvan Yan if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
280526947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
280626947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED);
280726947304SEvan Yan }
280826947304SEvan Yan
280926947304SEvan Yan devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
281026947304SEvan Yan
281126947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
281226947304SEvan Yan dip, devcap2);
281326947304SEvan Yan
281426947304SEvan Yan if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
281526947304SEvan Yan PCIE_DBG("pcie_ari_supported: "
281626947304SEvan Yan "dip=%p: ARI Forwarding is supported\n", dip);
281726947304SEvan Yan return (PCIE_ARI_FORW_SUPPORTED);
281826947304SEvan Yan }
281926947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED);
282026947304SEvan Yan }
282126947304SEvan Yan
282226947304SEvan Yan int
pcie_ari_enable(dev_info_t * dip)282326947304SEvan Yan pcie_ari_enable(dev_info_t *dip)
282426947304SEvan Yan {
282526947304SEvan Yan uint16_t devctl2;
282626947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
282726947304SEvan Yan
282826947304SEvan Yan PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
282926947304SEvan Yan
283026947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
283126947304SEvan Yan return (DDI_FAILURE);
283226947304SEvan Yan
283326947304SEvan Yan devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
283426947304SEvan Yan devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
283526947304SEvan Yan PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
283626947304SEvan Yan
283726947304SEvan Yan PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
283826947304SEvan Yan dip, devctl2);
283926947304SEvan Yan
284026947304SEvan Yan return (DDI_SUCCESS);
284126947304SEvan Yan }
284226947304SEvan Yan
284326947304SEvan Yan int
pcie_ari_disable(dev_info_t * dip)284426947304SEvan Yan pcie_ari_disable(dev_info_t *dip)
284526947304SEvan Yan {
284626947304SEvan Yan uint16_t devctl2;
284726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
284826947304SEvan Yan
284926947304SEvan Yan PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
285026947304SEvan Yan
285126947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
285226947304SEvan Yan return (DDI_FAILURE);
285326947304SEvan Yan
285426947304SEvan Yan devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
285526947304SEvan Yan devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
285626947304SEvan Yan PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
285726947304SEvan Yan
285826947304SEvan Yan PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
285926947304SEvan Yan dip, devctl2);
286026947304SEvan Yan
286126947304SEvan Yan return (DDI_SUCCESS);
286226947304SEvan Yan }
286326947304SEvan Yan
286426947304SEvan Yan int
pcie_ari_is_enabled(dev_info_t * dip)286526947304SEvan Yan pcie_ari_is_enabled(dev_info_t *dip)
286626947304SEvan Yan {
286726947304SEvan Yan uint16_t devctl2;
286826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
286926947304SEvan Yan
287026947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
287126947304SEvan Yan
287226947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
287326947304SEvan Yan return (PCIE_ARI_FORW_DISABLED);
287426947304SEvan Yan
287526947304SEvan Yan devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
287626947304SEvan Yan
287726947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
287826947304SEvan Yan dip, devctl2);
287926947304SEvan Yan
288026947304SEvan Yan if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
288126947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: "
288226947304SEvan Yan "dip=%p: ARI Forwarding is enabled\n", dip);
288326947304SEvan Yan return (PCIE_ARI_FORW_ENABLED);
288426947304SEvan Yan }
288526947304SEvan Yan
288626947304SEvan Yan return (PCIE_ARI_FORW_DISABLED);
288726947304SEvan Yan }
288826947304SEvan Yan
288926947304SEvan Yan int
pcie_ari_device(dev_info_t * dip)289026947304SEvan Yan pcie_ari_device(dev_info_t *dip)
289126947304SEvan Yan {
289226947304SEvan Yan ddi_acc_handle_t handle;
289326947304SEvan Yan uint16_t cap_ptr;
289426947304SEvan Yan
289526947304SEvan Yan PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
289626947304SEvan Yan
289726947304SEvan Yan /*
289826947304SEvan Yan * XXX - This function may be called before the bus_p structure
289926947304SEvan Yan * has been populated. This code can be changed to remove
290026947304SEvan Yan * pci_config_setup()/pci_config_teardown() when the RFE
290126947304SEvan Yan * to populate the bus_p structures early in boot is putback.
290226947304SEvan Yan */
290326947304SEvan Yan
290426947304SEvan Yan /* First make sure it is a PCIe device */
290526947304SEvan Yan
290626947304SEvan Yan if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
290726947304SEvan Yan return (PCIE_NOT_ARI_DEVICE);
290826947304SEvan Yan
290926947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
291026947304SEvan Yan != DDI_SUCCESS) {
291126947304SEvan Yan pci_config_teardown(&handle);
291226947304SEvan Yan return (PCIE_NOT_ARI_DEVICE);
291326947304SEvan Yan }
291426947304SEvan Yan
291526947304SEvan Yan /* Locate the ARI Capability */
291626947304SEvan Yan
291726947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
291826947304SEvan Yan &cap_ptr)) == DDI_FAILURE) {
291926947304SEvan Yan pci_config_teardown(&handle);
292026947304SEvan Yan return (PCIE_NOT_ARI_DEVICE);
292126947304SEvan Yan }
292226947304SEvan Yan
292326947304SEvan Yan /* ARI Capability was found so it must be a ARI device */
292426947304SEvan Yan PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
292526947304SEvan Yan
292626947304SEvan Yan pci_config_teardown(&handle);
292726947304SEvan Yan return (PCIE_ARI_DEVICE);
292826947304SEvan Yan }
292926947304SEvan Yan
293026947304SEvan Yan int
pcie_ari_get_next_function(dev_info_t * dip,int * func)293126947304SEvan Yan pcie_ari_get_next_function(dev_info_t *dip, int *func)
293226947304SEvan Yan {
293326947304SEvan Yan uint32_t val;
293426947304SEvan Yan uint16_t cap_ptr, next_function;
293526947304SEvan Yan ddi_acc_handle_t handle;
293626947304SEvan Yan
293726947304SEvan Yan /*
293826947304SEvan Yan * XXX - This function may be called before the bus_p structure
293926947304SEvan Yan * has been populated. This code can be changed to remove
294026947304SEvan Yan * pci_config_setup()/pci_config_teardown() when the RFE
294126947304SEvan Yan * to populate the bus_p structures early in boot is putback.
294226947304SEvan Yan */
294326947304SEvan Yan
294426947304SEvan Yan if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
294526947304SEvan Yan return (DDI_FAILURE);
294626947304SEvan Yan
294726947304SEvan Yan if ((PCI_CAP_LOCATE(handle,
294826947304SEvan Yan PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
294926947304SEvan Yan pci_config_teardown(&handle);
295026947304SEvan Yan return (DDI_FAILURE);
295126947304SEvan Yan }
295226947304SEvan Yan
2953296f12dcSToomas Soome val = PCI_CAP_GET32(handle, 0, cap_ptr, PCIE_ARI_CAP);
295426947304SEvan Yan
295526947304SEvan Yan next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
295626947304SEvan Yan PCIE_ARI_CAP_NEXT_FUNC_MASK;
295726947304SEvan Yan
295826947304SEvan Yan pci_config_teardown(&handle);
295926947304SEvan Yan
296026947304SEvan Yan *func = next_function;
296126947304SEvan Yan
296226947304SEvan Yan return (DDI_SUCCESS);
296326947304SEvan Yan }
296426947304SEvan Yan
296526947304SEvan Yan dev_info_t *
pcie_func_to_dip(dev_info_t * dip,pcie_req_id_t function)296626947304SEvan Yan pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
296726947304SEvan Yan {
296826947304SEvan Yan pcie_req_id_t child_bdf;
296926947304SEvan Yan dev_info_t *cdip;
297026947304SEvan Yan
297126947304SEvan Yan for (cdip = ddi_get_child(dip); cdip;
297226947304SEvan Yan cdip = ddi_get_next_sibling(cdip)) {
297326947304SEvan Yan
297426947304SEvan Yan if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
297526947304SEvan Yan return (NULL);
297626947304SEvan Yan
297726947304SEvan Yan if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
297826947304SEvan Yan return (cdip);
297926947304SEvan Yan }
298026947304SEvan Yan return (NULL);
298126947304SEvan Yan }
298226947304SEvan Yan
2983d4bc0535SKrishna Elango #ifdef DEBUG
2984d4bc0535SKrishna Elango
2985d4bc0535SKrishna Elango static void
pcie_print_bus(pcie_bus_t * bus_p)2986d4bc0535SKrishna Elango pcie_print_bus(pcie_bus_t *bus_p)
2987d4bc0535SKrishna Elango {
2988d4bc0535SKrishna Elango pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
2989d4bc0535SKrishna Elango pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
2990d4bc0535SKrishna Elango
2991d4bc0535SKrishna Elango pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
2992d4bc0535SKrishna Elango pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
2993d4bc0535SKrishna Elango pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
2994d4bc0535SKrishna Elango pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
2995d4bc0535SKrishna Elango pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
2996d4bc0535SKrishna Elango pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
2997d4bc0535SKrishna Elango pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
2998d4bc0535SKrishna Elango pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
2999d4bc0535SKrishna Elango pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
3000d4bc0535SKrishna Elango pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
3001d4bc0535SKrishna Elango }
3002d4bc0535SKrishna Elango
3003d4bc0535SKrishna Elango /*
3004d4bc0535SKrishna Elango * For debugging purposes set pcie_dbg_print != 0 to see printf messages
3005d4bc0535SKrishna Elango * during interrupt.
3006d4bc0535SKrishna Elango *
3007d4bc0535SKrishna Elango * When a proper solution is in place this code will disappear.
3008d4bc0535SKrishna Elango * Potential solutions are:
3009d4bc0535SKrishna Elango * o circular buffers
3010d4bc0535SKrishna Elango * o taskq to print at lower pil
3011d4bc0535SKrishna Elango */
3012d4bc0535SKrishna Elango int pcie_dbg_print = 0;
3013d4bc0535SKrishna Elango void
pcie_dbg(char * fmt,...)3014d4bc0535SKrishna Elango pcie_dbg(char *fmt, ...)
3015d4bc0535SKrishna Elango {
3016d4bc0535SKrishna Elango va_list ap;
3017d4bc0535SKrishna Elango
3018d4bc0535SKrishna Elango if (!pcie_debug_flags) {
3019d4bc0535SKrishna Elango return;
3020d4bc0535SKrishna Elango }
3021d4bc0535SKrishna Elango va_start(ap, fmt);
3022d4bc0535SKrishna Elango if (servicing_interrupt()) {
3023d4bc0535SKrishna Elango if (pcie_dbg_print) {
3024d4bc0535SKrishna Elango prom_vprintf(fmt, ap);
3025d4bc0535SKrishna Elango }
3026d4bc0535SKrishna Elango } else {
3027d4bc0535SKrishna Elango prom_vprintf(fmt, ap);
3028d4bc0535SKrishna Elango }
3029d4bc0535SKrishna Elango va_end(ap);
3030d4bc0535SKrishna Elango }
3031d4bc0535SKrishna Elango #endif /* DEBUG */
3032d4bc0535SKrishna Elango
3033b3d69c05SRobert Mustacchi boolean_t
pcie_link_bw_supported(dev_info_t * dip)3034b3d69c05SRobert Mustacchi pcie_link_bw_supported(dev_info_t *dip)
3035b3d69c05SRobert Mustacchi {
3036b3d69c05SRobert Mustacchi uint32_t linkcap;
3037b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3038b3d69c05SRobert Mustacchi
3039b3d69c05SRobert Mustacchi if (!PCIE_IS_PCIE(bus_p)) {
3040b3d69c05SRobert Mustacchi return (B_FALSE);
3041b3d69c05SRobert Mustacchi }
3042b3d69c05SRobert Mustacchi
3043b3d69c05SRobert Mustacchi if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3044b3d69c05SRobert Mustacchi return (B_FALSE);
3045b3d69c05SRobert Mustacchi }
3046b3d69c05SRobert Mustacchi
3047b3d69c05SRobert Mustacchi linkcap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
3048b3d69c05SRobert Mustacchi return ((linkcap & PCIE_LINKCAP_LINK_BW_NOTIFY_CAP) != 0);
3049b3d69c05SRobert Mustacchi }
3050b3d69c05SRobert Mustacchi
3051b3d69c05SRobert Mustacchi int
pcie_link_bw_enable(dev_info_t * dip)3052b3d69c05SRobert Mustacchi pcie_link_bw_enable(dev_info_t *dip)
3053b3d69c05SRobert Mustacchi {
3054b3d69c05SRobert Mustacchi uint16_t linkctl;
3055b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3056b3d69c05SRobert Mustacchi
3057f7afc1fdSRobert Mustacchi if (pcie_disable_lbw != 0) {
3058f7afc1fdSRobert Mustacchi return (DDI_FAILURE);
3059f7afc1fdSRobert Mustacchi }
3060f7afc1fdSRobert Mustacchi
3061b3d69c05SRobert Mustacchi if (!pcie_link_bw_supported(dip)) {
3062b3d69c05SRobert Mustacchi return (DDI_FAILURE);
3063b3d69c05SRobert Mustacchi }
3064b3d69c05SRobert Mustacchi
3065b3d69c05SRobert Mustacchi mutex_init(&bus_p->bus_lbw_mutex, NULL, MUTEX_DRIVER, NULL);
3066b3d69c05SRobert Mustacchi cv_init(&bus_p->bus_lbw_cv, NULL, CV_DRIVER, NULL);
3067b3d69c05SRobert Mustacchi linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3068b3d69c05SRobert Mustacchi linkctl |= PCIE_LINKCTL_LINK_BW_INTR_EN;
3069b3d69c05SRobert Mustacchi linkctl |= PCIE_LINKCTL_LINK_AUTO_BW_INTR_EN;
3070b3d69c05SRobert Mustacchi PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, linkctl);
3071b3d69c05SRobert Mustacchi
3072b3d69c05SRobert Mustacchi bus_p->bus_lbw_pbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
3073b3d69c05SRobert Mustacchi bus_p->bus_lbw_cbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
3074b3d69c05SRobert Mustacchi bus_p->bus_lbw_state |= PCIE_LBW_S_ENABLED;
3075b3d69c05SRobert Mustacchi
3076b3d69c05SRobert Mustacchi return (DDI_SUCCESS);
3077b3d69c05SRobert Mustacchi }
3078b3d69c05SRobert Mustacchi
3079b3d69c05SRobert Mustacchi int
pcie_link_bw_disable(dev_info_t * dip)3080b3d69c05SRobert Mustacchi pcie_link_bw_disable(dev_info_t *dip)
3081b3d69c05SRobert Mustacchi {
3082b3d69c05SRobert Mustacchi uint16_t linkctl;
3083b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3084b3d69c05SRobert Mustacchi
3085b3d69c05SRobert Mustacchi if ((bus_p->bus_lbw_state & PCIE_LBW_S_ENABLED) == 0) {
3086b3d69c05SRobert Mustacchi return (DDI_FAILURE);
3087b3d69c05SRobert Mustacchi }
3088b3d69c05SRobert Mustacchi
3089b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_lbw_mutex);
3090b3d69c05SRobert Mustacchi while ((bus_p->bus_lbw_state &
3091b3d69c05SRobert Mustacchi (PCIE_LBW_S_DISPATCHED | PCIE_LBW_S_RUNNING)) != 0) {
3092b3d69c05SRobert Mustacchi cv_wait(&bus_p->bus_lbw_cv, &bus_p->bus_lbw_mutex);
3093b3d69c05SRobert Mustacchi }
3094b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_lbw_mutex);
3095b3d69c05SRobert Mustacchi
3096b3d69c05SRobert Mustacchi linkctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3097b3d69c05SRobert Mustacchi linkctl &= ~PCIE_LINKCTL_LINK_BW_INTR_EN;
3098b3d69c05SRobert Mustacchi linkctl &= ~PCIE_LINKCTL_LINK_AUTO_BW_INTR_EN;
3099b3d69c05SRobert Mustacchi PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, linkctl);
3100b3d69c05SRobert Mustacchi
3101b3d69c05SRobert Mustacchi bus_p->bus_lbw_state &= ~PCIE_LBW_S_ENABLED;
3102b3d69c05SRobert Mustacchi kmem_free(bus_p->bus_lbw_pbuf, MAXPATHLEN);
3103b3d69c05SRobert Mustacchi kmem_free(bus_p->bus_lbw_cbuf, MAXPATHLEN);
3104b3d69c05SRobert Mustacchi bus_p->bus_lbw_pbuf = NULL;
3105b3d69c05SRobert Mustacchi bus_p->bus_lbw_cbuf = NULL;
3106b3d69c05SRobert Mustacchi
3107b3d69c05SRobert Mustacchi mutex_destroy(&bus_p->bus_lbw_mutex);
3108b3d69c05SRobert Mustacchi cv_destroy(&bus_p->bus_lbw_cv);
3109b3d69c05SRobert Mustacchi
3110b3d69c05SRobert Mustacchi return (DDI_SUCCESS);
3111b3d69c05SRobert Mustacchi }
3112b3d69c05SRobert Mustacchi
3113b3d69c05SRobert Mustacchi void
pcie_link_bw_taskq(void * arg)3114b3d69c05SRobert Mustacchi pcie_link_bw_taskq(void *arg)
3115b3d69c05SRobert Mustacchi {
3116b3d69c05SRobert Mustacchi dev_info_t *dip = arg;
3117b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3118b3d69c05SRobert Mustacchi dev_info_t *cdip;
3119b3d69c05SRobert Mustacchi boolean_t again;
3120b3d69c05SRobert Mustacchi sysevent_t *se;
3121b3d69c05SRobert Mustacchi sysevent_value_t se_val;
3122b3d69c05SRobert Mustacchi sysevent_id_t eid;
3123b3d69c05SRobert Mustacchi sysevent_attr_list_t *ev_attr_list;
3124b3d69c05SRobert Mustacchi
3125b3d69c05SRobert Mustacchi top:
31263fe80ca4SDan Cross ndi_devi_enter(dip);
3127b3d69c05SRobert Mustacchi se = NULL;
3128b3d69c05SRobert Mustacchi ev_attr_list = NULL;
3129b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_lbw_mutex);
3130b3d69c05SRobert Mustacchi bus_p->bus_lbw_state &= ~PCIE_LBW_S_DISPATCHED;
3131b3d69c05SRobert Mustacchi bus_p->bus_lbw_state |= PCIE_LBW_S_RUNNING;
3132b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_lbw_mutex);
3133b3d69c05SRobert Mustacchi
3134b3d69c05SRobert Mustacchi /*
3135b3d69c05SRobert Mustacchi * Update our own speeds as we've likely changed something.
3136b3d69c05SRobert Mustacchi */
3137b3d69c05SRobert Mustacchi pcie_capture_speeds(dip);
3138b3d69c05SRobert Mustacchi
3139b3d69c05SRobert Mustacchi /*
3140b3d69c05SRobert Mustacchi * Walk our children. We only care about updating this on function 0
3141b3d69c05SRobert Mustacchi * because the PCIe specification requires that these all be the same
3142b3d69c05SRobert Mustacchi * otherwise.
3143b3d69c05SRobert Mustacchi */
3144b3d69c05SRobert Mustacchi for (cdip = ddi_get_child(dip); cdip != NULL;
3145b3d69c05SRobert Mustacchi cdip = ddi_get_next_sibling(cdip)) {
3146b3d69c05SRobert Mustacchi pcie_bus_t *cbus_p = PCIE_DIP2BUS(cdip);
3147b3d69c05SRobert Mustacchi
3148b3d69c05SRobert Mustacchi if (cbus_p == NULL) {
3149b3d69c05SRobert Mustacchi continue;
3150b3d69c05SRobert Mustacchi }
3151b3d69c05SRobert Mustacchi
3152b3d69c05SRobert Mustacchi if ((cbus_p->bus_bdf & PCIE_REQ_ID_FUNC_MASK) != 0) {
3153b3d69c05SRobert Mustacchi continue;
3154b3d69c05SRobert Mustacchi }
3155b3d69c05SRobert Mustacchi
3156b3d69c05SRobert Mustacchi /*
3157b3d69c05SRobert Mustacchi * It's possible that this can fire while a child is otherwise
3158b3d69c05SRobert Mustacchi * only partially constructed. Therefore, if we don't have the
3159b3d69c05SRobert Mustacchi * config handle, don't bother updating the child.
3160b3d69c05SRobert Mustacchi */
3161b3d69c05SRobert Mustacchi if (cbus_p->bus_cfg_hdl == NULL) {
3162b3d69c05SRobert Mustacchi continue;
3163b3d69c05SRobert Mustacchi }
3164b3d69c05SRobert Mustacchi
3165b3d69c05SRobert Mustacchi pcie_capture_speeds(cdip);
3166b3d69c05SRobert Mustacchi break;
3167b3d69c05SRobert Mustacchi }
3168b3d69c05SRobert Mustacchi
3169b3d69c05SRobert Mustacchi se = sysevent_alloc(EC_PCIE, ESC_PCIE_LINK_STATE,
3170b3d69c05SRobert Mustacchi ILLUMOS_KERN_PUB "pcie", SE_SLEEP);
3171b3d69c05SRobert Mustacchi
3172b3d69c05SRobert Mustacchi (void) ddi_pathname(dip, bus_p->bus_lbw_pbuf);
3173b3d69c05SRobert Mustacchi se_val.value_type = SE_DATA_TYPE_STRING;
3174b3d69c05SRobert Mustacchi se_val.value.sv_string = bus_p->bus_lbw_pbuf;
3175b3d69c05SRobert Mustacchi if (sysevent_add_attr(&ev_attr_list, PCIE_EV_DETECTOR_PATH, &se_val,
3176b3d69c05SRobert Mustacchi SE_SLEEP) != 0) {
31773fe80ca4SDan Cross ndi_devi_exit(dip);
3178b3d69c05SRobert Mustacchi goto err;
3179b3d69c05SRobert Mustacchi }
3180b3d69c05SRobert Mustacchi
3181b3d69c05SRobert Mustacchi if (cdip != NULL) {
3182b3d69c05SRobert Mustacchi (void) ddi_pathname(cdip, bus_p->bus_lbw_cbuf);
3183b3d69c05SRobert Mustacchi
3184b3d69c05SRobert Mustacchi se_val.value_type = SE_DATA_TYPE_STRING;
3185b3d69c05SRobert Mustacchi se_val.value.sv_string = bus_p->bus_lbw_cbuf;
3186b3d69c05SRobert Mustacchi
3187b3d69c05SRobert Mustacchi /*
3188b3d69c05SRobert Mustacchi * If this fails, that's OK. We'd rather get the event off and
3189b3d69c05SRobert Mustacchi * there's a chance that there may not be anything there for us.
3190b3d69c05SRobert Mustacchi */
3191b3d69c05SRobert Mustacchi (void) sysevent_add_attr(&ev_attr_list, PCIE_EV_CHILD_PATH,
3192b3d69c05SRobert Mustacchi &se_val, SE_SLEEP);
3193b3d69c05SRobert Mustacchi }
3194b3d69c05SRobert Mustacchi
31953fe80ca4SDan Cross ndi_devi_exit(dip);
3196b3d69c05SRobert Mustacchi
3197b3d69c05SRobert Mustacchi /*
3198b3d69c05SRobert Mustacchi * Before we generate and send down a sysevent, we need to tell the
3199b3d69c05SRobert Mustacchi * system that parts of the devinfo cache need to be invalidated. While
3200b3d69c05SRobert Mustacchi * the function below takes several args, it ignores them all. Because
3201b3d69c05SRobert Mustacchi * this is a global invalidation, we don't bother trying to do much more
3202b3d69c05SRobert Mustacchi * than requesting a global invalidation, lest we accidentally kick off
3203b3d69c05SRobert Mustacchi * several in a row.
3204b3d69c05SRobert Mustacchi */
3205b3d69c05SRobert Mustacchi ddi_prop_cache_invalidate(DDI_DEV_T_NONE, NULL, NULL, 0);
3206b3d69c05SRobert Mustacchi
3207b3d69c05SRobert Mustacchi if (sysevent_attach_attributes(se, ev_attr_list) != 0) {
3208b3d69c05SRobert Mustacchi goto err;
3209b3d69c05SRobert Mustacchi }
3210b3d69c05SRobert Mustacchi ev_attr_list = NULL;
3211b3d69c05SRobert Mustacchi
3212b3d69c05SRobert Mustacchi if (log_sysevent(se, SE_SLEEP, &eid) != 0) {
3213b3d69c05SRobert Mustacchi goto err;
3214b3d69c05SRobert Mustacchi }
3215b3d69c05SRobert Mustacchi
3216b3d69c05SRobert Mustacchi err:
3217b3d69c05SRobert Mustacchi sysevent_free_attr(ev_attr_list);
3218b3d69c05SRobert Mustacchi sysevent_free(se);
3219b3d69c05SRobert Mustacchi
3220b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_lbw_mutex);
3221b3d69c05SRobert Mustacchi bus_p->bus_lbw_state &= ~PCIE_LBW_S_RUNNING;
3222b3d69c05SRobert Mustacchi cv_broadcast(&bus_p->bus_lbw_cv);
3223b3d69c05SRobert Mustacchi again = (bus_p->bus_lbw_state & PCIE_LBW_S_DISPATCHED) != 0;
3224b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_lbw_mutex);
3225b3d69c05SRobert Mustacchi
3226b3d69c05SRobert Mustacchi if (again) {
3227b3d69c05SRobert Mustacchi goto top;
3228b3d69c05SRobert Mustacchi }
3229b3d69c05SRobert Mustacchi }
3230b3d69c05SRobert Mustacchi
3231b3d69c05SRobert Mustacchi int
pcie_link_bw_intr(dev_info_t * dip)3232b3d69c05SRobert Mustacchi pcie_link_bw_intr(dev_info_t *dip)
3233b3d69c05SRobert Mustacchi {
3234b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3235b3d69c05SRobert Mustacchi uint16_t linksts;
3236b3d69c05SRobert Mustacchi uint16_t flags = PCIE_LINKSTS_LINK_BW_MGMT | PCIE_LINKSTS_AUTO_BW;
3237ead3c390SKeith M Wesolowski hrtime_t now;
3238b3d69c05SRobert Mustacchi
3239b3d69c05SRobert Mustacchi if ((bus_p->bus_lbw_state & PCIE_LBW_S_ENABLED) == 0) {
3240b3d69c05SRobert Mustacchi return (DDI_INTR_UNCLAIMED);
3241b3d69c05SRobert Mustacchi }
3242b3d69c05SRobert Mustacchi
3243b3d69c05SRobert Mustacchi linksts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3244b3d69c05SRobert Mustacchi if ((linksts & flags) == 0) {
3245b3d69c05SRobert Mustacchi return (DDI_INTR_UNCLAIMED);
3246b3d69c05SRobert Mustacchi }
3247b3d69c05SRobert Mustacchi
3248ead3c390SKeith M Wesolowski now = gethrtime();
3249ead3c390SKeith M Wesolowski
3250b3d69c05SRobert Mustacchi /*
3251b3d69c05SRobert Mustacchi * Check if we've already dispatched this event. If we have already
3252b3d69c05SRobert Mustacchi * dispatched it, then there's nothing else to do, we coalesce multiple
3253b3d69c05SRobert Mustacchi * events.
3254b3d69c05SRobert Mustacchi */
3255b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_lbw_mutex);
3256b3d69c05SRobert Mustacchi bus_p->bus_lbw_nevents++;
3257ead3c390SKeith M Wesolowski bus_p->bus_lbw_last_ts = now;
3258b3d69c05SRobert Mustacchi if ((bus_p->bus_lbw_state & PCIE_LBW_S_DISPATCHED) == 0) {
3259b3d69c05SRobert Mustacchi if ((bus_p->bus_lbw_state & PCIE_LBW_S_RUNNING) == 0) {
3260b3d69c05SRobert Mustacchi taskq_dispatch_ent(pcie_link_tq, pcie_link_bw_taskq,
3261b3d69c05SRobert Mustacchi dip, 0, &bus_p->bus_lbw_ent);
3262b3d69c05SRobert Mustacchi }
3263b3d69c05SRobert Mustacchi
3264b3d69c05SRobert Mustacchi bus_p->bus_lbw_state |= PCIE_LBW_S_DISPATCHED;
3265b3d69c05SRobert Mustacchi }
3266b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_lbw_mutex);
3267b3d69c05SRobert Mustacchi
3268b3d69c05SRobert Mustacchi PCIE_CAP_PUT(16, bus_p, PCIE_LINKSTS, flags);
3269b3d69c05SRobert Mustacchi return (DDI_INTR_CLAIMED);
3270b3d69c05SRobert Mustacchi }
3271b3d69c05SRobert Mustacchi
3272b3d69c05SRobert Mustacchi int
pcie_link_set_target(dev_info_t * dip,pcie_link_speed_t speed)3273b3d69c05SRobert Mustacchi pcie_link_set_target(dev_info_t *dip, pcie_link_speed_t speed)
3274b3d69c05SRobert Mustacchi {
3275b3d69c05SRobert Mustacchi uint16_t ctl2, rval;
3276b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3277b3d69c05SRobert Mustacchi
3278b3d69c05SRobert Mustacchi if (!PCIE_IS_PCIE(bus_p)) {
3279b3d69c05SRobert Mustacchi return (ENOTSUP);
3280b3d69c05SRobert Mustacchi }
3281b3d69c05SRobert Mustacchi
3282b3d69c05SRobert Mustacchi if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3283b3d69c05SRobert Mustacchi return (ENOTSUP);
3284b3d69c05SRobert Mustacchi }
3285b3d69c05SRobert Mustacchi
328689427192SRobert Mustacchi if (bus_p->bus_pcie_vers < 2) {
328789427192SRobert Mustacchi return (ENOTSUP);
328889427192SRobert Mustacchi }
328989427192SRobert Mustacchi
3290b3d69c05SRobert Mustacchi switch (speed) {
3291b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_2_5:
3292b3d69c05SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_2_5;
3293b3d69c05SRobert Mustacchi break;
3294b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_5:
3295b3d69c05SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_5;
3296b3d69c05SRobert Mustacchi break;
3297b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_8:
3298b3d69c05SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_8;
3299b3d69c05SRobert Mustacchi break;
3300b3d69c05SRobert Mustacchi case PCIE_LINK_SPEED_16:
3301b3d69c05SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_16;
3302b3d69c05SRobert Mustacchi break;
330389427192SRobert Mustacchi case PCIE_LINK_SPEED_32:
330489427192SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_32;
330589427192SRobert Mustacchi break;
330689427192SRobert Mustacchi case PCIE_LINK_SPEED_64:
330789427192SRobert Mustacchi rval = PCIE_LINKCTL2_TARGET_SPEED_64;
330889427192SRobert Mustacchi break;
3309b3d69c05SRobert Mustacchi default:
3310b3d69c05SRobert Mustacchi return (EINVAL);
3311b3d69c05SRobert Mustacchi }
3312b3d69c05SRobert Mustacchi
3313b3d69c05SRobert Mustacchi mutex_enter(&bus_p->bus_speed_mutex);
331489427192SRobert Mustacchi if ((bus_p->bus_sup_speed & speed) == 0) {
331589427192SRobert Mustacchi mutex_exit(&bus_p->bus_speed_mutex);
331689427192SRobert Mustacchi return (ENOTSUP);
331789427192SRobert Mustacchi }
331889427192SRobert Mustacchi
3319b3d69c05SRobert Mustacchi bus_p->bus_target_speed = speed;
3320b3d69c05SRobert Mustacchi bus_p->bus_speed_flags |= PCIE_LINK_F_ADMIN_TARGET;
3321b3d69c05SRobert Mustacchi
3322b3d69c05SRobert Mustacchi ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
3323b3d69c05SRobert Mustacchi ctl2 &= ~PCIE_LINKCTL2_TARGET_SPEED_MASK;
3324b3d69c05SRobert Mustacchi ctl2 |= rval;
3325b3d69c05SRobert Mustacchi PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL2, ctl2);
3326b3d69c05SRobert Mustacchi mutex_exit(&bus_p->bus_speed_mutex);
3327b3d69c05SRobert Mustacchi
3328b3d69c05SRobert Mustacchi /*
3329b3d69c05SRobert Mustacchi * Make sure our updates have been reflected in devinfo.
3330b3d69c05SRobert Mustacchi */
3331b3d69c05SRobert Mustacchi pcie_capture_speeds(dip);
3332b3d69c05SRobert Mustacchi
3333b3d69c05SRobert Mustacchi return (0);
3334b3d69c05SRobert Mustacchi }
3335b3d69c05SRobert Mustacchi
3336b3d69c05SRobert Mustacchi int
pcie_link_retrain(dev_info_t * dip)3337b3d69c05SRobert Mustacchi pcie_link_retrain(dev_info_t *dip)
3338b3d69c05SRobert Mustacchi {
3339b3d69c05SRobert Mustacchi uint16_t ctl;
3340b3d69c05SRobert Mustacchi pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
3341b3d69c05SRobert Mustacchi
3342b3d69c05SRobert Mustacchi if (!PCIE_IS_PCIE(bus_p)) {
3343b3d69c05SRobert Mustacchi return (ENOTSUP);
3344b3d69c05SRobert Mustacchi }
3345b3d69c05SRobert Mustacchi
3346b3d69c05SRobert Mustacchi if (!PCIE_IS_RP(bus_p) && !PCIE_IS_SWD(bus_p)) {
3347b3d69c05SRobert Mustacchi return (ENOTSUP);
3348b3d69c05SRobert Mustacchi }
3349b3d69c05SRobert Mustacchi
3350b3d69c05SRobert Mustacchi /*
3351b3d69c05SRobert Mustacchi * The PCIe specification suggests that we make sure that the link isn't
3352b3d69c05SRobert Mustacchi * in training before issuing this command in case there was a state
3353b3d69c05SRobert Mustacchi * machine transition prior to when we got here. We wait and then go
3354b3d69c05SRobert Mustacchi * ahead and issue the command anyways.
3355b3d69c05SRobert Mustacchi */
3356b3d69c05SRobert Mustacchi for (uint32_t i = 0; i < pcie_link_retrain_count; i++) {
3357b3d69c05SRobert Mustacchi uint16_t sts;
3358b3d69c05SRobert Mustacchi
3359b3d69c05SRobert Mustacchi sts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3360b3d69c05SRobert Mustacchi if ((sts & PCIE_LINKSTS_LINK_TRAINING) == 0)
3361b3d69c05SRobert Mustacchi break;
3362b3d69c05SRobert Mustacchi delay(drv_usectohz(pcie_link_retrain_delay_ms * 1000));
3363b3d69c05SRobert Mustacchi }
3364b3d69c05SRobert Mustacchi
3365b3d69c05SRobert Mustacchi ctl = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL);
3366b3d69c05SRobert Mustacchi ctl |= PCIE_LINKCTL_RETRAIN_LINK;
3367b3d69c05SRobert Mustacchi PCIE_CAP_PUT(16, bus_p, PCIE_LINKCTL, ctl);
3368b3d69c05SRobert Mustacchi
3369b3d69c05SRobert Mustacchi /*
3370b3d69c05SRobert Mustacchi * Wait again to see if it clears before returning to the user.
3371b3d69c05SRobert Mustacchi */
3372b3d69c05SRobert Mustacchi for (uint32_t i = 0; i < pcie_link_retrain_count; i++) {
3373b3d69c05SRobert Mustacchi uint16_t sts;
3374b3d69c05SRobert Mustacchi
3375b3d69c05SRobert Mustacchi sts = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
3376b3d69c05SRobert Mustacchi if ((sts & PCIE_LINKSTS_LINK_TRAINING) == 0)
3377b3d69c05SRobert Mustacchi break;
3378b3d69c05SRobert Mustacchi delay(drv_usectohz(pcie_link_retrain_delay_ms * 1000));
3379b3d69c05SRobert Mustacchi }
3380b3d69c05SRobert Mustacchi
3381b3d69c05SRobert Mustacchi return (0);
3382b3d69c05SRobert Mustacchi }
33835b2c4190SRobert Mustacchi
33845b2c4190SRobert Mustacchi /*
33855b2c4190SRobert Mustacchi * Here we're going through and grabbing information about a given PCIe device.
33865b2c4190SRobert Mustacchi * Our situation is a little bit complicated at this point. This gets invoked
33875b2c4190SRobert Mustacchi * both during early initialization and during hotplug events. We cannot rely on
33885b2c4190SRobert Mustacchi * the device node having been fully set up, that is, while the pcie_bus_t
33895b2c4190SRobert Mustacchi * normally contains a ddi_acc_handle_t for configuration space, that may not be
33905b2c4190SRobert Mustacchi * valid yet as this can occur before child initialization or we may be dealing
33915b2c4190SRobert Mustacchi * with a function that will never have a handle.
33925b2c4190SRobert Mustacchi *
33935b2c4190SRobert Mustacchi * However, we should always have a fully furnished pcie_bus_t, which means that
33945b2c4190SRobert Mustacchi * we can get its bdf and use that to access the devices configuration space.
33955b2c4190SRobert Mustacchi */
33965b2c4190SRobert Mustacchi static int
pcie_fabric_feature_scan(dev_info_t * dip,void * arg)33975b2c4190SRobert Mustacchi pcie_fabric_feature_scan(dev_info_t *dip, void *arg)
33985b2c4190SRobert Mustacchi {
33995b2c4190SRobert Mustacchi pcie_bus_t *bus_p;
34005b2c4190SRobert Mustacchi uint32_t devcap;
34015b2c4190SRobert Mustacchi uint16_t mps;
34025b2c4190SRobert Mustacchi dev_info_t *rcdip;
34035b2c4190SRobert Mustacchi pcie_fabric_data_t *fab = arg;
34045b2c4190SRobert Mustacchi
34055b2c4190SRobert Mustacchi /*
34065b2c4190SRobert Mustacchi * Skip over non-PCIe devices. If we encounter something here, we don't
34075b2c4190SRobert Mustacchi * bother going through any of its children because we don't have reason
34085b2c4190SRobert Mustacchi * to believe that a PCIe device that this will impact will exist below
34095b2c4190SRobert Mustacchi * this. While it is possible that there's a PCIe fabric downstream an
34105b2c4190SRobert Mustacchi * intermediate old PCI/PCI-X bus, at that point, we'll still trigger
34115b2c4190SRobert Mustacchi * our complex fabric detection and use the minimums.
34125b2c4190SRobert Mustacchi *
34135b2c4190SRobert Mustacchi * The reason this doesn't trigger an immediate flagging as a complex
34145b2c4190SRobert Mustacchi * case like the one below is because we could be scanning a device that
34155b2c4190SRobert Mustacchi * is a nexus driver and has children already (albeit that would be
34165b2c4190SRobert Mustacchi * somewhat surprising as we don't anticipate being called at this
34175b2c4190SRobert Mustacchi * point).
34185b2c4190SRobert Mustacchi */
34195b2c4190SRobert Mustacchi if (pcie_dev(dip) != DDI_SUCCESS) {
34205b2c4190SRobert Mustacchi return (DDI_WALK_PRUNECHILD);
34215b2c4190SRobert Mustacchi }
34225b2c4190SRobert Mustacchi
34235b2c4190SRobert Mustacchi /*
34245b2c4190SRobert Mustacchi * If we fail to find a pcie_bus_t for some reason, that's somewhat
34255b2c4190SRobert Mustacchi * surprising. We log this fact and set the complex flag and indicate it
34265b2c4190SRobert Mustacchi * was because of this case. This immediately transitions us to a
34275b2c4190SRobert Mustacchi * "complex" case which means use the minimal, safe, settings.
34285b2c4190SRobert Mustacchi */
34295b2c4190SRobert Mustacchi bus_p = PCIE_DIP2BUS(dip);
34305b2c4190SRobert Mustacchi if (bus_p == NULL) {
34315b2c4190SRobert Mustacchi dev_err(dip, CE_WARN, "failed to find associated pcie_bus_t "
34325b2c4190SRobert Mustacchi "during fabric scan");
34335b2c4190SRobert Mustacchi fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
34345b2c4190SRobert Mustacchi return (DDI_WALK_TERMINATE);
34355b2c4190SRobert Mustacchi }
343689cd7a0dSRobert Mustacchi
343789cd7a0dSRobert Mustacchi /*
343889cd7a0dSRobert Mustacchi * In a similar case, there is hardware out there which is a PCIe
343989cd7a0dSRobert Mustacchi * device, but does not advertise a PCIe capability. An example of this
344089cd7a0dSRobert Mustacchi * is the IDT Tsi382A which can hide its PCIe capability. If this is
344189cd7a0dSRobert Mustacchi * the case, we immediately terminate scanning and flag this as a
344289cd7a0dSRobert Mustacchi * 'complex' case which causes us to use guaranteed safe settings.
344389cd7a0dSRobert Mustacchi */
344489cd7a0dSRobert Mustacchi if (bus_p->bus_pcie_off == 0) {
344589cd7a0dSRobert Mustacchi dev_err(dip, CE_WARN, "encountered PCIe device without PCIe "
344689cd7a0dSRobert Mustacchi "capability");
344789cd7a0dSRobert Mustacchi fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
344889cd7a0dSRobert Mustacchi return (DDI_WALK_TERMINATE);
344989cd7a0dSRobert Mustacchi }
345089cd7a0dSRobert Mustacchi
34515b2c4190SRobert Mustacchi rcdip = pcie_get_rc_dip(dip);
34525b2c4190SRobert Mustacchi
34535b2c4190SRobert Mustacchi /*
34545b2c4190SRobert Mustacchi * First, start by determining what the device's tagging and max packet
34555b2c4190SRobert Mustacchi * size is. All PCIe devices will always have the 8-bit tag information
34565b2c4190SRobert Mustacchi * as this has existed since PCIe 1.0. 10-bit tagging requires a V2
34575b2c4190SRobert Mustacchi * PCIe capability. 14-bit requires the DEV3 cap. If we are missing a
34585b2c4190SRobert Mustacchi * version or capability, then we always treat that as lacking the bits
34595b2c4190SRobert Mustacchi * in the fabric.
34605b2c4190SRobert Mustacchi */
34615b2c4190SRobert Mustacchi ASSERT3U(bus_p->bus_pcie_off, !=, 0);
34625b2c4190SRobert Mustacchi devcap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
34635b2c4190SRobert Mustacchi PCIE_DEVCAP);
34645b2c4190SRobert Mustacchi mps = devcap & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
34655b2c4190SRobert Mustacchi if (mps < fab->pfd_mps_found) {
34665b2c4190SRobert Mustacchi fab->pfd_mps_found = mps;
34675b2c4190SRobert Mustacchi }
34685b2c4190SRobert Mustacchi
34695b2c4190SRobert Mustacchi if ((devcap & PCIE_DEVCAP_EXT_TAG_8BIT) == 0) {
34705b2c4190SRobert Mustacchi fab->pfd_tag_found &= ~PCIE_TAG_8B;
34715b2c4190SRobert Mustacchi }
34725b2c4190SRobert Mustacchi
34735b2c4190SRobert Mustacchi if (bus_p->bus_pcie_vers == PCIE_PCIECAP_VER_2_0) {
34745b2c4190SRobert Mustacchi uint32_t devcap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
34755b2c4190SRobert Mustacchi bus_p->bus_pcie_off + PCIE_DEVCAP2);
34765b2c4190SRobert Mustacchi if ((devcap2 & PCIE_DEVCAP2_10B_TAG_COMP_SUP) == 0) {
34775b2c4190SRobert Mustacchi fab->pfd_tag_found &= ~PCIE_TAG_10B_COMP;
34785b2c4190SRobert Mustacchi }
34795b2c4190SRobert Mustacchi } else {
34805b2c4190SRobert Mustacchi fab->pfd_tag_found &= ~PCIE_TAG_10B_COMP;
34815b2c4190SRobert Mustacchi }
34825b2c4190SRobert Mustacchi
34835b2c4190SRobert Mustacchi if (bus_p->bus_dev3_off != 0) {
34845b2c4190SRobert Mustacchi uint32_t devcap3 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
34855b2c4190SRobert Mustacchi bus_p->bus_dev3_off + PCIE_DEVCAP3);
34865b2c4190SRobert Mustacchi if ((devcap3 & PCIE_DEVCAP3_14B_TAG_COMP_SUP) == 0) {
34875b2c4190SRobert Mustacchi fab->pfd_tag_found &= ~PCIE_TAG_14B_COMP;
34885b2c4190SRobert Mustacchi }
34895b2c4190SRobert Mustacchi } else {
34905b2c4190SRobert Mustacchi fab->pfd_tag_found &= ~PCIE_TAG_14B_COMP;
34915b2c4190SRobert Mustacchi }
34925b2c4190SRobert Mustacchi
34935b2c4190SRobert Mustacchi /*
34945b2c4190SRobert Mustacchi * Now that we have captured device information, we must go and ask
34955b2c4190SRobert Mustacchi * questions of the topology here. The big theory statement enumerates
34965b2c4190SRobert Mustacchi * several types of cases. The big question we need to answer is have we
34975b2c4190SRobert Mustacchi * encountered a hotpluggable bridge that means we need to mark this as
34985b2c4190SRobert Mustacchi * complex.
34995b2c4190SRobert Mustacchi *
35005b2c4190SRobert Mustacchi * The big theory statement notes several different kinds of hotplug
35015b2c4190SRobert Mustacchi * topologies that exist that we can theoretically support. Right now we
35025b2c4190SRobert Mustacchi * opt to keep our lives simple and focus solely on (4) and (5). These
35035b2c4190SRobert Mustacchi * can both be summarized by a single, fairly straightforward rule:
35045b2c4190SRobert Mustacchi *
35055b2c4190SRobert Mustacchi * The only allowed hotpluggable entity is a root port.
35065b2c4190SRobert Mustacchi *
35075b2c4190SRobert Mustacchi * The reason that this can work and detect cases like (6), (7), and our
35085b2c4190SRobert Mustacchi * other invalid ones is that the hotplug code will scan and find all
35095b2c4190SRobert Mustacchi * children before we are called into here.
35105b2c4190SRobert Mustacchi */
35115b2c4190SRobert Mustacchi if (bus_p->bus_hp_sup_modes != 0) {
35125b2c4190SRobert Mustacchi /*
35135b2c4190SRobert Mustacchi * We opt to terminate in this case because there's no value in
35145b2c4190SRobert Mustacchi * scanning the rest of the tree at this point.
35155b2c4190SRobert Mustacchi */
35165b2c4190SRobert Mustacchi if (!PCIE_IS_RP(bus_p)) {
35175b2c4190SRobert Mustacchi fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
35185b2c4190SRobert Mustacchi return (DDI_WALK_TERMINATE);
35195b2c4190SRobert Mustacchi }
35205b2c4190SRobert Mustacchi
35215b2c4190SRobert Mustacchi fab->pfd_flags |= PCIE_FABRIC_F_RP_HP;
35225b2c4190SRobert Mustacchi }
35235b2c4190SRobert Mustacchi
35245b2c4190SRobert Mustacchi /*
35255b2c4190SRobert Mustacchi * As our walk starts at a root port, we need to make sure that we don't
35265b2c4190SRobert Mustacchi * pick up any of its siblings and their children as those would be
35275b2c4190SRobert Mustacchi * different PCIe fabric domains for us to scan. In many hardware
35285b2c4190SRobert Mustacchi * platforms multiple root ports are all at the same level in the tree.
35295b2c4190SRobert Mustacchi */
35305b2c4190SRobert Mustacchi if (bus_p->bus_rp_dip == dip) {
35315b2c4190SRobert Mustacchi return (DDI_WALK_PRUNESIB);
35325b2c4190SRobert Mustacchi }
35335b2c4190SRobert Mustacchi
35345b2c4190SRobert Mustacchi return (DDI_WALK_CONTINUE);
35355b2c4190SRobert Mustacchi }
35365b2c4190SRobert Mustacchi
35375b2c4190SRobert Mustacchi static int
pcie_fabric_feature_set(dev_info_t * dip,void * arg)35385b2c4190SRobert Mustacchi pcie_fabric_feature_set(dev_info_t *dip, void *arg)
35395b2c4190SRobert Mustacchi {
35405b2c4190SRobert Mustacchi pcie_bus_t *bus_p;
35415b2c4190SRobert Mustacchi dev_info_t *rcdip;
35425b2c4190SRobert Mustacchi pcie_fabric_data_t *fab = arg;
35435b2c4190SRobert Mustacchi uint32_t devcap, devctl;
35445b2c4190SRobert Mustacchi
35455b2c4190SRobert Mustacchi if (pcie_dev(dip) != DDI_SUCCESS) {
35465b2c4190SRobert Mustacchi return (DDI_WALK_PRUNECHILD);
35475b2c4190SRobert Mustacchi }
35485b2c4190SRobert Mustacchi
35495b2c4190SRobert Mustacchi /*
35505b2c4190SRobert Mustacchi * The missing bus_t sent us into the complex case previously. We still
35515b2c4190SRobert Mustacchi * need to make sure all devices have values we expect here and thus
355289cd7a0dSRobert Mustacchi * don't terminate like the above. The same is true for the case where
355389cd7a0dSRobert Mustacchi * there is no PCIe capability.
35545b2c4190SRobert Mustacchi */
35555b2c4190SRobert Mustacchi bus_p = PCIE_DIP2BUS(dip);
355689cd7a0dSRobert Mustacchi if (bus_p == NULL || bus_p->bus_pcie_off == 0) {
35575b2c4190SRobert Mustacchi return (DDI_WALK_CONTINUE);
35585b2c4190SRobert Mustacchi }
35595b2c4190SRobert Mustacchi rcdip = pcie_get_rc_dip(dip);
35605b2c4190SRobert Mustacchi
35615b2c4190SRobert Mustacchi devcap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35625b2c4190SRobert Mustacchi PCIE_DEVCAP);
35635b2c4190SRobert Mustacchi devctl = pci_cfgacc_get16(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35645b2c4190SRobert Mustacchi PCIE_DEVCTL);
35655b2c4190SRobert Mustacchi
35665b2c4190SRobert Mustacchi if ((devcap & PCIE_DEVCAP_EXT_TAG_8BIT) != 0 &&
35675b2c4190SRobert Mustacchi (fab->pfd_tag_act & PCIE_TAG_8B) != 0) {
35685b2c4190SRobert Mustacchi devctl |= PCIE_DEVCTL_EXT_TAG_FIELD_EN;
35695b2c4190SRobert Mustacchi }
35705b2c4190SRobert Mustacchi
35715b2c4190SRobert Mustacchi devctl &= ~PCIE_DEVCTL_MAX_PAYLOAD_MASK;
35725b2c4190SRobert Mustacchi ASSERT0(fab->pfd_mps_act & ~PCIE_DEVCAP_MAX_PAYLOAD_MASK);
35735b2c4190SRobert Mustacchi devctl |= fab->pfd_mps_act << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT;
35745b2c4190SRobert Mustacchi
35755b2c4190SRobert Mustacchi pci_cfgacc_put16(rcdip, bus_p->bus_bdf, bus_p->bus_pcie_off +
35765b2c4190SRobert Mustacchi PCIE_DEVCTL, devctl);
35775b2c4190SRobert Mustacchi
35785b2c4190SRobert Mustacchi if (bus_p->bus_pcie_vers == PCIE_PCIECAP_VER_2_0 &&
35795b2c4190SRobert Mustacchi (fab->pfd_tag_act & PCIE_TAG_10B_COMP) != 0) {
35805b2c4190SRobert Mustacchi uint32_t devcap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
35815b2c4190SRobert Mustacchi bus_p->bus_pcie_off + PCIE_DEVCAP2);
35825b2c4190SRobert Mustacchi
35835b2c4190SRobert Mustacchi if ((devcap2 & PCIE_DEVCAP2_10B_TAG_REQ_SUP) == 0) {
35845b2c4190SRobert Mustacchi uint16_t devctl2 = pci_cfgacc_get16(rcdip,
35855b2c4190SRobert Mustacchi bus_p->bus_bdf, bus_p->bus_pcie_off + PCIE_DEVCTL2);
35865b2c4190SRobert Mustacchi devctl2 |= PCIE_DEVCTL2_10B_TAG_REQ_EN;
35875b2c4190SRobert Mustacchi pci_cfgacc_put16(rcdip, bus_p->bus_bdf,
35885b2c4190SRobert Mustacchi bus_p->bus_pcie_off + PCIE_DEVCTL2, devctl2);
35895b2c4190SRobert Mustacchi }
35905b2c4190SRobert Mustacchi }
35915b2c4190SRobert Mustacchi
35925b2c4190SRobert Mustacchi if (bus_p->bus_dev3_off != 0 &&
35935b2c4190SRobert Mustacchi (fab->pfd_tag_act & PCIE_TAG_14B_COMP) != 0) {
35945b2c4190SRobert Mustacchi uint32_t devcap3 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
35955b2c4190SRobert Mustacchi bus_p->bus_dev3_off + PCIE_DEVCAP3);
35965b2c4190SRobert Mustacchi
35975b2c4190SRobert Mustacchi if ((devcap3 & PCIE_DEVCAP3_14B_TAG_REQ_SUP) == 0) {
35985b2c4190SRobert Mustacchi uint16_t devctl3 = pci_cfgacc_get16(rcdip,
35995b2c4190SRobert Mustacchi bus_p->bus_bdf, bus_p->bus_dev3_off + PCIE_DEVCTL3);
36005b2c4190SRobert Mustacchi devctl3 |= PCIE_DEVCTL3_14B_TAG_REQ_EN;
36015b2c4190SRobert Mustacchi pci_cfgacc_put16(rcdip, bus_p->bus_bdf,
36025b2c4190SRobert Mustacchi bus_p->bus_pcie_off + PCIE_DEVCTL2, devctl3);
36035b2c4190SRobert Mustacchi }
36045b2c4190SRobert Mustacchi }
36055b2c4190SRobert Mustacchi
36065b2c4190SRobert Mustacchi /*
36075b2c4190SRobert Mustacchi * As our walk starts at a root port, we need to make sure that we don't
36085b2c4190SRobert Mustacchi * pick up any of its siblings and their children as those would be
36095b2c4190SRobert Mustacchi * different PCIe fabric domains for us to scan. In many hardware
36105b2c4190SRobert Mustacchi * platforms multiple root ports are all at the same level in the tree.
36115b2c4190SRobert Mustacchi */
36125b2c4190SRobert Mustacchi if (bus_p->bus_rp_dip == dip) {
36135b2c4190SRobert Mustacchi return (DDI_WALK_PRUNESIB);
36145b2c4190SRobert Mustacchi }
36155b2c4190SRobert Mustacchi
36165b2c4190SRobert Mustacchi return (DDI_WALK_CONTINUE);
36175b2c4190SRobert Mustacchi }
36185b2c4190SRobert Mustacchi
36195b2c4190SRobert Mustacchi /*
36205b2c4190SRobert Mustacchi * This is used to scan and determine the total set of PCIe fabric settings that
36215b2c4190SRobert Mustacchi * we should have in the system for everything downstream of this specified root
36225b2c4190SRobert Mustacchi * port. Note, it is only really safe to call this while working from the
36235b2c4190SRobert Mustacchi * perspective of a root port as we will be walking down the entire device tree.
36245b2c4190SRobert Mustacchi *
36255b2c4190SRobert Mustacchi * However, our callers, particularly hoptlug, don't have all the information
36265b2c4190SRobert Mustacchi * we'd like. In particular, we need to check that:
36275b2c4190SRobert Mustacchi *
36285b2c4190SRobert Mustacchi * o This is actually a PCIe device.
36295b2c4190SRobert Mustacchi * o That this is a root port (see the big theory statement to understand this
36305b2c4190SRobert Mustacchi * constraint).
36315b2c4190SRobert Mustacchi */
36325b2c4190SRobert Mustacchi void
pcie_fabric_setup(dev_info_t * dip)36335b2c4190SRobert Mustacchi pcie_fabric_setup(dev_info_t *dip)
36345b2c4190SRobert Mustacchi {
36355b2c4190SRobert Mustacchi pcie_bus_t *bus_p;
36365b2c4190SRobert Mustacchi pcie_fabric_data_t *fab;
36375b2c4190SRobert Mustacchi dev_info_t *pdip;
36385b2c4190SRobert Mustacchi
36395b2c4190SRobert Mustacchi bus_p = PCIE_DIP2BUS(dip);
36405b2c4190SRobert Mustacchi if (bus_p == NULL || !PCIE_IS_RP(bus_p)) {
36415b2c4190SRobert Mustacchi return;
36425b2c4190SRobert Mustacchi }
36435b2c4190SRobert Mustacchi
36445b2c4190SRobert Mustacchi VERIFY3P(bus_p->bus_fab, !=, NULL);
36455b2c4190SRobert Mustacchi fab = bus_p->bus_fab;
36465b2c4190SRobert Mustacchi
36475b2c4190SRobert Mustacchi /*
36485b2c4190SRobert Mustacchi * For us to call ddi_walk_devs(), our parent needs to be held.
36495b2c4190SRobert Mustacchi * ddi_walk_devs() will take care of grabbing our dip as part of its
36505b2c4190SRobert Mustacchi * walk before we iterate over our children.
36515b2c4190SRobert Mustacchi *
36525b2c4190SRobert Mustacchi * A reasonable question to ask here is why is it safe to ask for our
36535b2c4190SRobert Mustacchi * parent? In this case, because we have entered here through some
36545b2c4190SRobert Mustacchi * thread that's operating on us whether as part of attach or a hotplug
36555b2c4190SRobert Mustacchi * event, our dip somewhat by definition has to be valid. If we were
36565b2c4190SRobert Mustacchi * looking at our dip's children and then asking them for a parent, then
36575b2c4190SRobert Mustacchi * that would be a race condition.
36585b2c4190SRobert Mustacchi */
36595b2c4190SRobert Mustacchi pdip = ddi_get_parent(dip);
36605b2c4190SRobert Mustacchi VERIFY3P(pdip, !=, NULL);
36613fe80ca4SDan Cross ndi_devi_enter(pdip);
36625b2c4190SRobert Mustacchi fab->pfd_flags |= PCIE_FABRIC_F_SCANNING;
36635b2c4190SRobert Mustacchi
36645b2c4190SRobert Mustacchi /*
36655b2c4190SRobert Mustacchi * Reinitialize the tracking structure to basically set the maximum
36665b2c4190SRobert Mustacchi * caps. These will be chipped away during the scan.
36675b2c4190SRobert Mustacchi */
36685b2c4190SRobert Mustacchi fab->pfd_mps_found = PCIE_DEVCAP_MAX_PAYLOAD_4096;
36695b2c4190SRobert Mustacchi fab->pfd_tag_found = PCIE_TAG_ALL;
36705b2c4190SRobert Mustacchi fab->pfd_flags &= ~PCIE_FABRIC_F_COMPLEX;
36715b2c4190SRobert Mustacchi
36725b2c4190SRobert Mustacchi ddi_walk_devs(dip, pcie_fabric_feature_scan, fab);
36735b2c4190SRobert Mustacchi
36745b2c4190SRobert Mustacchi if ((fab->pfd_flags & PCIE_FABRIC_F_COMPLEX) != 0) {
36755b2c4190SRobert Mustacchi fab->pfd_tag_act = PCIE_TAG_5B;
36765b2c4190SRobert Mustacchi fab->pfd_mps_act = PCIE_DEVCAP_MAX_PAYLOAD_128;
36775b2c4190SRobert Mustacchi } else {
36785b2c4190SRobert Mustacchi fab->pfd_tag_act = fab->pfd_tag_found;
36795b2c4190SRobert Mustacchi fab->pfd_mps_act = fab->pfd_mps_found;
36805b2c4190SRobert Mustacchi }
36815b2c4190SRobert Mustacchi
36825b2c4190SRobert Mustacchi ddi_walk_devs(dip, pcie_fabric_feature_set, fab);
36835b2c4190SRobert Mustacchi
36845b2c4190SRobert Mustacchi fab->pfd_flags &= ~PCIE_FABRIC_F_SCANNING;
36853fe80ca4SDan Cross ndi_devi_exit(pdip);
36865b2c4190SRobert Mustacchi }
3687